source: cpp/gdk/modelparts.cpp @ 104

Last change on this file since 104 was 104, checked in by sz, 11 years ago

introducing object de/serialization - see serialtest.cpp
the core GDK classes can be now used in multiple threads (ifdef MULTITHREADED)

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