source: cpp/gdk/modelparts.cpp @ 64

Last change on this file since 64 was 64, checked in by Maciej Komosinski, 13 years ago

a lot of minor fixes

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