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

Last change on this file since 362 was 304, checked in by Maciej Komosinski, 9 years ago

Improved docs

  • Property svn:eol-style set to native
File size: 14.4 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
126int internalcheck(int final);
127
128void moveNeuro(int oldpos,int newpos);
129
130void init(const Geno &srcgen);
131void init();
132
133void delMap();
134void delF0Map();
135void initMap();
136void initF0Map();
137
138public:
139/** get current model state.
140\f[(dot)
141digraph M
142 {
143 node [fontsize=12]
144 edge [fontsize=10]
145 building [label="building = can be modified"]
146 valid -> building [label="open()"]
147 building -> valid [label="close()"]
148 invalid -> building [label="open()"]
149 building -> invalid [label="close() [failed]"]
150 empty -> building [label="open()"]
151 }
152\f]
153*/
154ModelBuildStatus getStatus() const {return buildstatus;}
155int isValid() const {return buildstatus==valid;}
156int getErrorPosition(bool includingwarnings=false);
157Shape getShape() {return shape;}
158
159void updateRefno(); // set ::refno for all elements
160
161/// The bounding box size. Valid if the model is valid. Read only.
162Pt3D size;
163
164SString vis_style;
165double startenergy;
166Callback delmodel_list;
167ModelUserTags userdata;
168
169/// Create empty model with invalid empty genotype
170Model();
171
172/** Create a model based on provided genotype
173   @param buildmaps if not 0, generate mapping information for the model.
174   default is 0, because mapping uses additional time and memory.
175   @see getMap()
176 */
177Model(const Geno &src,bool buildmaps=false);
178Model(const Model &mod,bool buildmaps=false);
179/** duplicate the model.
180    the resulting object's status is 'building' (opened).
181    @see getStatus()
182 */
183void operator=(const Model &source);
184
185/** move all elements from 'source' into our model object.
186    'source' becomes empty after this operation.
187    the model will be opened if it is not already open.
188    @see addElementsFrom(const Model &source);
189 */
190void moveElementsFrom(Model &source);
191
192/** copy all elements from 'source' into our model object
193    without affecting the 'source'.
194    the model will be opened if it is not already open.
195    @see moveElementsFrom(Model &source);
196 */
197void addElementsFrom(const Model &source)
198{Model m(source); moveElementsFrom(m);}
199
200void operator+=(const Model &source)
201{addElementsFrom(source);}
202
203~Model();
204
205/** @return source genotype.
206    @warn source genotype will not automatically change
207    when the model is modified. this behaviour is inconsistent
208    with the previous release. use getF0Geno() if you need
209    the updated genotype.
210    @see getF0Geno(), setGeno()
211*/
212const Geno &getGeno() const;
213
214/// change source genotype
215void setGeno(const Geno& newgeno);
216
217/** @return f0 genotype - generated from current model state
218    don't use between open()-close()
219*/
220const Geno getF0Geno();
221
222/// make f0 genotype from current construction (low level version of getF0Geno)
223void makeGeno(Geno &,MultiMap *map=0,bool handle_defaults=true);
224
225/** @return Mapping from source genotype (0-based position in text) to model elements reference numbers.
226    Read about how mappings work: http://www.framsticks.com/files/common/GeneticMappingsInArtificialGenomes.pdf
227    The map can be empty if the mapping hasn't been requested earlier (in constructor)
228    or the converters don't support mapping.
229    If you create or modify the model using singleStepBuild() or direct manipulation
230    the map will be not changed or created automatically - it is your responsibility.
231    @see Model(const Geno &src,int buildmaps=0), singleStepBuild(), PartBase::addMapping()
232    @see clearMap()
233    @see convmap
234
235*/
236MultiMap &getMap();
237
238/** Read about how mappings work: http://www.framsticks.com/files/common/GeneticMappingsInArtificialGenomes.pdf
239    @return mapping from f0 genotype (0-based position in text) to model elements reference numbers
240 */
241const MultiMap &getF0Map();
242
243/** discard all mapping information for this model.
244    getMap().clear() also works, but it doesn't remove mappings from model elements.
245    If there are any mappings, they will be incorporated into model map during close().
246    @see close(), getMap(), PartBase::clearMapping()
247 */
248void clearMap();
249
250/** Generate mapping from the current genotype to the f0 genotype.
251    This works only if both current and f0 maps are already known.
252    Read about how mappings work: http://www.framsticks.com/files/common/GeneticMappingsInArtificialGenomes.pdf
253    @see convmap
254*/
255void getCurrentToF0Map(MultiMap& m);
256
257void setValidationLevel(int level)
258        {checklevel=level;}
259
260/// calculate location of the new part connected to the existing one
261/// using delta option
262Pt3D whereDelta(const Part& start,const Pt3D& rot, const Pt3D& delta);
263
264/// create the whole model from scratch, using current genotype
265void rebuild(bool buildmaps);
266
267/// setGeno(newgeno); rebuild();
268void rebuild(const Geno& newgeno,bool buildmaps) {setGeno(newgeno); rebuild(buildmaps);}
269
270/// reuse current model object but discard all model data
271void clear();
272
273/** Execute single line of <B>f0</B> genotype.
274    Return value is non-negative reference number of the created item,
275    or negative value. reference number can be used to access
276    the item using getPart(int), getJoint(int) and getNeuroItem(int) methods.
277    @param srcrange source genotype range which will be mapped to this element
278*/
279int singleStepBuild(const SString &singleline,const MultiRange* srcrange=0);
280
281/// separate build stages (for future use)
282void checkpoint();
283
284/// call resetDelta() on all joints
285void resetAllDelta();
286
287/// call useDelta() on all joints
288void useAllDelta(bool yesno);
289
290/// Final validity check of the model, all model data has to be available at this point.
291/// If the model was modified, the genotype will be also updated.
292/// It also calls "validate" with all side effects.
293/// @return > 0 means "valid"
294int close();
295
296/// Enable model building.
297/// You should use it if you need to create new model, modify the model after close
298/// or modify the model created from the genotype.
299/// Between open() and close() the model is not fully usable.
300void open();
301
302/// Current model written as f0 genotype while building
303/// (not cached, not validated, probably unusable and bad if used before close(). But good for debugging.)
304Geno rawGeno();
305
306/// partial validity check - you can use this call
307/// anytime between open - close.
308/// this function will check (and repair)
309/// - part-joint-neuro connections
310/// - model geometry (if "delta option" was used)
311/// - physical/biological limits
312/// @return 1 = valid
313/// @return 0 = invalid
314/// validate doesn't make the model fully usable (for simulation)
315/// you still need to use close if you have changed anything
316int validate();
317
318int getPartCount() const;
319/// you can access parts 0 .. getPartCount()-1.
320Part *getPart(int i) const;
321
322int getJointCount() const;
323/// you can access joints 0 .. getJointCount()-1.
324Joint *getJoint(int i) const;
325
326int getNeuroCount() const;
327int getConnectionCount() const;
328/// you can access neurons 0 .. getNeuroCount()-1.
329Neuro *getNeuro(int i) const;
330
331#ifdef MODEL_V1_COMPATIBLE
332/* compatibility calls for accessing old Neuro objects */
333
334/// @deprecated Neuro class will be removed soon
335/// @see compat
336int old_getNeuroCount();
337/// you can access neurons 0 .. getNeuroCount()-1.
338/// @deprecated Neuro class will be removed soon
339Neuro *old_getNeuro(int i);
340/// @see addNewNeuro, addNeuro
341/// @deprecated Neuro class will be removed soon
342Neuro *old_addNewNeuro();
343/// @return neuro index or -1 if not found
344/// @deprecated Neuro class will be removed soon
345int old_findNeuro(Neuro* n);
346#endif
347
348/** create new Part and add it to the model. @see addPart()  */
349Part *addNewPart(Part::Shape shape=Part::SHAPE_DEFAULT) {return addPart(new Part(shape));}
350/** create new Joint and add it to the model. @see addJoint() */
351Joint *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;}
352/** create new Neuro and add it to the model. @see addNeuro() */
353Neuro *addNewNeuro() {return addNeuro(new Neuro());}
354
355/** add p to the model. p->refno is adjusted. @return the Part just added (==p). */
356Part *addPart(Part *p);
357/** add j to the model. j->refno is adjusted. @return the Joint just added (==j). */
358Joint *addJoint(Joint *j);
359/** add n to the model. n->refno is adjusted. @return the Neuro just added (==n). */
360Neuro *addNeuro(Neuro *n);
361
362/** remove the part from model.
363    @param removeattachedjoints if not 0 -> remove all joints connected with this part
364    @param removeattachedneurons if not 0 -> remove neurons attached to this part */
365void removePart(int partindex,int removeattachedjoints=1,int removeattachedneurons=1);
366
367/** remove the joint from model.
368    @param removeattachedneurons if not 0 -> remove neurons attached to this joint */
369void removeJoint(int jointindex,int removeattachedneurons=1);
370
371/** remove the neuron from model.
372    @param removereferences if true -> look for references to this neuron
373    (i.e. connections from other neurons) and remove them as well */
374void removeNeuro(int neuroindex,bool removereferences=true);
375
376void removeNeuros(SList &nlist);
377
378/// @return part index or -1 if not found in the model
379int findPart(Part* p);
380/// @return joint index or -1 if not found in the model
381int findJoint(Joint* j);
382/// @return neuro index or -1 if not found in the model
383int findNeuro(Neuro* nu);
384/// @return joint index or -1 if not found in the model
385int findJoint(Part *p1, Part *p2);
386
387/** make the list of neuros satisfying given search criteria: classname,part,joint
388    @param result objects will be appended here
389    @return number of objects found  */
390int findNeuros(SList& result,const char* classname=0,const Part* part=0,const Joint* joint=0);
391
392/** search for joints connected to the part
393    @param result objects will be appended here
394    @return number of objects found  */
395int findJoints(SList& result,const Part* part=0);
396
397void disturb(double amount);
398void move(const Pt3D& shift);
399/// rotate around the origin (move-rotate-move to rotate around arbitrary point)
400void rotate(const Orient& rotation);
401/// rotate around the origin (move-rotate-move to rotate around arbitrary point)
402void rotate(const Pt3D& angles) {Orient o=Orient_1; o.rotate(angles); rotate(o);}
403
404/// build this model using new shapes, based on the provided model that uses old shapes. See also shapeconvert.cpp.
405void buildUsingNewShapes(const Model& src_old_shapes, Part::Shape default_shape = Part::SHAPE_CYLINDER, float thickness = 0.2);
406
407#ifdef EASYMAPDEBUG
408static int partToMap(int i) {return 0+i;}
409static int jointToMap(int i) {return 10+i;}
410static int neuroToMap(int i) {return 20+i;}
411static int mapToPart(int i) {return i-0;}
412static int mapToJoint(int i) {return i-10;}
413static int mapToNeuro(int i) {return i-20;}
414#else
415static int partToMap(int i) {return 0x10000000+i;}
416static int jointToMap(int i) {return 0x20000000+i;}
417static int neuroToMap(int i) {return 0x30000000+i;}
418static int mapToPart(int i) {return i-0x10000000;}
419static int mapToJoint(int i) {return i-0x20000000;}
420static int mapToNeuro(int i) {return i-0x30000000;}
421#endif
422
423static void makeGenToGenMap(MultiMap& result,const MultiMap& gen1tomodel,const MultiMap& gen2tomodel);
424
425///////////////////////////
426
427static Part& getMinPart();
428static Part& getMaxPart();
429static Part& getDefPart();
430static Joint& getMinJoint();
431static Joint& getMaxJoint();
432static Joint& getDefJoint();
433static Neuro& getMinNeuro();
434static Neuro& getMaxNeuro();
435static Neuro& getDefNeuro();
436};
437
438#endif
Note: See TracBrowser for help on using the repository browser.