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

Last change on this file since 997 was 997, checked in by Maciej Komosinski, 2 years ago

Make getPreferredLocation() return the proper PrefLocation? enum, not its int counterpart

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