source: cpp/frams/model/modelparts.cpp @ 743

Last change on this file since 743 was 743, checked in by Maciej Komosinski, 10 months ago

Introduced different function names in C++ instead of overloading (with the same number of arguments) so that javascript is able to discriminate them

  • Property svn:eol-style set to native
File size: 15.7 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2017  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include <stdlib.h>
6#include <math.h>
7#include <stdio.h>
8#include <string.h>
9#include <ctype.h>
10#include <time.h>
11#include <errno.h>
12
13///////////////////////////////     MODELPARTS.CPP     ///////////////
14
15#include "modelparts.h"
16#include "model.h"
17
18#include <common/nonstd.h>
19#include <frams/param/param.h>
20#include <frams/neuro/neurolibrary.h>
21#include <frams/util/multirange.h>
22#include <frams/util/extvalue.h>
23#include <frams/param/paramobj.h>
24
25#include F0_DEFASSIGN_FILE
26
27#ifndef SDK_WITHOUT_FRAMS
28#include <frams/neuro/neuroclsobject.h>
29#endif
30
31template<>
32char ModelUserTags::reg[5] = { 0 };
33
34/////////////////////////
35
36PartBase::~PartBase()
37{
38        if (mapped) delete mapped;
39}
40
41void PartBase::notifyMappingChange()
42{
43        if (owner) owner->partmappingchanged = 1;
44}
45
46void PartBase::setMapping(const IRange &r)
47{
48        if (mapped) (*mapped) = r;
49        else mapped = new MultiRange(r);
50        notifyMappingChange();
51}
52
53void PartBase::clearMapping()
54{
55        if (mapped) { delete mapped; mapped = 0; }
56}
57
58void PartBase::addMapping(const IRange &r)
59{
60        if (mapped) mapped->add(r);
61        else mapped = new MultiRange(r);
62        notifyMappingChange();
63}
64
65void PartBase::setMapping(const MultiRange &mr)
66{
67        if (mapped) (*mapped) = mr;
68        else mapped = new MultiRange(mr);
69        notifyMappingChange();
70}
71
72void PartBase::addMapping(const MultiRange &mr)
73{
74        if (mapped) mapped->add(mr);
75        else mapped = new MultiRange(mr);
76        notifyMappingChange();
77}
78
79void PartBase::setInfo(const SString& name, const SString& value)
80{
81        strSetField(info, name, value);
82}
83
84void PartBase::setInfo(const SString& name, int value)
85{
86        setInfo(name, SString::valueOf(value));
87}
88
89void PartBase::setInfo(const SString& name, double value)
90{
91        setInfo(name, SString::valueOf(value));
92}
93
94SString PartBase::getInfo(const SString& name)
95{
96        return strGetField(info, name);
97}
98
99/////////////////////////
100
101NeuroClass::NeuroClass(ParamEntry *_props, SString _description,
102        int _prefinputs, int _prefoutput, int _preflocation,
103        int *_vectordata, bool own_vd, int vhints)
104        :ownedvectordata(own_vd),
105        name(_props->name), longname(_props->id), description(_description),
106        props(_props), ownedprops(false),
107        prefinputs(_prefinputs),
108        prefoutput(_prefoutput),
109        preflocation(_preflocation),
110        vectordata(_vectordata),
111        visualhints(vhints), impl_count(0),/*impl(0),*/active(1), genactive(0)
112{}
113
114NeuroClass::~NeuroClass()
115{
116        setSymbolGlyph(0, 0);
117        if (props && ownedprops)
118                ParamObject::freeParamTab(props);
119}
120
121NeuroClass::NeuroClass()
122        :ownedvectordata(0),
123        name("Invalid"),
124        props(empty_paramtab), ownedprops(false),
125        prefinputs(0), prefoutput(0),
126        preflocation(0), vectordata(0),
127        visualhints(0), impl_count(0), /*impl(0),*/ active(1), genactive(0)
128{}
129
130void NeuroClass::resetActive()
131{
132        for (int i = 0; i < Neuro::getClassCount(); i++)
133        {
134                Neuro::getClass(i)->genactive = 0;
135                Neuro::getClass(i)->active = 1;
136        }
137}
138
139void NeuroClass::setGenActive(const char* genactive_classes[])
140{
141        for (const char** n = genactive_classes; *n; n++)
142        {
143                NeuroClass* cls = Neuro::getClass(*n);
144                if (cls) cls->genactive = 1;
145        }
146}
147
148SString NeuroClass::getSummary()
149{
150        SString t;
151        t = getDescription();
152        if (t.len()) t += "\n\n";
153        t += "Characteristics:\n";
154        if (getPreferredInputs())
155        {
156                if (getPreferredInputs() < 0) t += "   supports any number of inputs\n";
157                else if (getPreferredInputs() == 1) t += "   uses single input\n";
158                else t += SString::sprintf("   uses %d inputs\n", getPreferredInputs());
159        }
160        else t += "   does not use inputs\n";
161        if (getPreferredOutput())
162                t += "   provides output value\n";
163        else
164                t += "   does not provide output value\n";
165        switch (getPreferredLocation())
166        {
167        case 0: t += "   does not require location in body\n"; break;
168        case 1: t += "   should be located on a Part\n"; break;
169        case 2: t += "   should be located on a Joint\n"; break;
170        }
171        Param p = getProperties();
172        if (p.getPropCount())
173        {
174                if (t.len()) t += "\n\n";
175                t += "Properties:\n";
176                const char *h;
177                int i;
178                for (i = 0; i < p.getPropCount(); i++)
179                {
180                        if (i) t += "\n";
181                        t += "   "; t += p.name(i); t += " ("; t += p.id(i); t += ") ";
182                        t += p.friendlyTypeDescr(i);
183                        if (h = p.help(i)) if (*h) { t += " - "; t += h; }
184                }
185        }
186        return t;
187}
188
189/////////////////////////
190
191/////////////////////////////////////
192
193Neuro::Neuro(double _state, double _inertia, double _force, double _sigmo)
194        :PartBase(getDefaultStyle()), state(_state)
195{
196        flags = 0;
197        myclass = 0;
198        knownclass = 1;
199        part_refno = -1; joint_refno = -1;
200}
201
202Neuro::Neuro(void) :PartBase(getDefaultStyle())
203{
204        defassign();
205        state = 0.0;
206        myclass = NULL;
207        myclassname = "N";//default d="N" but f0.def is unable to set this (d is GETSET, not a regular FIELD)
208        knownclass = 0;
209        refno = 0;
210        pos = Pt3D_0; rot = Pt3D_0;
211        parent = 0; part = 0; joint = 0;
212        parentcount = 0;
213        flags = 0;
214        part_refno = -1; joint_refno = -1;
215}
216
217
218Neuro::~Neuro()
219{
220        int i;
221        for (i = 0; i < inputs.size(); i++)
222        {
223                NInput &ni = inputs(i);
224                if (ni.info) delete ni.info;
225        }
226}
227
228SString** Neuro::inputInfo(int i)
229{
230        if (i >= getInputCount()) return 0;
231        return &inputs(i).info;
232}
233
234void Neuro::setInputInfo(int i, const SString& name, const SString &value)
235{
236        SString **s = inputInfo(i);
237        if (!s) return;
238        if (!*s) *s = new SString();
239        strSetField(**s, name, value);
240}
241
242void Neuro::setInputInfo(int i, const SString& name, int value)
243{
244        setInputInfo(i, name, SString::valueOf(value));
245}
246
247void Neuro::setInputInfo(int i, const SString& name, double value)
248{
249        setInputInfo(i, name, SString::valueOf(value));
250}
251
252SString Neuro::getInputInfo(int i)
253{
254        SString **s = inputInfo(i);
255        if (!s) return SString();
256        if (!*s) return SString();
257        return **s;
258}
259
260SString Neuro::getInputInfo(int i, const SString& name)
261{
262        SString **s = inputInfo(i);
263        if (!s) return SString();
264        if (!*s) return SString();
265        return strGetField(**s, name);
266}
267
268void Neuro::operator=(const Neuro& src)
269{
270        refno = src.refno;
271        state = src.state;
272        part_refno = -1;
273        joint_refno = -1;
274        pos = src.pos; rot = src.rot;
275        parent = 0; part = 0; joint = 0;
276        parentcount = 0;
277        flags = 0;
278        myclass = src.myclass;
279        knownclass = src.knownclass;
280        myclassname = src.myclassname;
281        myclassparams = src.myclassparams;
282}
283
284void Neuro::attachToPart(int i)
285{
286        attachToPart((i >= 0) ? owner->getPart(i) : 0);
287}
288
289void Neuro::attachToJoint(int i)
290{
291        attachToJoint((i >= 0) ? owner->getJoint(i) : 0);
292}
293
294int Neuro::getClassCount()
295{
296        return NeuroLibrary::staticlibrary.getClassCount();
297}
298
299NeuroClass* Neuro::getClass(int classindex)
300{
301        return NeuroLibrary::staticlibrary.getClass(classindex);
302}
303
304NeuroClass* Neuro::getClass(const SString& classname)
305{
306        return NeuroLibrary::staticlibrary.findClass(classname);
307}
308
309int Neuro::getClassIndex(const NeuroClass*nc)
310{
311        return NeuroLibrary::staticlibrary.classes.find((void*)nc);
312}
313
314NeuroClass* Neuro::getClass()
315{
316        checkClass();
317        return myclass;
318}
319
320void Neuro::setClass(NeuroClass* cl)
321{
322        myclass = cl;
323        myclassname = cl->getName();
324        knownclass = 1;
325}
326
327SString Neuro::getClassName(int classindex)
328{
329        NeuroClass *cl = NeuroLibrary::staticlibrary.getClass(classindex);
330        return cl ? cl->getName() : SString();
331}
332
333void Neuro::setDetails(const SString& details)
334{
335        int colon = details.indexOf(':');
336        if (colon >= 0) { myclassname = details.substr(0, colon); myclassparams = details.substr(colon + 1); }
337        else { myclassname = details; myclassparams = 0; }
338        knownclass = 0;
339}
340
341SString Neuro::getDetails()
342{
343        SString ret = getClassName();
344        if (myclassparams.len()) { if (!ret.len()) ret = "N"; ret += ":"; ret += myclassparams; }
345        return ret;
346}
347
348void Neuro::checkClass()
349{
350        if (knownclass) return;
351        myclass = getClass(myclassname);
352        knownclass = 1;
353}
354
355SyntParam Neuro::classProperties(bool handle_defaults_when_saving)
356{
357        NeuroClass *cl = getClass();
358        ParamEntry *pe = cl ? cl->getParamTab() : emptyParamTab;
359        return SyntParam(pe, &myclassparams, handle_defaults_when_saving);
360}
361
362SString Neuro::getClassName()
363{
364        return myclassname;
365}
366
367void Neuro::setClassName(const SString& clazz)
368{
369        myclassname = clazz;
370        knownclass = 0;
371}
372
373int Neuro::addInput(Neuro* child, double weight, const SString *info)
374{
375        inputs += NInput(child, weight, (info && (info->len())) ? new SString(*info) : 0);
376        child->parentcount++;
377        if (child->parentcount == 1) { child->parent = this; }
378        return inputs.size() - 1;
379}
380
381int Neuro::findInput(Neuro* child) const
382{
383        for (int i = 0; i < inputs.size(); i++)
384                if (inputs(i).n == child) return i;
385        return -1;
386}
387
388Neuro* Neuro::getInput(int i, double &weight) const
389{
390        if (i >= getInputCount()) return 0;
391        NInput &inp = inputs(i);
392        weight = inp.weight;
393        return inp.n;
394}
395
396double Neuro::getInputWeight(int i) const
397{
398        return inputs(i).weight;
399}
400
401void Neuro::setInputWeight(int i, double w)
402{
403        inputs(i).weight = w;
404}
405
406void Neuro::setInput(int i, Neuro* n)
407{
408        NInput &inp = inputs(i);
409        inp.n = n;
410}
411
412void Neuro::setInput(int i, Neuro* n, double w)
413{
414        NInput &inp = inputs(i);
415        inp.n = n;
416        inp.weight = w;
417}
418
419void Neuro::removeInput(int refno)
420{
421        Neuro *child = getInput(refno);
422        child->parentcount--;
423        if (child->parent == this) child->parent = 0;
424        SString *s = inputs(refno).info;
425        if (s) delete s;
426        inputs.remove(refno);
427}
428
429int Neuro::removeInput(Neuro* child)
430{
431        int i = findInput(child);
432        if (i >= 0) removeInput(i);
433        return i;
434}
435
436int Neuro::getOutputsCount() const
437{
438        int c = 0;
439        for (int i = 0; i < owner->getNeuroCount(); i++)
440                for (int j = 0; j < owner->getNeuro(i)->getInputCount(); j++) c += owner->getNeuro(i)->getInput(j) == this;
441        return c;
442}
443
444int Neuro::isOldEffector()
445{
446        static SString bend("|"), rot("@");
447        return ((getClassName() == bend) || (getClassName() == rot));
448}
449
450int Neuro::isOldReceptor()
451{
452        static SString g("G"), t("T"), s("S");
453        return ((getClassName() == g) || (getClassName() == t) || (getClassName() == s));
454}
455
456int Neuro::isOldNeuron()
457{
458        static SString n("N");
459        return (getClassName() == n);
460}
461
462int Neuro::isNNConnection()
463{
464        static SString conn("-");
465        return (getClassName() == conn);
466}
467
468int Neuro::findInputs(SList& result, const char* classname, const Part* part, const Joint* joint) const
469{
470        Neuro *nu;
471        SString cn(classname);
472        int n0 = result.size();
473        for (int i = 0; nu = getInput(i); i++)
474        {
475                if (part)
476                        if (nu->part != part) continue;
477                if (joint)
478                        if (nu->joint != joint) continue;
479                if (classname)
480                        if (nu->getClassName() != cn) continue;
481                result += (void*)nu;
482        }
483        return result.size() - n0;
484}
485
486int Neuro::findOutputs(SList& result, const char* classname, const Part* part, const Joint* joint) const
487{ // not very efficient...
488        Neuro *nu, *inp;
489        SString cn(classname);
490        SList found;
491        int n0 = result.size();
492        for (int i = 0; nu = getModel().getNeuro(i); i++)
493        {
494                if (part)
495                        if (nu->part != part) continue;
496                if (joint)
497                        if (nu->joint != joint) continue;
498                if (classname)
499                        if (inp->getClassName() != cn) continue;
500                for (int j = 0; inp = nu->getInput(j); j++)
501                        if (inp == this)
502                        {
503                        result += (void*)nu;
504                        break;
505                        }
506        }
507        return result.size() - n0;
508}
509
510void Neuro::get_inputCount(PARAMGETARGS)
511{
512        ret->setInt(inputs.size());
513}
514
515void Neuro::p_getInputNeuroDef(ExtValue *args, ExtValue *ret)
516{
517        int i = args->getInt();
518        if ((i < 0) || (i >= inputs.size()))
519                ret->setEmpty();
520        else
521                ret->setObject(ExtObject(&Neuro::getStaticParam(), inputs(i).n));
522}
523
524void Neuro::p_getInputWeight(ExtValue *args, ExtValue *ret)
525{
526        int i = args->getInt();
527        if ((i < 0) || (i >= inputs.size()))
528                ret->setEmpty();
529        else
530                ret->setDouble(inputs(i).weight);
531}
532
533void Neuro::p_getInputNeuroIndex(ExtValue *args, ExtValue *ret)
534{
535        int i = args->getInt();
536        if ((i < 0) || (i >= inputs.size()))
537                ret->setInt(-1);
538        else
539                ret->setInt(inputs(i).n->refno);
540}
541
542void Neuro::get_classObject(PARAMGETARGS)
543{
544#ifndef SDK_WITHOUT_FRAMS
545        NeuroClassExt::makeStaticObject(ret, getClass());
546#endif
547}
548
549///////////////////////////////////////
550
551SString Part::getDefaultStyle()
552{
553        return SString("part");
554}
555SString Joint::getDefaultStyle()
556{
557        return SString("joint");
558}
559/*
560const SString& Neuro::getDefaultStyle()
561{static SString s("neuro"); return s;}
562const SString& NeuroItem::getDefaultStyle()
563{static SString s("neuroitem"); return s;}
564*/
565SString Neuro::getDefaultStyle()
566{
567        return SString("neuro");
568}
569
570Part::Part(enum Shape s) :PartBase(getDefaultStyle())
571{
572        o = Orient_1;
573        p = Pt3D_0;
574        rot = Pt3D_0;
575        flags = 0;
576        defassign();
577        shape = s;
578        mass = 1;
579}
580
581void Part::operator=(const Part& src)
582{
583        p = src.p; o = src.o;
584        flags = src.flags;
585        mass = src.mass; density = src.density;
586        friction = src.friction;
587        ingest = src.ingest;
588        assim = src.assim;
589        size = src.size;
590        rot = src.rot;
591        refno = src.refno;
592        vcolor = src.vcolor;
593        vsize = src.vsize;
594        vis_style = src.vis_style;
595        shape = src.shape;
596        scale = src.scale;
597        hollow = src.hollow;
598}
599
600void Part::setOrient(const Orient &_o)
601{
602        o = _o;
603        rot.getAngles(o.x, o.z);
604}
605
606void Part::setRot(const Pt3D &r)
607{
608        rot = r;
609        o = Orient_1;
610        o.rotate(rot);
611}
612
613void Part::setPositionAndRotationFromAxis(const Pt3D &p1, const Pt3D &p2)
614{
615        Pt3D x = p2 - p1;
616        Pt3D dir(x.y, x.z, x.x);
617        p = p1 + x*0.5;
618        rot.getAngles(x, dir);
619}
620
621Param& Part::getStaticParam()
622{
623        static Param p(f0_part_paramtab, 0, "Part");
624        return p;
625}
626
627
628///////////////////////////
629
630Joint::Joint() :PartBase(getDefaultStyle())
631{
632        rot = Pt3D_0;
633        defassign();
634        d.x = JOINT_DELTA_MARKER;
635        d.y = JOINT_DELTA_MARKER;
636        d.z = JOINT_DELTA_MARKER;
637        part1 = 0; part2 = 0;
638        flags = 0;
639        usedelta = 0;
640}
641
642void Joint::operator=(const Joint& src)
643{
644        rot = src.rot;
645        d = src.d;
646        shape = src.shape;
647        stamina = src.stamina;
648        stif = src.stif; rotstif = src.rotstif;
649        vis_style = src.vis_style;
650        vcolor = src.vcolor;
651        part1 = 0; part2 = 0;
652        flags = src.flags;
653        usedelta = src.usedelta;
654        refno = src.refno;
655}
656
657void Joint::attachToParts(Part* p1, Part* p2)
658{
659        part1 = p1;
660        part2 = p2;
661        if (p1 && p2)
662        {
663                o = rot;
664                if (usedelta)
665                {
666                        p1->o.transform(p2->o, o);
667                        //              p2->o.x=p1->o/o.x; p2->o.y=p1->o/o.y; p2->o.z=p1->o/o.z;
668                        p2->p = p2->o.transform(d) + p1->p;
669                }
670        }
671}
672
673void Joint::attachToParts(int p1, int p2)
674{
675        attachToParts((p1 >= 0) ? owner->getPart(p1) : 0, (p2 >= 0) ? owner->getPart(p2) : 0);
676}
677
678void Joint::resetDelta()
679{
680        d = Pt3D(JOINT_DELTA_MARKER, JOINT_DELTA_MARKER, JOINT_DELTA_MARKER);
681}
682
683void Joint::resetDeltaMarkers()
684{
685        if (d.x == JOINT_DELTA_MARKER) d.x = 0;
686        if (d.y == JOINT_DELTA_MARKER) d.y = 0;
687        if (d.z == JOINT_DELTA_MARKER) d.z = 0;
688}
689
690void Joint::useDelta(bool use)
691{
692        usedelta = use;
693}
694
695bool Joint::isDelta()
696{
697        return usedelta;
698}
699
700Param& Joint::getStaticParam()
701{
702        static Param p(f0_joint_paramtab, 0, "Joint");
703        return p;
704}
705
706/////////////////////////////////////////////////////////////////
707
708#include F0_CLASSES_FILE
709
710////////////////////////////////////////
711
712ParamEntry Neuro::emptyParamTab[] =
713{
714        { "Undefined Neuro", 1, 0, "?", },
715        { 0, 0, 0, },
716};
717
718Param Part::extraProperties()
719{
720        return Param(f0_part_xtra_paramtab, this);
721}
722
723Param Joint::extraProperties()
724{
725        return Param(f0_joint_xtra_paramtab, this);
726}
727
728Param Neuro::extraProperties()
729{
730        return Param(f0_neuro_xtra_paramtab, this);
731}
732
733Param Part::properties()
734{
735        return Param(f0_part_paramtab, this);
736}
737
738Param Joint::properties()
739{
740        return Param(usedelta ? f0_joint_paramtab : f0_nodeltajoint_paramtab, this);
741}
742
743Param Neuro::properties()
744{
745        return Param(f0_neuro_paramtab, this);
746}
747
748class NeuroExtParamTab : public ParamTab
749{
750public:
751        NeuroExtParamTab() :ParamTab(f0_neuro_paramtab)
752        {
753#define FIELDSTRUCT NeuroExt
754                ParamEntry entry = { "class", 2, 0, "neuro class", "s", GETSET(neuroclass) };
755#undef FIELDSTRUCT
756                add(&entry);
757
758#define FIELDSTRUCT Neuro
759                ParamEntry entry2 = { "state", 2, 0, "state", "f", FIELD(state) };
760#undef FIELDSTRUCT
761                add(&entry2);
762        }
763};
764
765Param& Neuro::getStaticParam()
766{
767        static Param p(f0_neuro_paramtab, 0, "NeuroDef");
768        return p;
769}
770
771////////////////////////
772
773NeuroConn::NeuroConn()
774{
775        defassign();
776}
777
778//////////////////////////////////////
779
780ParamEntry *NeuroExt::getParamTab()
781{
782        static NeuroExtParamTab tab;
783        return tab.getParamTab();
784}
785
786void NeuroExt::get_neuroclass(PARAMGETARGS)
787{
788        ret->setString(getClassName());
789}
790
791int NeuroExt::set_neuroclass(PARAMSETARGS)
792{
793        setClassName(arg->getString()); return PSET_CHANGED;
794}
Note: See TracBrowser for help on using the repository browser.