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

Last change on this file since 906 was 899, checked in by Maciej Komosinski, 5 years ago

Code formatting

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