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

Last change on this file since 546 was 546, checked in by Maciej Komosinski, 4 years ago

Renamed: Model::buildUsingNewShapes -> Model::buildUsingSolidShapeTypes()
Added class SolidsShapeTypeModel? (for making ball-and-stick Models look like solids-type Models)
ModelGeometryInfo? functions: findSizesAndAxesOfModel(), volume() and area() now accept ball-and-stick Models (using SolidsShapeTypeModel? class)
[refs #46] and possibly closes this issue (needs verification)

  • Property svn:eol-style set to native
File size: 16.5 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)
45        digraph 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{
60protected:
61        Geno geno, f0geno;
62        char modelfromgenotype;
63        char f0genoknown;
64        /// make model map in build()
65        bool autobuildmaps;
66        /// valid if build from f0 genotype
67        int f0errorposition;
68        /// valid if build from f0 genotype
69        int f0warnposition;
70
71        ModelBuildStatus buildstatus;
72        /// NULL if the map is not (yet) created
73        MultiMap *map, *f0map;
74
75        SList parts, joints, neurons;
76        char 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                */
83        int oldneurocount;
84        char oldconnections;
85
86        /** calculate oldNeuroCount */
87        void calcOldNeuroCount();
88        /** some new calls can invalidate old compatibility data */
89        void 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           */
97        int reorderToOldLayout();
98
99        /** check if compatibility should be preserved */
100        int hasOldNeuroLayout() {return oldneurocount>=0;}
101
102        /** add inputs to the old "-" units.
103                @return 1=ok, 0=invalid input detected  */
104        int addOldConnectionsInputs();
105#endif
106
107        void internalCopy(const Model &mod);
108
109        /// make the model from current genotype
110        void build();
111
112        friend class NeuroNetFactory;
113        friend class VisualModel;
114        friend class GLVisualModel;
115        friend class Creature;
116        friend class PartBase;
117
118        int checklevel;
119
120public:
121        enum ShapeType { SHAPE_UNKNOWN, SHAPE_ILLEGAL, SHAPE_BALL_AND_STICK, SHAPE_SOLIDS };
122protected:
123        ShapeType shape;
124
125        void updateNeuroRefno(); // set Neuro::refno for all neurons
126        SString nameForErrors() const;
127        int internalcheck(int final);
128
129        void moveNeuro(int oldpos, int newpos);
130
131        void init(const Geno &srcgen);
132        void init();
133
134        void delMap();
135        void delF0Map();
136        void initMap();
137        void initF0Map();
138
139public:
140        /** get current model state.
141        \f[(dot)
142        digraph 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        */
155        ModelBuildStatus getStatus() const { return buildstatus; }
156        int isValid() const { return buildstatus == valid; }
157        int getErrorPosition(bool includingwarnings = false);
158        ShapeType getShapeType() const { return shape; }
159
160        void updateRefno(); // set ::refno for all elements
161
162        /// The bounding box size. Valid if the model is valid. Read only.
163        Pt3D size;
164
165        SString vis_style;
166        double startenergy;
167        Callback delmodel_list;
168        ModelUserTags userdata;
169
170        /// Create empty model with invalid empty genotype
171        Model();
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           */
178        Model(const Geno &src, bool buildmaps = false);
179        Model(const Model &mod, bool buildmaps = false);
180        /** duplicate the model.
181                the resulting object's status is 'building' (opened).
182                @see getStatus()
183                */
184        void 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                */
191        void 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                */
198        void addElementsFrom(const Model &source)
199        {
200                Model m(source); moveElementsFrom(m);
201        }
202
203        void operator+=(const Model &source)
204        {
205                addElementsFrom(source);
206        }
207
208        ~Model();
209
210        /** @return source genotype.
211                @warn source genotype will not automatically change
212                when the model is modified. this behaviour is inconsistent
213                with the previous release. use getF0Geno() if you need
214                the updated genotype.
215                @see getF0Geno(), setGeno()
216                */
217        const Geno &getGeno() const;
218
219        /// change source genotype
220        void setGeno(const Geno& newgeno);
221
222        /** @return f0 genotype - generated from current model state
223                don't use between open()-close()
224                */
225        const Geno getF0Geno();
226
227        /// make f0 genotype from current construction (low level version of getF0Geno)
228        void makeGeno(Geno &, MultiMap *map = 0, bool handle_defaults = true);
229
230        /** @return Mapping from source genotype (0-based position in text) to model elements reference numbers.
231                Read about how mappings work: http://www.framsticks.com/files/common/GeneticMappingsInArtificialGenomes.pdf
232                The map can be empty if the mapping hasn't been requested earlier (in constructor)
233                or the converters don't support mapping.
234                If you create or modify the model using singleStepBuild() or direct manipulation
235                the map will be not changed or created automatically - it is your responsibility.
236                @see Model(const Geno &src,int buildmaps=0), singleStepBuild(), PartBase::addMapping()
237                @see clearMap()
238                @see convmap
239
240                */
241        MultiMap &getMap();
242
243        /** Read about how mappings work: http://www.framsticks.com/files/common/GeneticMappingsInArtificialGenomes.pdf
244                @return mapping from f0 genotype (0-based position in text) to model elements reference numbers
245                */
246        const MultiMap &getF0Map();
247
248        /** discard all mapping information for this model.
249                getMap().clear() also works, but it doesn't remove mappings from model elements.
250                If there are any mappings, they will be incorporated into model map during close().
251                @see close(), getMap(), PartBase::clearMapping()
252                */
253        void clearMap();
254
255        /** Generate mapping from the current genotype to the f0 genotype.
256                This works only if both current and f0 maps are already known.
257                Read about how mappings work: http://www.framsticks.com/files/common/GeneticMappingsInArtificialGenomes.pdf
258                @see convmap
259                */
260        void getCurrentToF0Map(MultiMap& m);
261
262        void setValidationLevel(int level)
263        {
264                checklevel = level;
265        }
266
267        /// calculate location of the new part connected to the existing one
268        /// using delta option
269        Pt3D whereDelta(const Part& start, const Pt3D& rot, const Pt3D& delta);
270
271        /// create the whole model from scratch, using current genotype
272        void rebuild(bool buildmaps);
273
274        /// setGeno(newgeno); rebuild();
275        void rebuild(const Geno& newgeno, bool buildmaps) { setGeno(newgeno); rebuild(buildmaps); }
276
277        /// reuse current model object but discard all model data
278        void clear();
279
280        /** Execute single line of <B>f0</B> genotype.
281                Return value is non-negative reference number of the created item,
282                or negative value. reference number can be used to access
283                the item using getPart(int), getJoint(int) and getNeuroItem(int) methods.
284                @param line_num optional line number used in error messages
285                @param srcrange source genotype range which will be mapped to this element
286                */
287        int singleStepBuild(const SString &singleline, int line_num, const MultiRange* srcrange = NULL);
288        /** Execute single line of <B>f0</B> genotype - compatiblity variant */
289        int singleStepBuild(const SString &singleline, const MultiRange* srcrange = NULL);
290        /** Execute single line of <B>f0</B> genotype - low level variant, used by Model::build(), error messages returned as string instead of calling logger */
291        int singleStepBuildNoLog(const SString &singleline, SString& error_message, const MultiRange* srcrange = 0);
292
293        /// separate build stages (for future use)
294        void checkpoint();
295
296        /// call resetDelta() on all joints
297        void resetAllDelta();
298
299        /// call useDelta() on all joints
300        void useAllDelta(bool yesno);
301
302        /// Final validity check of the model, all model data has to be available at this point.
303        /// If the model was modified, the genotype will be also updated.
304        /// It also calls "validate" with all side effects.
305        /// @return > 0 means "valid"
306        int close();
307
308        /// Enable model building.
309        /// You should use it if you need to create new model, modify the model after close
310        /// or modify the model created from the genotype.
311        /// Between open() and close() the model is not fully usable.
312        void open();
313
314        /// Current model written as f0 genotype while building
315        /// (not cached, not validated, probably unusable and bad if used before close(). But good for debugging.)
316        Geno rawGeno();
317
318        /// partial validity check - you can use this call
319        /// anytime between open - close.
320        /// this function will check (and repair)
321        /// - part-joint-neuro connections
322        /// - model geometry (if "delta option" was used)
323        /// - physical/biological limits
324        /// @return 1 = valid
325        /// @return 0 = invalid
326        /// validate doesn't make the model fully usable (for simulation)
327        /// you still need to use close if you have changed anything
328        int validate();
329
330        int getPartCount() const;
331        /// you can access parts 0 .. getPartCount()-1.
332        Part *getPart(int i) const;
333
334        int getJointCount() const;
335        /// you can access joints 0 .. getJointCount()-1.
336        Joint *getJoint(int i) const;
337
338        int getNeuroCount() const;
339        int getConnectionCount() const;
340        /// you can access neurons 0 .. getNeuroCount()-1.
341        Neuro *getNeuro(int i) const;
342
343#ifdef MODEL_V1_COMPATIBLE
344        /* compatibility calls for accessing old Neuro objects */
345
346        /// @deprecated Neuro class will be removed soon
347        /// @see compat
348        int old_getNeuroCount();
349        /// you can access neurons 0 .. getNeuroCount()-1.
350        /// @deprecated Neuro class will be removed soon
351        Neuro *old_getNeuro(int i);
352        /// @see addNewNeuro, addNeuro
353        /// @deprecated Neuro class will be removed soon
354        Neuro *old_addNewNeuro();
355        /// @return neuro index or -1 if not found
356        /// @deprecated Neuro class will be removed soon
357        int old_findNeuro(Neuro* n);
358#endif
359
360        /** create new Part and add it to the model. @see addPart()  */
361        Part *addNewPart(Part::Shape shape = Part::SHAPE_BALL_AND_STICK) { return addPart(new Part(shape)); }
362        /** create new Joint and add it to the model. @see addJoint() */
363        Joint *addNewJoint(Part *p1 = NULL, Part *p2 = NULL, Joint::Shape shape = Joint::SHAPE_BALL_AND_STICK) { Joint *j = addJoint(new Joint()); j->shape = shape; if ((p1 != NULL) && (p2 != NULL)) j->attachToParts(p1, p2); return j; }
364        /** create new Neuro and add it to the model. @see addNeuro() */
365        Neuro *addNewNeuro() { return addNeuro(new Neuro()); }
366
367        /** add p to the model. p->refno is adjusted. @return the Part just added (==p). */
368        Part *addPart(Part *p);
369        /** add j to the model. j->refno is adjusted. @return the Joint just added (==j). */
370        Joint *addJoint(Joint *j);
371        /** add n to the model. n->refno is adjusted. @return the Neuro just added (==n). */
372        Neuro *addNeuro(Neuro *n);
373
374        /** remove the part from model.
375                @param removeattachedjoints if not 0 -> remove all joints connected with this part
376                @param removeattachedneurons if not 0 -> remove neurons attached to this part */
377        void removePart(int partindex, int removeattachedjoints = 1, int removeattachedneurons = 1);
378
379        /** remove the joint from model.
380                @param removeattachedneurons if not 0 -> remove neurons attached to this joint */
381        void removeJoint(int jointindex, int removeattachedneurons = 1);
382
383        /** remove the neuron from model.
384                @param removereferences if true -> look for references to this neuron
385                (i.e. connections from other neurons) and remove them as well */
386        void removeNeuro(int neuroindex, bool removereferences = true);
387
388        void removeNeuros(SList &nlist);
389
390        /// @return part index or -1 if not found in the model
391        int findPart(Part* p);
392        /// @return joint index or -1 if not found in the model
393        int findJoint(Joint* j);
394        /// @return neuro index or -1 if not found in the model
395        int findNeuro(Neuro* nu);
396        /// @return joint index or -1 if not found in the model
397        int findJoint(Part *p1, Part *p2);
398
399        /** make the list of neuros satisfying given search criteria: classname,part,joint
400                @param result objects will be appended here
401                @return number of objects found  */
402        int findNeuros(SList& result, const char* classname = 0, const Part* part = 0, const Joint* joint = 0);
403
404        /** search for joints connected to the part
405                @param result objects will be appended here
406                @return number of objects found  */
407        int findJoints(SList& result, const Part* part = 0);
408
409        void disturb(double amount);
410        void move(const Pt3D& shift);
411        /// rotate around the origin (move-rotate-move to rotate around arbitrary point)
412        void rotate(const Orient& rotation);
413        /// rotate around the origin (move-rotate-move to rotate around arbitrary point)
414        void rotate(const Pt3D& angles) { Orient o = Orient_1; o.rotate(angles); rotate(o); }
415
416        /// build this model using solid shape types, based on the provided ball-and-stick model. See also shapeconvert.cpp.
417        void buildUsingSolidShapeTypes(const Model& src_ballandstick_shapes, Part::Shape use_shape = Part::SHAPE_CYLINDER, float thickness = 0.2);
418
419#ifdef EASYMAPDEBUG
420        static int partToMap(int i) {return 0+i;}
421        static int jointToMap(int i) {return 10+i;}
422        static int neuroToMap(int i) {return 20+i;}
423        static int mapToPart(int i) {return i-0;}
424        static int mapToJoint(int i) {return i-10;}
425        static int mapToNeuro(int i) {return i-20;}
426#else
427        static int partToMap(int i) { return 0x10000000 + i; }
428        static int jointToMap(int i) { return 0x20000000 + i; }
429        static int neuroToMap(int i) { return 0x30000000 + i; }
430        static int mapToPart(int i) { return i - 0x10000000; }
431        static int mapToJoint(int i) { return i - 0x20000000; }
432        static int mapToNeuro(int i) { return i - 0x30000000; }
433#endif
434
435        static void makeGenToGenMap(MultiMap& result, const MultiMap& gen1tomodel, const MultiMap& gen2tomodel);
436
437        ///////////////////////////
438
439        static Part& getMinPart();
440        static Part& getMaxPart();
441        static Part& getDefPart();
442        static Joint& getMinJoint();
443        static Joint& getMaxJoint();
444        static Joint& getDefJoint();
445        static Neuro& getMinNeuro();
446        static Neuro& getMaxNeuro();
447        static Neuro& getDefNeuro();
448};
449
450/**
451   An object of this class is created from a Model and returns the solids-type const Model& regardless of the source Model shape type.
452   For solids-type Models, the same source Model reference is returned.
453   For ball-and-stick-type Models, the new temporary Model is created (using Model::buildUsingSolidShapeTypes).
454   Useful for making the solids-only code work for both solids Models and ball-and-stick Models, without if's and special cases, like in this example:
455   
456   void fun(const Model& input) // 'input' can be any shape type
457   {
458      SolidsShapeTypeModel converted(input); // 'converted' contains either 'input' or the new solids-type Model created from 'input'
459      functionAcceptingSolidsTypeModel(converted); // operator const Model&() is called automatically because of the function signature
460      int n=converted.getModel().getPartCount(); // getting the const Model& explicitly (converted.getPartCount() would fail)
461   }
462 */
463class SolidsShapeTypeModel
464{
465public:
466        Model *converted_model;
467        const Model *using_model;
468        SolidsShapeTypeModel(const Model& m, Part::Shape use_shape = Part::SHAPE_CYLINDER, float thickness = 0.2);
469        operator const Model&() const { return *using_model; }
470        const Model& getModel() const { return *using_model; }
471        ~SolidsShapeTypeModel() { if (converted_model) delete converted_model; }
472};
473
474#endif
Note: See TracBrowser for help on using the repository browser.