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

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

Model::rawGeno() now ignores model validity

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