source: cpp/frams/model/modelparts.h @ 972

Last change on this file since 972 was 972, checked in by Maciej Komosinski, 4 years ago
  • separate "0" and "0s" formats (for SHAPE_BALL_AND_STICK and SHAPE_SOLIDS, respectively)
  • converting to format list (Geno::F0_FORMAT_LIST = "0,0s")
  • (optional) declaring Model as SHAPE_BALL_AND_STICK or SHAPE_SOLIDS (or SHAPE_UNKNOWN)
  • Property svn:eol-style set to native
File size: 18.0 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#ifndef _MODELPARTS_H_
6#define _MODELPARTS_H_
7
8#include <frams/util/3d.h>
9#include <frams/genetics/genoconv.h>
10
11#include <frams/util/extvalue.h>
12#include <frams/util/list.h>
13#include <frams/util/sstring.h>
14#include <frams/util/sstringutils.h>
15#include <frams/param/param.h>
16#include <frams/param/syntparam.h>
17#include <frams/util/usertags.h>
18#include <frams/param/paramtabobj.h>
19
20#include <stdio.h>
21
22class Model;
23class IRange;
24class MultiRange;
25
26typedef UserTags<Model, void *, 5> ModelUserTags;
27
28
29/// Introduced only because we can't have a forward declaration of enum in the Model class,
30/// and we would need a forward declaration because of mutual (cyclic) dependence of declarations of Model and NeuroClass.
31/// https://stackoverflow.com/questions/27019292/is-in-class-enum-forward-declaration-possible
32/// Use Model::... instead of ModelEnum::...
33class ModelEnum
34{
35public:
36        enum ShapeType { SHAPE_BALL_AND_STICK = 0, SHAPE_SOLIDS = 1, SHAPE_UNKNOWN, SHAPE_ILLEGAL }; ///< 0 and 1 have special significance - these values allow for bit operations.
37};
38
39
40/** Common base for model elements. */
41class PartBase
42{
43public:
44        SString vis_style;
45        PartBase(const SString &s) :vis_style(s), mapped(0) {}
46        ~PartBase();
47        static SString getDefaultStyle() { return SString("none"); }
48        MultiRange *mapped;
49        enum PartBaseFlags { Selected = 1 };
50        int flags;
51        Model *owner;   ///< backlink to the model
52
53        SString info;
54
55        Model &getModel() const { return *owner; }
56
57        ModelUserTags userdata;
58
59        void notifyMappingChange();
60
61        void clearMapping();
62        MultiRange *getMapping() { return mapped; }
63        void setMapping(const IRange &mr);
64        void addMapping(const IRange &mr);
65        void setMapping(const MultiRange &mr);
66        void addMapping(const MultiRange &mr);
67
68        void setInfo(const SString &name, const SString &value);
69        void setInfo(const SString &name, int value);
70        void setInfo(const SString &name, double value);
71        SString getInfo(const SString &name);
72};
73
74/// Part is the only real physical object in the Framsticks creature.
75/// You can use this class for querying and adjusting constructed
76/// model properties
77class Part : public PartBase
78{
79        friend class Model;
80        static SString getDefaultStyle();
81        Part(double _mass, double _size, double _density, double _friction, double _ingest, double _assim)
82                :PartBase(getDefaultStyle()), mass(_mass), size(_size), density(_density), friction(_friction), ingest(_ingest), assim(_assim)
83        {}
84        void defassign();
85public:
86        // base properties - have special meaning and therefore are often accessed directly for convenience
87        Pt3D p;    ///< 3d coordinates of the part
88        Orient o;  ///< orientation in 3d space (rotation matrix)
89        /// ParamInterface object is preferred way to get/set other properties.
90        Param extraProperties();
91        Param properties();
92        paInt refno;
93        Pt3D rot;///< rotation angles
94
95        ///
96        paInt shape;///default=old Framsticks compatible, do not mix with shapes>0
97        enum Shape { SHAPE_BALL_AND_STICK = 0, SHAPE_ELLIPSOID = 1, SHAPE_CUBOID = 2, SHAPE_CYLINDER = 3 };
98        double mass, size, density, friction, ingest, assim, hollow;
99        Pt3D scale;
100        Pt3D food;
101        //SList points; // collistion points
102        //Slist neurons; // "select * from owner->neurons where part=this" ;-)
103
104        Pt3D vcolor;
105        double vsize;
106
107        Part(enum Shape s = SHAPE_BALL_AND_STICK);
108        Part(const Part &src) :PartBase(getDefaultStyle()) { operator=(src); }
109        void operator=(const Part &src);
110
111        void setPositionAndRotationFromAxis(const Pt3D &p1, const Pt3D &p2);
112        void setOrient(const Orient &o);///< set part.o and calculates part.rot (rotation angles)
113        void setRot(const Pt3D &r);///< set part.rot (rotation angles) and calculate part.o
114
115        static Param &getStaticParam();
116};
117
118class Part_MinMaxDef : public Part //contains additional information for Model::getMinPart()/getMaxPart()/getDefPart()
119{
120public:
121        double volume; ///< Introduced to limit the range of volumes (~mass) in simulation of solids. Genetic operators should observe this min,max volume by calculating and limiting the volume of Parts based on their type and sx,sy,sz.
122
123        void defassign();
124        Part_MinMaxDef() { defassign(); }
125};
126
127/// Imaginary connection between two parts.
128/// Joint has no mass nor intertia but can transfer forces.
129class Joint : public PartBase
130{
131        friend class Model;
132        SString getDefaultStyle();
133        Joint(double _stamina, double _stif, double _rotstif, double _d)
134                :PartBase(getDefaultStyle()), stamina(_stamina), stif(_stif), rotstif(_rotstif)
135        {
136                d = Pt3D(_d, 0, 0);
137        }
138        void defassign();
139        void resetDeltaMarkers();
140public:
141        // base properties:
142        paInt p1_refno, p2_refno; ///< parts' reference numbers
143
144        Part *part1, *part2;    ///< references to parts
145        class Pt3D d;           ///< position delta between parts
146        class Pt3D rot; ///< orientation delta between parts expressed as 3 angles
147        enum Shape {
148                SHAPE_BALL_AND_STICK = 0, ///<  old Framsticks compatible, creates a physical rod between parts (cylinder or cuboid), do not mix with part.shape>0
149                SHAPE_FIXED = 1, ///< merge parts into one physical entity
150                SHAPE_HINGE_X = 2, ///< hinge connection, revolving around X axis defined by hinge_pos and hinge_rot
151                SHAPE_HINGE_XY = 3 ///< double hinge connection, revolving around X and Y axes defined by hinge_pos and hinge_rot
152        };
153        paInt shape;///< values of type Shape (paInt for integration with Param)
154        class Pt3D hinge_pos; ///< hinge position (relative to part1) for HINGE_X and HINGE_XY
155        class Pt3D hinge_rot; ///< hinge orientation (relative to part1) for HINGE_X and HINGE_XY
156        double hinge_limit_x[2], hinge_limit_y[2]; ///< hinge movement range - i.e., extreme allowed values of a state. A state can be an angle or other physical property. limit[0] <= 0 <= limit[1]. Relative Part position and orientation as set in the Model define the initial state 0.
157
158        Joint();
159        Joint(const Joint &src) :PartBase(getDefaultStyle()) { operator=(src); }
160        void operator=(const Joint &src);
161
162        /** connect two parts with this joint.
163                p2 position will be adjusted if delta option is in effect.
164                @see isDelta()
165                */
166        void attachToParts(Part *p1, Part *p2);
167        /// @see attachToParts(Part*,Part*)
168        void attachToParts(int p1, int p2);
169
170        /** discard delta information but don't disable delta flag.
171                delta will be calculated from parts positions during final consistency check.
172                */
173        void resetDelta();
174
175        /** enable or disable delta option.
176                delta value is not changed.
177                */
178        void useDelta(bool use);
179
180        /** @return true if delta option is in effect.
181                @see useDelta(), resetDelta(), useDelta()
182                */
183        bool isDelta();
184
185        /// ParamInterface object is preferred way to get/set other properties.
186        Param extraProperties();
187        Param properties();
188
189        // do not touch these:
190        paInt refno; ///< this joint's reference number
191        double stamina;
192        double stif, rotstif;   ///< stiffness for moving and bending forces
193        class Orient o; ///< orientation delta between parts as rotation matrix
194        /** flag: generated f0 should include delta data.
195                set by 'singlestep' if j: attributes use delta option */
196        bool usedelta;
197        Pt3D vcolor;
198
199        static Param &getStaticParam();
200};
201
202#define JOINT_DELTA_MARKER 99999.0
203
204
205
206////////////////// Neural Network /////////////////
207
208class NeuroClass;
209
210typedef UserTags<NeuroClass, void *, 5> NeuroClassUserTags;
211
212/** Information about neuron class.
213 */
214class NeuroClass
215{
216        bool ownedvectordata;
217        void operator=(const NeuroClass &nosuchthich) {}
218public:
219        SString name, longname, description;
220        ParamEntry *props;
221        bool ownedprops;//< destructor will free props using ParamObject::freeParamTab
222        paInt prefinputs, prefoutput;
223        paInt preflocation;
224
225        static constexpr int SUPPORTED_SHAPE_BALL_AND_STICK = 1;
226        static constexpr int SUPPORTED_SHAPE_SOLIDS = 2;
227        static constexpr int SUPPORTED_SHAPE_ALL = SUPPORTED_SHAPE_BALL_AND_STICK | SUPPORTED_SHAPE_SOLIDS;
228        paInt supported_shape_types; //< bitfield of 'Model::shape' values: NeuroClass::SUPPORTED_SHAPE_xxx = 1 << Model::SHAPE_xxx
229        int *vectordata;
230        paInt visualhints;
231
232        //void *impl;
233        int impl_count;
234        bool active;
235        bool genactive;
236        NeuroClassUserTags userdata;
237
238        //////////////////////
239        ~NeuroClass();
240        NeuroClass();
241        NeuroClass(ParamEntry *_props, SString _description,
242                int _prefinputs, int _prefoutput, int _preflocation, int *_vectordata, bool own_vd = 1, int vhints = 0, int sup_shapes = NeuroClass::SUPPORTED_SHAPE_ALL);
243        /** class name for use in Neuro::setClassName(), Neuro::setDetails() (former 'moredata' field),
244                eg. "N","-",G" */
245        const SString &getName() { return name; }
246        /** human friendly name, eg. "Neuron","Link","Gyroscope"  */
247        const SString &getLongName() { return longname; }
248        /** long description */
249        const SString &getDescription() { return description; }
250        ParamEntry *getParamTab() { return props; }
251
252        /** NeuroClass specific properties, recognized by all neurons of this class */
253        Param getProperties() { return Param(props); }
254
255        /** preferred number of inputs, -1 = no preference (any number will go).
256                extra inputs may be ignored by the object (depends on the class).
257                */
258        int getPreferredInputs() { return (int)prefinputs; }
259
260        /** @return 0 if this object doesn't provide useful output signal. */
261        int getPreferredOutput() { return (int)prefoutput; }
262
263        /** @return 0 if the object doesn't need any assignment to the body element.
264                @return 1 = it likes to be attached to the Part ( @see Neuro::attachToPart() )
265                @return 2 = the object prefers to have the Joint ( @see Neuro::attachToJoint() )
266                */
267        int getPreferredLocation() { return (int)preflocation; }
268        /** vector drawing to be used in neuro net diagram.
269                interpretation:
270                {
271                LEN = datalength (excluding this number)
272                NL = number_of_lines
273                line#1 ->  NS = number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1,
274                ...
275                line#NL -> NS = number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1,
276                }
277                */
278        int getSupportedShapeTypes() { return (int)supported_shape_types; }
279        bool isShapeTypeSupported(ModelEnum::ShapeType t) { return (1 << (int)t) & supported_shape_types; }
280        int *getSymbolGlyph()
281        {
282                return vectordata;
283        }
284        void setSymbolGlyph(int *data, bool owned = 1)
285        {
286                if (vectordata && ownedvectordata) delete[]vectordata;
287                vectordata = data; ownedvectordata = owned;
288        }
289        /** additional information about how the neuron should be drawn
290                used by structure view (and maybe some other components).
291                return value is defined by the enum Hint
292                @see enum Hint
293                */
294        int getVisualHints()
295        {
296                return (int)visualhints;
297        }
298
299        enum Hint
300        {
301                /** don't draw neurons of this class */
302                Invisible = 1,
303                /** don't draw classname label below the neuron */
304                DontShowClass = 2,
305                /** draw the neuron at the first part when attached to joint (default is in the middle) */
306                AtFirstPart = 4,
307                /** draw the neuron at the second part when attached to joint (default is in the middle) */
308                AtSecondPart = 8,
309                /** use effector colour for this neuro unit */
310                EffectorClass = 16,
311                /** use receptor colour for this neuro unit */
312                ReceptorClass = 32,
313                IsV1BendMuscle = 64,
314                IsV1RotMuscle = 128,
315                IsLinearMuscle = 256,
316                IsSolidMuscle = 512
317        };
318
319        /** textual summary, automatically generated from other properties (like the neuro class tooltip) */
320        SString getSummary();
321
322        static void resetActive(); ///< set default values of active and genactive for all classes
323        static void setGenActive(const char *classes[]); ///< set genactive for specified classes
324};
325
326
327
328
329
330
331/** Single processing unit in Framsticks neural network.  */
332class Neuro : public PartBase
333{
334        friend class Model;
335        static SString getDefaultStyle();
336
337        struct NInput {
338                Neuro *n; double weight; SString *info;
339                NInput(Neuro *_n, double w, SString *i = 0) :n(_n), weight(w), info(i) {}
340        };
341
342        SListTempl<NInput> inputs;
343
344        NeuroClass *myclass;
345        bool knownclass;
346        SString myclassname, myclassparams;
347        /** set myclass and make knownclass=true */
348        void checkClass();
349        SString **inputInfo(int i);
350        void defassign();
351
352public:
353        enum NeuroFlags { HoldState = 2 };
354        Param properties();
355        Param extraProperties();
356
357        void setInputInfo(int i, const SString &name, const SString &value);
358        void setInputInfo(int i, const SString &name, int value);
359        void setInputInfo(int i, const SString &name, double value);
360        SString getInputInfo(int i);
361        SString getInputInfo(int i, const SString &name);
362
363        NeuroClass *getClass();
364        void setClass(NeuroClass *);
365
366        SString getClassParams() { return myclassparams; }
367        void setClassParams(const SString &cp) { myclassparams = cp; }
368
369        SString getClassName();
370        void setClassName(const SString &clazz);
371
372        /** return neuro unit details encoded as <CLASS> ":" <PROPERTIES>
373
374                new Neuro can be created as root object (without parent) or can be
375                the child of existing Neuro. Children of the Neuro are its inputs.
376                Standard Framsticks neuron calculates the sum of all input units - other processing
377                units don't have to treat them equally and can even ignore some of them.
378                There are hints about expected inputs in the class database, @see getClass
379
380                Application should not assume anything about classes and its properties
381                except for two standard classes: (information about all current classes
382                can be retrieved with getClass/getClassProperties methods)
383                - getClassName()="N" is the standard Framsticks neuron, accepts any number of inputs,
384                compatible with old Neuro object
385                - getClassName()="-" is the neuron link, compatible with old Neuro-Neuro link
386                (NeuroItem with empty details)
387                Empty details defaults to "-" if the parent unit is specified,
388                and "N" if the unit has no parent.
389                */
390        SString getDetails();
391
392        /** details = classname + ":" + classparams
393                @see getDetails()
394                */
395        void setDetails(const SString &);
396
397#define STATRICKCLASS Neuro
398        PARAMGETDEF(details) { arg1->setString(getDetails()); }
399        PARAMSETDEF(details) { setDetails(arg1->getString()); return PSET_CHANGED; }
400        PARAMGETDEF(inputCount);
401        PARAMPROCDEF(p_getInputNeuroDef);
402        PARAMPROCDEF(p_getInputNeuroIndex);
403        PARAMPROCDEF(p_getInputWeight);
404        PARAMGETDEF(classObject);
405#undef STATRICKCLASS
406
407        ///@param handle_defaults_when_saving see SyntParam
408        SyntParam classProperties(bool handle_defaults_when_saving = true);
409        // base properties:
410        paInt refno; ///< unique reference number (former 'neuro' refno)
411
412        paInt part_refno; ///< can be used by some items as the part ref#
413        paInt joint_refno; ///< can be used by some items as the joint ref#
414
415        Pt3D pos, rot;  ///< default = zero
416
417        ModelUserTags userdata;
418
419        Neuro();
420        Neuro(double _state, double _inertia, double _force, double _sigmo);
421        Neuro(const Neuro &src) :PartBase(getDefaultStyle()) { operator=(src); }
422
423        ~Neuro();
424
425        void operator=(const Neuro &src);
426
427        /** Attach this Neuro to the specified Part or detach it from the body if p==NULL.
428                Neuro can be attached to either Part or Joint, but not both.
429                @see getPart()
430                */
431        void attachToPart(Part *p) { part = p; joint = 0; }
432
433        /** Attach this Neuro to the specified Joint or detach it from the body if p==NULL.
434                Neuro can be attached to either Part or Joint, but not both.
435                @see getJoint()
436                */
437        void attachToJoint(Joint *j) { joint = j; part = 0; }
438
439        void attachToPart(int i);
440        void attachToJoint(int i);
441
442        /** @return Part the Neuro is attached to, or NULL if it has no defined location on the body.
443                @see attachToPart()
444                */
445        Part *getPart() { return part; }
446
447        /** @return Joint the Neuro is attached to, or NULL if it has no defined location on the body.
448                @see attachToJoint()
449                */
450        Joint *getJoint() { return joint; }
451
452        int isOldEffector();
453        int isOldReceptor();
454        int isOldNeuron();
455        int isNNConnection();
456
457        /** @return the number of inputs connected to this Neuro.
458                Functions like getInput(), getInputWeight() will accept connection number [0..InputCount-1]
459                */
460        int getInputCount() const { return inputs.size(); }
461
462        /// @return the number of output connections (including possible self-connections)
463        int getOutputsCount() const;
464
465        /** @return the Neuro connected as i-th input */
466        Neuro *getInput(int i) const { return (i >= inputs.size()) ? 0 : inputs(i).n; }
467        /** @return the Neuro connected as i-th input.
468                @param weight
469                */
470        Neuro *getInput(int i, double &weight) const;
471        /** @return connectin weight for i-th input */
472        double getInputWeight(int i) const;
473        /** change connection weight for i-th input */
474        void setInputWeight(int i, double weight);
475        /** connect i-th input with another neuron */
476        void setInput(int i, Neuro *n);
477        /** connect i-th input with another neuron */
478        void setInput(int i, Neuro *n, double weight);
479        /** add new input. @return its reference number */
480        int addInput(Neuro *child, double weight = 1.0, const SString *info = 0);
481        /** @return reference number [0..InputCount-1] of the input
482           or -1 if 'child' is not connected with this Neuro.*/
483        int findInput(Neuro *child) const;
484        void removeInput(paInt refno);
485        /**    @return reference number of the child connection, like findInput() */
486        int removeInput(Neuro *child);
487
488        int findInputs(SList &result, const char *classname = 0, const Part *part = 0, const Joint *joint = 0) const;
489        int findOutputs(SList &result, const char *classname = 0, const Part *part = 0, const Joint *joint = 0) const;
490
491        /* class database retrieval */
492        static int getClassCount();
493        /** @return Neuro class name.
494                @param classindex 0 .. getClassCount()
495                */
496        static SString getClassName(int classindex);
497        static NeuroClass *getClass(int classindex);
498        static NeuroClass *getClass(const SString &classname);
499        static int getClassIndex(const NeuroClass *nc);
500
501        // not really private, but you should not access those directly
502        double state;
503
504        /** may reference parent neuron if parentcount is exacty 1. parent is invalid otherwise. @sa parentcount */
505        Neuro *parent;
506        int parentcount; ///< @sa parent
507
508        Part *part;     ///< link to the Part
509        Joint *joint;   ///< link to the Joint - required by some objects (eg.muscles)
510        Orient o;       ///< rotation matrix calculated from "rot"
511        static ParamEntry emptyParamTab[];
512        static Param &getStaticParam();
513};
514
515class NeuroExt : public Neuro
516{
517public:
518#define STATRICKCLASS NeuroExt
519        PARAMGETDEF(neuroclass);
520        PARAMSETDEF(neuroclass);
521        PARAMGETDEF(liveNeuro);
522#undef STATRICKCLASS
523        static ParamEntry *getParamTab();
524};
525
526class NeuroConn
527{
528        void defassign();
529public:
530        int n1_refno, n2_refno;
531        double weight;
532        SString info;
533        NeuroConn();
534};
535
536extern ParamEntry f0_part_paramtab[], f0_part_minmaxdef_paramtab[], f0_joint_paramtab[], f0_nodeltajoint_paramtab[], f0_neuro_paramtab[], f0_neuroconn_paramtab[], f0_neuroitem_paramtab[];
537
538#endif
Note: See TracBrowser for help on using the repository browser.