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

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

Added NeuroClass::getSupportedJointTypes() and NeuroClass::isJointTypeSupported() for use in genetic operators

  • Property svn:eol-style set to native
File size: 18.7 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
230        static constexpr int SUPPORTED_JOINT_BALL_AND_STICK = 1;
231        static constexpr int SUPPORTED_JOINT_FIXED = 2;
232        static constexpr int SUPPORTED_JOINT_HINGE_X = 4;
233        static constexpr int SUPPORTED_JOINT_HINGE_XY = 8;
234        static constexpr int SUPPORTED_JOINT_ALL = SUPPORTED_JOINT_BALL_AND_STICK + SUPPORTED_JOINT_FIXED + SUPPORTED_JOINT_HINGE_X + SUPPORTED_JOINT_HINGE_XY;
235        paInt supported_joint_types; //< bitfield of 'Joint::shape' values: NeuroClass::SUPPORTED_JOINT_xxx = 1 << JOINT::SHAPE_xxx
236
237        int *vectordata;
238        paInt visualhints;
239
240        //void *impl;
241        int impl_count;
242        bool active;
243        bool genactive;
244        NeuroClassUserTags userdata;
245
246        //////////////////////
247        ~NeuroClass();
248        NeuroClass();
249        NeuroClass(ParamEntry *_props, SString _description,
250                   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);
251        /** class name for use in Neuro::setClassName(), Neuro::setDetails() (former 'moredata' field),
252                eg. "N","-",G" */
253        const SString &getName() { return name; }
254        /** human friendly name, eg. "Neuron","Link","Gyroscope"  */
255        const SString &getLongName() { return longname; }
256        /** long description */
257        const SString &getDescription() { return description; }
258        ParamEntry *getParamTab() { return props; }
259
260        /** NeuroClass specific properties, recognized by all neurons of this class */
261        Param getProperties() { return Param(props); }
262
263        /** preferred number of inputs, -1 = no preference (any number will go).
264                extra inputs may be ignored by the object (depends on the class).
265                */
266        int getPreferredInputs() { return (int)prefinputs; }
267
268        /** @return 0 if this object doesn't provide useful output signal. */
269        int getPreferredOutput() { return (int)prefoutput; }
270
271        /** @return 0 if the object doesn't need any assignment to the body element.
272                @return 1 = it likes to be attached to the Part ( @see Neuro::attachToPart() )
273                @return 2 = the object prefers to have the Joint ( @see Neuro::attachToJoint() )
274                */
275        int getPreferredLocation() { return (int)preflocation; }
276        /** vector drawing to be used in neuro net diagram.
277                interpretation:
278                {
279                LEN = datalength (excluding this number)
280                NL = number_of_lines
281                line#1 ->  NS = number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1,
282                ...
283                line#NL -> NS = number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1,
284                }
285                */
286        int getSupportedShapeTypes() { return (int)supported_shape_types; }
287        bool isShapeTypeSupported(ModelEnum::ShapeType t) { return (1 << (int)t) & supported_shape_types; }
288        int getSupportedJointTypes() { return (int)supported_joint_types; }
289        bool isJointTypeSupported(Joint::Shape t) { return (1 << (int)t) & supported_joint_types; }
290        int *getSymbolGlyph()
291        {
292                return vectordata;
293        }
294        void setSymbolGlyph(int *data, bool owned = 1)
295        {
296                if (vectordata && ownedvectordata) delete[]vectordata;
297                vectordata = data; ownedvectordata = owned;
298        }
299        /** additional information about how the neuron should be drawn
300                used by structure view (and maybe some other components).
301                return value is defined by the enum Hint
302                @see enum Hint
303                */
304        int getVisualHints()
305        {
306                return (int)visualhints;
307        }
308
309        enum Hint
310        {
311                /** don't draw neurons of this class */
312                Invisible = 1,
313                /** don't draw classname label below the neuron */
314                DontShowClass = 2,
315                /** draw the neuron at the first part when attached to joint (default is in the middle) */
316                AtFirstPart = 4,
317                /** draw the neuron at the second part when attached to joint (default is in the middle) */
318                AtSecondPart = 8,
319                /** use effector colour for this neuro unit */
320                EffectorClass = 16,
321                /** use receptor colour for this neuro unit */
322                ReceptorClass = 32,
323                IsV1BendMuscle = 64,
324                IsV1RotMuscle = 128,
325                IsLinearMuscle = 256,
326                IsSolidMuscle = 512
327        };
328
329        /** textual summary, automatically generated from other properties (like the neuro class tooltip) */
330        SString getSummary();
331
332        static void resetActive(); ///< set default values of active and genactive for all classes
333        static void setGenActive(const char *classes[]); ///< set genactive for specified classes
334};
335
336
337
338
339
340
341/** Single processing unit in Framsticks neural network.  */
342class Neuro : public PartBase
343{
344        friend class Model;
345        static SString getDefaultStyle();
346
347        struct NInput {
348                Neuro *n; double weight; SString *info;
349                NInput(Neuro *_n, double w, SString *i = 0) :n(_n), weight(w), info(i) {}
350        };
351
352        SListTempl<NInput> inputs;
353
354        NeuroClass *myclass;
355        bool knownclass;
356        SString myclassname, myclassparams;
357        /** set myclass and make knownclass=true */
358        void checkClass();
359        SString **inputInfo(int i);
360        void defassign();
361
362public:
363        enum NeuroFlags { HoldState = 2 };
364        Param properties();
365        Param extraProperties();
366
367        void setInputInfo(int i, const SString &name, const SString &value);
368        void setInputInfo(int i, const SString &name, int value);
369        void setInputInfo(int i, const SString &name, double value);
370        SString getInputInfo(int i);
371        SString getInputInfo(int i, const SString &name);
372
373        NeuroClass *getClass();
374        void setClass(NeuroClass *);
375
376        SString getClassParams() { return myclassparams; }
377        void setClassParams(const SString &cp) { myclassparams = cp; }
378
379        SString getClassName();
380        void setClassName(const SString &clazz);
381
382        /** return neuro unit details encoded as <CLASS> ":" <PROPERTIES>
383
384                new Neuro can be created as root object (without parent) or can be
385                the child of existing Neuro. Children of the Neuro are its inputs.
386                Standard Framsticks neuron calculates the sum of all input units - other processing
387                units don't have to treat them equally and can even ignore some of them.
388                There are hints about expected inputs in the class database, @see getClass
389
390                Application should not assume anything about classes and its properties
391                except for two standard classes: (information about all current classes
392                can be retrieved with getClass/getClassProperties methods)
393                - getClassName()="N" is the standard Framsticks neuron, accepts any number of inputs,
394                compatible with old Neuro object
395                - getClassName()="-" is the neuron link, compatible with old Neuro-Neuro link
396                (NeuroItem with empty details)
397                Empty details defaults to "-" if the parent unit is specified,
398                and "N" if the unit has no parent.
399                */
400        SString getDetails();
401
402        /** details = classname + ":" + classparams
403                @see getDetails()
404                */
405        void setDetails(const SString &);
406
407#define STATRICKCLASS Neuro
408        PARAMGETDEF(details) { arg1->setString(getDetails()); }
409        PARAMSETDEF(details) { setDetails(arg1->getString()); return PSET_CHANGED; }
410        PARAMGETDEF(inputCount);
411        PARAMPROCDEF(p_getInputNeuroDef);
412        PARAMPROCDEF(p_getInputNeuroIndex);
413        PARAMPROCDEF(p_getInputWeight);
414        PARAMGETDEF(classObject);
415#undef STATRICKCLASS
416
417        ///@param handle_defaults_when_saving see SyntParam
418        SyntParam classProperties(bool handle_defaults_when_saving = true);
419        // base properties:
420        paInt refno; ///< unique reference number (former 'neuro' refno)
421
422        paInt part_refno; ///< can be used by some items as the part ref#
423        paInt joint_refno; ///< can be used by some items as the joint ref#
424
425        Pt3D pos, rot;  ///< default = zero
426
427        ModelUserTags userdata;
428
429        Neuro();
430        Neuro(double _state, double _inertia, double _force, double _sigmo);
431        Neuro(const Neuro &src) :PartBase(getDefaultStyle()) { operator=(src); }
432
433        ~Neuro();
434
435        void operator=(const Neuro &src);
436
437        /** Attach this Neuro to the specified Part or detach it from the body if p==NULL.
438                Neuro can be attached to either Part or Joint, but not both.
439                @see getPart()
440                */
441        void attachToPart(Part *p) { part = p; joint = 0; }
442
443        /** Attach this Neuro to the specified Joint or detach it from the body if p==NULL.
444                Neuro can be attached to either Part or Joint, but not both.
445                @see getJoint()
446                */
447        void attachToJoint(Joint *j) { joint = j; part = 0; }
448
449        void attachToPart(int i);
450        void attachToJoint(int i);
451
452        /** @return Part the Neuro is attached to, or NULL if it has no defined location on the body.
453                @see attachToPart()
454                */
455        Part *getPart() { return part; }
456
457        /** @return Joint the Neuro is attached to, or NULL if it has no defined location on the body.
458                @see attachToJoint()
459                */
460        Joint *getJoint() { return joint; }
461
462        int isOldEffector();
463        int isOldReceptor();
464        int isOldNeuron();
465        int isNNConnection();
466
467        /** @return the number of inputs connected to this Neuro.
468                Functions like getInput(), getInputWeight() will accept connection number [0..InputCount-1]
469                */
470        int getInputCount() const { return inputs.size(); }
471
472        /// @return the number of output connections (including possible self-connections)
473        int getOutputsCount() const;
474
475        /** @return the Neuro connected as i-th input */
476        Neuro *getInput(int i) const { return (i >= inputs.size()) ? 0 : inputs(i).n; }
477        /** @return the Neuro connected as i-th input.
478                @param weight
479                */
480        Neuro *getInput(int i, double &weight) const;
481        /** @return connectin weight for i-th input */
482        double getInputWeight(int i) const;
483        /** change connection weight for i-th input */
484        void setInputWeight(int i, double weight);
485        /** connect i-th input with another neuron */
486        void setInput(int i, Neuro *n);
487        /** connect i-th input with another neuron */
488        void setInput(int i, Neuro *n, double weight);
489        /** add new input. @return its reference number */
490        int addInput(Neuro *child, double weight = 1.0, const SString *info = 0);
491        /** @return reference number [0..InputCount-1] of the input
492           or -1 if 'child' is not connected with this Neuro.*/
493        int findInput(Neuro *child) const;
494        void removeInput(paInt refno);
495        /**    @return reference number of the child connection, like findInput() */
496        int removeInput(Neuro *child);
497
498        int findInputs(SList &result, const char *classname = 0, const Part *part = 0, const Joint *joint = 0) const;
499        int findOutputs(SList &result, const char *classname = 0, const Part *part = 0, const Joint *joint = 0) const;
500
501        /* class database retrieval */
502        static int getClassCount();
503        /** @return Neuro class name.
504                @param classindex 0 .. getClassCount()
505                */
506        static SString getClassName(int classindex);
507        static NeuroClass *getClass(int classindex);
508        static NeuroClass *getClass(const SString &classname);
509        static int getClassIndex(const NeuroClass *nc);
510
511        // not really private, but you should not access those directly
512        double state;
513
514        /** may reference parent neuron if parentcount is exacty 1. parent is invalid otherwise. @sa parentcount */
515        Neuro *parent;
516        int parentcount; ///< @sa parent
517
518        Part *part;     ///< link to the Part
519        Joint *joint;   ///< link to the Joint - required by some objects (eg.muscles)
520        Orient o;       ///< rotation matrix calculated from "rot"
521        static ParamEntry emptyParamTab[];
522        static Param &getStaticParam();
523};
524
525class NeuroExt : public Neuro
526{
527public:
528#define STATRICKCLASS NeuroExt
529        PARAMGETDEF(neuroclass);
530        PARAMSETDEF(neuroclass);
531        PARAMGETDEF(liveNeuro);
532#undef STATRICKCLASS
533        static ParamEntry *getParamTab();
534};
535
536class NeuroConn
537{
538        void defassign();
539public:
540        int n1_refno, n2_refno;
541        double weight;
542        SString info;
543        NeuroConn();
544};
545
546extern ParamEntry f0_part_paramtab[], f0_part_minmaxdef_paramtab[], f0_joint_paramtab[], f0_nodeltajoint_paramtab[], f0_neuro_paramtab[], f0_neuroconn_paramtab[], f0_neuroitem_paramtab[];
547
548#endif
Note: See TracBrowser for help on using the repository browser.