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

Last change on this file since 269 was 269, checked in by Maciej Komosinski, 10 years ago
  • Model validation checks part/joint shapes for consistency (old/new)
  • Model::getShape() returns new/old style
  • Model shape conversion (old to new) and sample usage in shapeconvert.cpp
  • Property svn:eol-style set to native
File size: 13.7 KB
Line 
1// This file is a part of the Framsticks GDK.
2// Copyright (C) 1999-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
3// Refer to http://www.framsticks.com/ for further information.
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    the map can be empty if the mapping hasn't been requested earlier (in constructor)
227    or the converters don't support mapping.
228    if you create or modify the model using singleStepBuild() or direct manipulation
229    the map will be not changed or created automatically - it is your responsibility.
230    @see Model(const Geno &src,int buildmaps=0), singleStepBuild(), PartBase::addMapping()
231    @see clearMap()
232    @see convmap
233
234*/
235MultiMap &getMap();
236
237/** @return mapping from f0 genotype (0-based position in text) to model elements reference numbers
238 */
239const MultiMap &getF0Map();
240
241/** discard all mapping information for this model.
242    getMap().clear() also works, but it doesn't remove mappings from model elements.
243    If there are any mappings, they will be incorporated into model map during close().
244    @see close(), getMap(), PartBase::clearMapping()
245 */
246void clearMap();
247
248/** generate mapping from the current genotype to the f0 genotype.
249    This works only if both current and f0 maps are already known.
250    @see convmap
251*/
252void getCurrentToF0Map(MultiMap& m);
253
254void setValidationLevel(int level)
255        {checklevel=level;}
256
257/// calculate location of the new part connected to the existing one
258/// using delta option
259Pt3D whereDelta(const Part& start,const Pt3D& rot, const Pt3D& delta);
260
261/// create the whole model from scratch, using current genotype
262void rebuild(bool buildmaps);
263
264/// setGeno(newgeno); rebuild();
265void rebuild(const Geno& newgeno,bool buildmaps) {setGeno(newgeno); rebuild(buildmaps);}
266
267/// reuse current model object but discard all model data
268void clear();
269
270/** execute single line of <B>f0</B> genotype.
271    return value is non-negative reference number of the created item,
272    or negative value. reference number can be used to access
273    the item using getPart(int), getJoint(int) and getNeuroItem(int) methods.
274    @param srcrange source genotype range which will be mapped to this element
275*/
276int singleStepBuild(const SString &singleline,const MultiRange* srcrange=0);
277
278/// separate build stages (for future use)
279void checkpoint();
280
281/// call resetDelta() on all joints
282void resetAllDelta();
283
284/// call useDelta() on all joints
285void useAllDelta(bool yesno);
286
287/// final validity check of the model, all model data has to be available at this point.
288/// if the model was modified, the genotype will be also updated.
289/// it also calls "validate" with all side effects.
290/// @return > 0 means "valid"
291int close();
292
293/// enable model building.
294/// you should use it if you need to create new model, modify the model after close
295/// or modify the model created from the genotype.
296/// between open() and close() the model is not fully usable,
297void open();
298
299/// current model written as f0 genotype while building
300/// (not cached, not validated, probably unusable and bad if used before close(). but good for debugging.)
301Geno rawGeno();
302
303/// partial validity check - you can use this call
304/// anytime between open - close.
305/// this function will check (and repair)
306/// - part-joint-neuro connections
307/// - model geometry (if "delta option" was used)
308/// - physical/biological limits
309/// @return 1 = valid
310/// @return 0 = invalid
311/// validate doesn't make the model fully usable (for simulation)
312/// you still need to use close if you have changed anything
313int validate();
314
315int getPartCount() const;
316/// you can access parts 0 .. getPartCount()-1.
317Part *getPart(int i) const;
318
319int getJointCount() const;
320/// you can access joints 0 .. getJointCount()-1.
321Joint *getJoint(int i) const;
322
323int getNeuroCount() const;
324int getConnectionCount() const;
325/// you can access neurons 0 .. getNeuroCount()-1.
326Neuro *getNeuro(int i) const;
327
328#ifdef MODEL_V1_COMPATIBLE
329/* compatibility calls for accessing old Neuro objects */
330
331/// @deprecated Neuro class will be removed soon
332/// @see compat
333int old_getNeuroCount();
334/// you can access neurons 0 .. getNeuroCount()-1.
335/// @deprecated Neuro class will be removed soon
336Neuro *old_getNeuro(int i);
337/// @see addNewNeuro, addNeuro
338/// @deprecated Neuro class will be removed soon
339Neuro *old_addNewNeuro();
340/// @return neuro index or -1 if not found
341/// @deprecated Neuro class will be removed soon
342int old_findNeuro(Neuro* n);
343#endif
344
345/** create new Part and add it to the model. @see addPart()  */
346Part *addNewPart(Part::Shape shape=Part::SHAPE_DEFAULT) {return addPart(new Part(shape));}
347/** create new Joint and add it to the model. @see addJoint() */
348Joint *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;}
349/** create new Neuro and add it to the model. @see addNeuro() */
350Neuro *addNewNeuro() {return addNeuro(new Neuro());}
351
352/** add p to the model. p->refno is adjusted. @return the Part just added (==p). */
353Part *addPart(Part *p);
354/** add j to the model. j->refno is adjusted. @return the Joint just added (==j). */
355Joint *addJoint(Joint *j);
356/** add n to the model. n->refno is adjusted. @return the Neuro just added (==n). */
357Neuro *addNeuro(Neuro *n);
358
359/** remove the part from model.
360    @param removeattachedjoints if not 0 -> remove all joints connected with this part
361    @param removeattachedneurons if not 0 -> remove neurons attached to this part */
362void removePart(int partindex,int removeattachedjoints=1,int removeattachedneurons=1);
363
364/** remove the joint from model.
365    @param removeattachedneurons if not 0 -> remove neurons attached to this joint */
366void removeJoint(int jointindex,int removeattachedneurons=1);
367
368/** remove the neuron from model.
369    @param removereferences if true -> look for references to this neuron
370    (i.e. connections from other neurons) and remove them as well */
371void removeNeuro(int neuroindex,bool removereferences=true);
372
373void removeNeuros(SList &nlist);
374
375/// @return part index or -1 if not found in the model
376int findPart(Part* p);
377/// @return joint index or -1 if not found in the model
378int findJoint(Joint* j);
379/// @return neuro index or -1 if not found in the model
380int findNeuro(Neuro* nu);
381/// @return joint index or -1 if not found in the model
382int findJoint(Part *p1, Part *p2);
383
384/** make the list of neuros satisfying given search criteria: classname,part,joint
385    @param result objects will be appended here
386    @return number of objects found  */
387int findNeuros(SList& result,const char* classname=0,const Part* part=0,const Joint* joint=0);
388
389/** search for joints connected to the part
390    @param result objects will be appended here
391    @return number of objects found  */
392int findJoints(SList& result,const Part* part=0);
393
394void disturb(double amount);
395
396void buildUsingNewShapes(const Model& src_old_shapes, Part::Shape default_shape = Part::SHAPE_CYLINDER, float thickness = 0.2);
397
398#ifdef EASYMAPDEBUG
399static int partToMap(int i) {return 0+i;}
400static int jointToMap(int i) {return 10+i;}
401static int neuroToMap(int i) {return 20+i;}
402static int mapToPart(int i) {return i-0;}
403static int mapToJoint(int i) {return i-10;}
404static int mapToNeuro(int i) {return i-20;}
405#else
406static int partToMap(int i) {return 0x10000000+i;}
407static int jointToMap(int i) {return 0x20000000+i;}
408static int neuroToMap(int i) {return 0x30000000+i;}
409static int mapToPart(int i) {return i-0x10000000;}
410static int mapToJoint(int i) {return i-0x20000000;}
411static int mapToNeuro(int i) {return i-0x30000000;}
412#endif
413
414static void makeGenToGenMap(MultiMap& result,const MultiMap& gen1tomodel,const MultiMap& gen2tomodel);
415
416///////////////////////////
417
418static Part& getMinPart();
419static Part& getMaxPart();
420static Part& getDefPart();
421static Joint& getMinJoint();
422static Joint& getMaxJoint();
423static Joint& getDefJoint();
424static Neuro& getMinNeuro();
425static Neuro& getMaxNeuro();
426static Neuro& getDefNeuro();
427};
428
429#endif
Note: See TracBrowser for help on using the repository browser.