source: cpp/gdk/modelparts.cpp @ 69

Last change on this file since 69 was 69, checked in by sz, 13 years ago

removed unnecessary files. all GDK samples can be built again (including neurotest). TODO: add #define GDK_WITHOUT_FRAMS to all VS projects! Note: read Makefile before syncing frams<->GDK!

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