source: cpp/gdk/modelparts.cpp @ 5

Last change on this file since 5 was 5, checked in by sz, 15 years ago

added the GDK (Genotype Development Kit)

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