source: cpp/frams/model/model.h @ 495

Last change on this file since 495 was 495, checked in by Maciej Komosinski, 8 years ago

Unified and better formatted error and warning messages

  • Property svn:eol-style set to native
File size: 14.9 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#ifndef _MODEL_H_
6#define _MODEL_H_
7
8#include <common/nonstd_math.h>
9#include <stdlib.h>
10#include <stdio.h>
11
12#include "modelparts.h"
13#include <frams/util/advlist.h>
14#include <frams/util/usertags.h>
15
16extern ParamEntry f0_model_paramtab[];
17
18//#define EASYMAPDEBUG
19
20enum ModelBuildStatus {empty,building,invalid,valid};
21
22class MultiMap;
23
24class VisualModel;
25
26/**
27    "Model" is the skeleton of the Framsticks creature.
28    This object can be used for 2 purposes:
29     - you can build a creature from any supported Framsticks genotype
30    format
31     - or generate low level f0 genotype from existing construct.
32
33    In both cases you have access to geometry and neuron net data.
34    Using this standard class assures compatibility and good
35    integration with core Framsticks engine.
36
37    Model contains 3 kinds of objects:
38    - Parts (class Part).
39    - Joints (class Joint). Each Joint is connected with 2 Parts. (@see Joint::attachToParts()).
40    - Neurons (class Neuro). Neuron can have 0 or more inputs - other neurons. (@see Neuro::addInput()).
41      Each Neuron can be located on the physical structure, i.e. it can ba attached to Part or Joint
42      (@see Neuro::attachToPart(), Neuro::attachToJoint()).
43
44\f[(dot)
45digraph Model
46 {
47  Joint1; Joint2;
48  node [ shape=box ]
49  Part1; Part2; Part3;
50  Joint1 -> Part1; Joint1 -> Part2; Joint2 -> Part2; Joint2 -> Part3
51  node [ shape=diamond ]
52  Neuro1 -> Neuro2; Neuro1 -> Neuro3; Neuro2 -> Neuro2; Neuro3 -> Neuro2;
53  Neuro1 -> Part1; Neuro2 -> Joint2;
54 }
55\f]
56*/
57
58class Model: public DestrBase
59{
60  protected:
61Geno geno,f0geno;
62char modelfromgenotype;
63char f0genoknown;
64/// make model map in build()
65bool autobuildmaps;
66/// valid if build from f0 genotype
67int f0errorposition;
68/// valid if build from f0 genotype
69int f0warnposition;
70
71ModelBuildStatus buildstatus;
72/// NULL if the map is not (yet) created
73MultiMap *map,*f0map;
74
75SList parts,joints,neurons;
76char partmappingchanged;
77
78#ifdef MODEL_V1_COMPATIBLE
79/** NeuroCount value.
80    compatibility_neurocount = -1 if its value is unknown and the layout is not compatible
81    @see reorderToOldLayout()
82*/
83int oldneurocount;
84char oldconnections;
85
86/** calculate oldNeuroCount */
87void calcOldNeuroCount();
88/** some new calls can invalidate old compatibility data */
89void invalidateOldNeuroCount() {oldneurocount=-1;}
90/**
91   for compatibility with old NeuroClass the layout of Neurons
92   is changed when old 'Neuro' accessing methods are in use.
93   Neurons:
94   0 .. compatibility_neurocount-1                : old Neurons (class "N")
95   compatibility_neurocount .. neurons.size()-1   : other units
96*/
97int reorderToOldLayout();
98
99/** check if compatibility should be preserved */
100int hasOldNeuroLayout() {return oldneurocount>=0;}
101
102/** add inputs to the old "-" units.
103    @return 1=ok, 0=invalid input detected  */
104int addOldConnectionsInputs();
105#endif
106
107void internalCopy(const Model &mod);
108
109/// make the model from current genotype
110void build();
111
112friend class NeuroNetFactory;
113friend class VisualModel;
114friend class GLVisualModel;
115friend class Creature;
116friend class PartBase;
117
118int checklevel;
119
120  public:
121enum Shape {SHAPE_UNKNOWN,SHAPE_ILLEGAL,SHAPE_OLD,SHAPE_NEW};
122  protected:
123Shape shape;
124
125void updateNeuroRefno(); // set Neuro::refno for all neurons
126SString nameForErrors() const;
127int internalcheck(int final);
128
129void moveNeuro(int oldpos,int newpos);
130
131void init(const Geno &srcgen);
132void init();
133
134void delMap();
135void delF0Map();
136void initMap();
137void initF0Map();
138
139public:
140/** get current model state.
141\f[(dot)
142digraph M
143 {
144 node [fontsize=12]
145 edge [fontsize=10]
146 building [label="building = can be modified"]
147 valid -> building [label="open()"]
148 building -> valid [label="close()"]
149 invalid -> building [label="open()"]
150 building -> invalid [label="close() [failed]"]
151 empty -> building [label="open()"]
152 }
153\f]
154*/
155ModelBuildStatus getStatus() const {return buildstatus;}
156int isValid() const {return buildstatus==valid;}
157int getErrorPosition(bool includingwarnings=false);
158Shape getShape() {return shape;}
159
160void updateRefno(); // set ::refno for all elements
161
162/// The bounding box size. Valid if the model is valid. Read only.
163Pt3D size;
164
165SString vis_style;
166double startenergy;
167Callback delmodel_list;
168ModelUserTags userdata;
169
170/// Create empty model with invalid empty genotype
171Model();
172
173/** Create a model based on provided genotype
174   @param buildmaps if not 0, generate mapping information for the model.
175   default is 0, because mapping uses additional time and memory.
176   @see getMap()
177 */
178Model(const Geno &src,bool buildmaps=false);
179Model(const Model &mod,bool buildmaps=false);
180/** duplicate the model.
181    the resulting object's status is 'building' (opened).
182    @see getStatus()
183 */
184void operator=(const Model &source);
185
186/** move all elements from 'source' into our model object.
187    'source' becomes empty after this operation.
188    the model will be opened if it is not already open.
189    @see addElementsFrom(const Model &source);
190 */
191void moveElementsFrom(Model &source);
192
193/** copy all elements from 'source' into our model object
194    without affecting the 'source'.
195    the model will be opened if it is not already open.
196    @see moveElementsFrom(Model &source);
197 */
198void addElementsFrom(const Model &source)
199{Model m(source); moveElementsFrom(m);}
200
201void operator+=(const Model &source)
202{addElementsFrom(source);}
203
204~Model();
205
206/** @return source genotype.
207    @warn source genotype will not automatically change
208    when the model is modified. this behaviour is inconsistent
209    with the previous release. use getF0Geno() if you need
210    the updated genotype.
211    @see getF0Geno(), setGeno()
212*/
213const Geno &getGeno() const;
214
215/// change source genotype
216void setGeno(const Geno& newgeno);
217
218/** @return f0 genotype - generated from current model state
219    don't use between open()-close()
220*/
221const Geno getF0Geno();
222
223/// make f0 genotype from current construction (low level version of getF0Geno)
224void makeGeno(Geno &,MultiMap *map=0,bool handle_defaults=true);
225
226/** @return Mapping from source genotype (0-based position in text) to model elements reference numbers.
227    Read about how mappings work: http://www.framsticks.com/files/common/GeneticMappingsInArtificialGenomes.pdf
228    The map can be empty if the mapping hasn't been requested earlier (in constructor)
229    or the converters don't support mapping.
230    If you create or modify the model using singleStepBuild() or direct manipulation
231    the map will be not changed or created automatically - it is your responsibility.
232    @see Model(const Geno &src,int buildmaps=0), singleStepBuild(), PartBase::addMapping()
233    @see clearMap()
234    @see convmap
235
236*/
237MultiMap &getMap();
238
239/** Read about how mappings work: http://www.framsticks.com/files/common/GeneticMappingsInArtificialGenomes.pdf
240    @return mapping from f0 genotype (0-based position in text) to model elements reference numbers
241 */
242const MultiMap &getF0Map();
243
244/** discard all mapping information for this model.
245    getMap().clear() also works, but it doesn't remove mappings from model elements.
246    If there are any mappings, they will be incorporated into model map during close().
247    @see close(), getMap(), PartBase::clearMapping()
248 */
249void clearMap();
250
251/** Generate mapping from the current genotype to the f0 genotype.
252    This works only if both current and f0 maps are already known.
253    Read about how mappings work: http://www.framsticks.com/files/common/GeneticMappingsInArtificialGenomes.pdf
254    @see convmap
255*/
256void getCurrentToF0Map(MultiMap& m);
257
258void setValidationLevel(int level)
259        {checklevel=level;}
260
261/// calculate location of the new part connected to the existing one
262/// using delta option
263Pt3D whereDelta(const Part& start,const Pt3D& rot, const Pt3D& delta);
264
265/// create the whole model from scratch, using current genotype
266void rebuild(bool buildmaps);
267
268/// setGeno(newgeno); rebuild();
269void rebuild(const Geno& newgeno,bool buildmaps) {setGeno(newgeno); rebuild(buildmaps);}
270
271/// reuse current model object but discard all model data
272void clear();
273
274/** Execute single line of <B>f0</B> genotype.
275    Return value is non-negative reference number of the created item,
276    or negative value. reference number can be used to access
277    the item using getPart(int), getJoint(int) and getNeuroItem(int) methods.
278    @param line_num optional line number used in error messages
279    @param srcrange source genotype range which will be mapped to this element
280*/
281int singleStepBuild(const SString &singleline,int line_num,const MultiRange* srcrange=NULL);
282/** Execute single line of <B>f0</B> genotype - compatiblity variant */
283int singleStepBuild(const SString &singleline,const MultiRange* srcrange=NULL);
284/** Execute single line of <B>f0</B> genotype - low level variant, used by Model::build(), error messages returned as string instead of calling logger */
285int singleStepBuildNoLog(const SString &singleline,SString& error_message,const MultiRange* srcrange=0);
286
287/// separate build stages (for future use)
288void checkpoint();
289
290/// call resetDelta() on all joints
291void resetAllDelta();
292
293/// call useDelta() on all joints
294void useAllDelta(bool yesno);
295
296/// Final validity check of the model, all model data has to be available at this point.
297/// If the model was modified, the genotype will be also updated.
298/// It also calls "validate" with all side effects.
299/// @return > 0 means "valid"
300int close();
301
302/// Enable model building.
303/// You should use it if you need to create new model, modify the model after close
304/// or modify the model created from the genotype.
305/// Between open() and close() the model is not fully usable.
306void open();
307
308/// Current model written as f0 genotype while building
309/// (not cached, not validated, probably unusable and bad if used before close(). But good for debugging.)
310Geno rawGeno();
311
312/// partial validity check - you can use this call
313/// anytime between open - close.
314/// this function will check (and repair)
315/// - part-joint-neuro connections
316/// - model geometry (if "delta option" was used)
317/// - physical/biological limits
318/// @return 1 = valid
319/// @return 0 = invalid
320/// validate doesn't make the model fully usable (for simulation)
321/// you still need to use close if you have changed anything
322int validate();
323
324int getPartCount() const;
325/// you can access parts 0 .. getPartCount()-1.
326Part *getPart(int i) const;
327
328int getJointCount() const;
329/// you can access joints 0 .. getJointCount()-1.
330Joint *getJoint(int i) const;
331
332int getNeuroCount() const;
333int getConnectionCount() const;
334/// you can access neurons 0 .. getNeuroCount()-1.
335Neuro *getNeuro(int i) const;
336
337#ifdef MODEL_V1_COMPATIBLE
338/* compatibility calls for accessing old Neuro objects */
339
340/// @deprecated Neuro class will be removed soon
341/// @see compat
342int old_getNeuroCount();
343/// you can access neurons 0 .. getNeuroCount()-1.
344/// @deprecated Neuro class will be removed soon
345Neuro *old_getNeuro(int i);
346/// @see addNewNeuro, addNeuro
347/// @deprecated Neuro class will be removed soon
348Neuro *old_addNewNeuro();
349/// @return neuro index or -1 if not found
350/// @deprecated Neuro class will be removed soon
351int old_findNeuro(Neuro* n);
352#endif
353
354/** create new Part and add it to the model. @see addPart()  */
355Part *addNewPart(Part::Shape shape=Part::SHAPE_DEFAULT) {return addPart(new Part(shape));}
356/** create new Joint and add it to the model. @see addJoint() */
357Joint *addNewJoint(Part *p1=NULL,Part *p2=NULL,Joint::Shape shape=Joint::SHAPE_DEFAULT) { Joint *j=addJoint(new Joint()); j->shape=shape; if ((p1!=NULL)&&(p2!=NULL)) j->attachToParts(p1,p2); return j;}
358/** create new Neuro and add it to the model. @see addNeuro() */
359Neuro *addNewNeuro() {return addNeuro(new Neuro());}
360
361/** add p to the model. p->refno is adjusted. @return the Part just added (==p). */
362Part *addPart(Part *p);
363/** add j to the model. j->refno is adjusted. @return the Joint just added (==j). */
364Joint *addJoint(Joint *j);
365/** add n to the model. n->refno is adjusted. @return the Neuro just added (==n). */
366Neuro *addNeuro(Neuro *n);
367
368/** remove the part from model.
369    @param removeattachedjoints if not 0 -> remove all joints connected with this part
370    @param removeattachedneurons if not 0 -> remove neurons attached to this part */
371void removePart(int partindex,int removeattachedjoints=1,int removeattachedneurons=1);
372
373/** remove the joint from model.
374    @param removeattachedneurons if not 0 -> remove neurons attached to this joint */
375void removeJoint(int jointindex,int removeattachedneurons=1);
376
377/** remove the neuron from model.
378    @param removereferences if true -> look for references to this neuron
379    (i.e. connections from other neurons) and remove them as well */
380void removeNeuro(int neuroindex,bool removereferences=true);
381
382void removeNeuros(SList &nlist);
383
384/// @return part index or -1 if not found in the model
385int findPart(Part* p);
386/// @return joint index or -1 if not found in the model
387int findJoint(Joint* j);
388/// @return neuro index or -1 if not found in the model
389int findNeuro(Neuro* nu);
390/// @return joint index or -1 if not found in the model
391int findJoint(Part *p1, Part *p2);
392
393/** make the list of neuros satisfying given search criteria: classname,part,joint
394    @param result objects will be appended here
395    @return number of objects found  */
396int findNeuros(SList& result,const char* classname=0,const Part* part=0,const Joint* joint=0);
397
398/** search for joints connected to the part
399    @param result objects will be appended here
400    @return number of objects found  */
401int findJoints(SList& result,const Part* part=0);
402
403void disturb(double amount);
404void move(const Pt3D& shift);
405/// rotate around the origin (move-rotate-move to rotate around arbitrary point)
406void rotate(const Orient& rotation);
407/// rotate around the origin (move-rotate-move to rotate around arbitrary point)
408void rotate(const Pt3D& angles) {Orient o=Orient_1; o.rotate(angles); rotate(o);}
409
410/// build this model using new shapes, based on the provided model that uses old shapes. See also shapeconvert.cpp.
411void buildUsingNewShapes(const Model& src_old_shapes, Part::Shape default_shape = Part::SHAPE_CYLINDER, float thickness = 0.2);
412
413#ifdef EASYMAPDEBUG
414static int partToMap(int i) {return 0+i;}
415static int jointToMap(int i) {return 10+i;}
416static int neuroToMap(int i) {return 20+i;}
417static int mapToPart(int i) {return i-0;}
418static int mapToJoint(int i) {return i-10;}
419static int mapToNeuro(int i) {return i-20;}
420#else
421static int partToMap(int i) {return 0x10000000+i;}
422static int jointToMap(int i) {return 0x20000000+i;}
423static int neuroToMap(int i) {return 0x30000000+i;}
424static int mapToPart(int i) {return i-0x10000000;}
425static int mapToJoint(int i) {return i-0x20000000;}
426static int mapToNeuro(int i) {return i-0x30000000;}
427#endif
428
429static void makeGenToGenMap(MultiMap& result,const MultiMap& gen1tomodel,const MultiMap& gen2tomodel);
430
431///////////////////////////
432
433static Part& getMinPart();
434static Part& getMaxPart();
435static Part& getDefPart();
436static Joint& getMinJoint();
437static Joint& getMaxJoint();
438static Joint& getDefJoint();
439static Neuro& getMinNeuro();
440static Neuro& getMaxNeuro();
441static Neuro& getDefNeuro();
442};
443
444#endif
Note: See TracBrowser for help on using the repository browser.