source: cpp/gdk/model.cpp @ 82

Last change on this file since 82 was 82, checked in by Maciej Komosinski, 11 years ago

compiles under more platforms and OSes

  • Property svn:eol-style set to native
File size: 27.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 "nonstd_math.h"
6#include "model.h"
7#include "framsg.h"
8#include "multimap.h"
9#include "errmanager.h"
10
11#define FIELDSTRUCT Model
12ParamEntry f0_model_paramtab[]=
13{
14{"Model",1,2,"m",},
15{"se",2,0,"startenergy","f",FIELD(startenergy),},
16{"Vstyle",2,0,"vis_style","s",FIELD(vis_style),},
17{0,0,0,},
18};
19#undef FIELDSTRUCT
20
21Model::Model()
22{
23autobuildmaps=0;
24init();
25}
26
27void Model::init()
28{
29partmappingchanged=0;
30buildstatus=empty;
31modelfromgenotype=0;
32startenergy=1.0;
33checklevel=1;
34#ifdef MODEL_V1_COMPATIBLE
35oldneurocount=-1; // == unknown
36oldconnections=0;
37#endif
38map=0;
39f0map=0;
40f0genoknown=1;
41}
42
43void Model::moveElementsFrom(Model &source)
44{
45int i;
46open();
47for (i=0;i<source.getPartCount();i++)
48        addPart(source.getPart(i));
49for (i=0;i<source.getJointCount();i++)
50        addJoint(source.getJoint(i));
51for (i=0;i<source.getNeuroCount();i++)
52        addNeuro(source.getNeuro(i));
53source.parts.clear(); source.joints.clear(); source.neurons.clear();
54source.clear();
55}
56
57void Model::internalCopy(const Model &mod)
58{
59geno=mod.geno;
60f0genoknown=0;
61startenergy=mod.startenergy;
62if (mod.getStatus()==valid)
63        {
64        modelfromgenotype=mod.modelfromgenotype;
65        {for (int i=0;i<mod.getPartCount();i++)
66                addPart(new Part(*mod.getPart(i)));}
67        {for (int i=0;i<mod.getJointCount();i++)
68                {
69                Joint *oldj=mod.getJoint(i);
70                Joint *j=new Joint(*oldj);
71                addJoint(j);
72                j->attachToParts(oldj->part1->refno,oldj->part2->refno);
73                }}
74        {for (int i=0;i<mod.getNeuroCount();i++)
75                {
76                Neuro *oldn=mod.getNeuro(i);
77                Neuro *n=new Neuro(*oldn);
78                addNeuro(n);
79                if (oldn->part_refno>=0) n->attachToPart(oldn->part_refno);
80                else n->attachToJoint(oldn->joint_refno);
81                }}
82        for (int i=0;i<mod.getNeuroCount();i++)
83                {
84                Neuro *oldn=mod.getNeuro(i);
85                Neuro *n=getNeuro(i);
86                for (int ni=0;ni < oldn->getInputCount();ni++)
87                        {
88                        float w;
89                        Neuro *oldinput=oldn->getInput(ni,w);
90                        SString info=n->getInputInfo(ni);
91                        n->addInput(getNeuro(oldinput->refno),w,&info);
92                        }
93                }
94        }
95}
96
97
98Model::Model(const Geno &src,int buildmaps)
99        :autobuildmaps(buildmaps)
100{init(src);}
101
102void Model::operator=(const Model &mod)
103{
104clear();
105open();
106internalCopy(mod);
107buildstatus=mod.buildstatus;
108}
109
110Model::Model(const Model &mod,int buildmaps)
111        :autobuildmaps(buildmaps)
112{
113init();
114open();
115internalCopy(mod);
116buildstatus=mod.buildstatus;
117}
118
119void Model::init(const Geno &src)
120{
121init();
122modelfromgenotype=1;
123geno=src;
124build();
125}
126
127void Model::resetAllDelta()
128{
129for (int i=0;i<getJointCount();i++)
130        getJoint(i)->resetDelta();
131}
132
133void Model::useAllDelta(bool yesno)
134{
135for (int i=0;i<getJointCount();i++)
136        getJoint(i)->useDelta(yesno);
137}
138
139Model::~Model()
140{
141delmodel_list.action((long)this);
142clear();
143}
144
145void Model::clear()
146{
147Part *p;
148for (parts.start();p=(Part*)parts();) delete p;
149Joint* j;
150for (joints.start();j=(Joint*)joints();) delete j;
151Neuro *n;
152for (neurons.start();n=(Neuro*)neurons();) delete n;
153parts.clear(); joints.clear(); neurons.clear();
154delMap();
155delF0Map();
156init();
157geno=Geno();
158f0geno=Geno();
159}
160
161Part *Model::addPart(Part *p)
162{
163p->owner=this;
164p->refno=parts.size();
165parts+=p;
166return p;
167}
168
169Joint *Model::addJoint(Joint *j)
170{
171j->owner=this;
172j->refno=joints.size();
173joints+=j;
174return j;
175}
176
177Neuro *Model::addNeuro(Neuro *n)
178{
179n->owner=this;
180n->refno=neurons.size();
181neurons+=n;
182return n;
183}
184
185void Model::removeNeuros(SList &nlist)
186{
187FOREACH(Neuro*,nu,nlist)
188        {
189        int i=findNeuro(nu);
190        if (i>=0) removeNeuro(i);
191        }
192}
193
194void Model::removePart(int partindex,int removeattachedjoints,int removeattachedneurons)
195{
196Part *p=getPart(partindex);
197if (removeattachedjoints)
198        {
199        SList jlist;
200        findJoints(jlist,p);
201        FOREACH(Joint*,j,jlist)
202                {
203                int i=findJoint(j);
204                if (i>=0) removeJoint(i,removeattachedneurons);
205                }
206        }
207if (removeattachedneurons)
208        {
209        SList nlist;
210        findNeuros(nlist,0,p);
211        removeNeuros(nlist);
212        }
213parts-=partindex;
214delete p;
215}
216
217void Model::removeJoint(int jointindex,int removeattachedneurons)
218{
219Joint *j=getJoint(jointindex);
220if (removeattachedneurons)
221        {
222        SList nlist;
223        findNeuros(nlist,0,0,j);
224        removeNeuros(nlist);
225        }
226joints-=jointindex;
227delete j;
228}
229
230void Model::removeNeuro(int neuroindex,bool removereferences)
231{
232Neuro* thisN=getNeuro(neuroindex);
233
234if (removereferences)
235        {
236        Neuro* n;
237// remove all references to thisN
238        for (int i=0;n=(Neuro*)neurons(i);i++)
239                {
240                Neuro *inp;
241                for (int j=0;inp=n->getInput(j);j++)
242                        if (inp==thisN)
243                                {
244                                n->removeInput(j);
245                                j--;
246                                }
247                }
248        }
249
250neurons-=neuroindex;
251delete thisN;
252}
253
254MultiMap& Model::getMap()
255{
256if (!map) map=new MultiMap();
257return *map;
258}
259
260void Model::delMap()
261{
262if (map) {delete map; map=0;}
263}
264void Model::delF0Map()
265{
266if (f0map) {delete f0map; f0map=0;}
267}
268
269void Model::makeGenToGenMap(MultiMap& result,const MultiMap& gen1tomodel,const MultiMap& gen2tomodel)
270{
271result.clear();
272MultiMap m;
273m.addReversed(gen2tomodel);
274result.addCombined(gen1tomodel,m);
275}
276
277void Model::getCurrentToF0Map(MultiMap& result)
278{
279result.clear();
280if (!map) return;
281const MultiMap& f0m=getF0Map();
282makeGenToGenMap(result,*map,f0m);
283}
284
285void Model::rebuild(int buildm)
286{
287autobuildmaps=buildm;
288clear();
289build();
290}
291
292void Model::initMap()
293{
294if (!map) map=new MultiMap();
295else map->clear();
296}
297
298void Model::initF0Map()
299{
300if (!f0map) f0map=new MultiMap();
301else f0map->clear();
302}
303
304void Model::build()
305{
306f0errorposition=-1;
307f0warnposition=-1;
308MultiMap *convmap=autobuildmaps?new MultiMap():0;
309f0geno=(geno.getFormat()=='0')? geno : geno.getConverted('0',convmap);
310f0genoknown=1;
311if (f0geno.isInvalid())
312        {
313        buildstatus=invalid;
314        if (convmap) delete convmap;
315        return;
316        }
317SString f0txt=f0geno.getGene();
318buildstatus=building; // was: open();
319if (autobuildmaps)
320        {
321        partmappingchanged=0;
322        initMap();
323        initF0Map();
324        }
325int pos=0,lnum=1,lastpos=0;
326SString line;
327MultiRange frommap;
328ErrorHandler err(ErrorHandler::DontBlock);
329for (;f0txt.getNextToken(pos,line,'\n');lnum++)
330        {
331        if (autobuildmaps)
332                {
333                frommap.clear();
334                frommap.add(lastpos,pos-1);
335                }
336        err.reset();
337        if (singleStepBuild(line,autobuildmaps?(&frommap):0)==-1)
338                {
339                buildstatus=invalid;
340                FMprintf("Model","build",FMLV_ERROR,
341                         geno.getName().len()?"illegal f0 code at line %d (%s)":"illegal f0 code at line %d",
342                         lnum,(const char*)geno.getName());
343                f0errorposition=lastpos;
344                if (convmap) delete convmap;
345                return;
346                }
347        if (err.getWarningCount())
348                {if (f0warnposition<0) f0warnposition=lastpos;}
349        lastpos=pos;
350        }
351err.disable();
352close();
353if (convmap)
354        {
355        *f0map=*map;
356        if (geno.getFormat()!='0')
357                {
358                MultiMap tmp;
359                tmp.addCombined(*convmap,getMap());
360                *map=tmp;
361                }
362        delete convmap;
363        }
364}
365
366const MultiMap& Model::getF0Map()
367{
368if (!f0map)
369        {
370        f0map=new MultiMap();
371        makeGeno(f0geno,f0map);
372        f0genoknown=1;
373        }
374return *f0map;
375}
376
377Geno Model::rawGeno()
378{
379Geno tmpgen;
380makeGeno(tmpgen);
381return tmpgen;
382}
383
384void Model::makeGeno(Geno &g,MultiMap *map,bool handle_defaults)
385{
386if ((buildstatus!=valid)&&(buildstatus!=building))
387        {
388        g=Geno(0,0,0,"invalid model");
389        return;
390        }
391
392SString gen;
393
394static Param modelparam(f0_model_paramtab);
395static Param partparam(f0_part_paramtab);
396static Param jointparam(f0_joint_paramtab);
397static Param neuroparam(f0_neuro_paramtab);
398static Param connparam(f0_neuroconn_paramtab);
399
400static Part defaultpart;
401static Joint defaultjoint;
402static Neuro defaultneuro;
403static Model defaultmodel;
404static NeuroConn defaultconn;
405//static NeuroItem defaultneuroitem;
406
407Part *p;
408Joint *j;
409Neuro *n;
410int i;
411int len;
412int a,b;
413//NeuroItem *ni;
414
415if (startenergy!=defaultmodel.startenergy)
416        {
417        modelparam.select(this);
418        gen+="m:";
419        modelparam.save2(gen,handle_defaults ? &defaultmodel : NULL,true,!handle_defaults);
420        }
421
422for (i=0;p=(Part*)parts(i);i++)
423        {
424        partparam.select(p);
425        len=gen.len();
426        gen+="p:";
427        partparam.save2(gen,handle_defaults ? &defaultpart : NULL,true,!handle_defaults);
428        if (map)
429                map->add(len,gen.len()-1,partToMap(i));
430        }
431for (i=0;j=(Joint*)joints(i);i++)
432        {
433        jointparam.select(j);
434        len=gen.len();
435        jointparam.setParamTab(j->usedelta?f0_joint_paramtab:f0_nodeltajoint_paramtab);
436        gen+="j:";
437        jointparam.save2(gen,handle_defaults ? &defaultjoint : NULL,true,!handle_defaults);
438        if (map)
439                map->add(len,gen.len()-1,jointToMap(i));
440        }
441for (i=0;n=(Neuro*)neurons(i);i++)
442        {
443        neuroparam.select(n);
444        len=gen.len();
445        gen+="n:";
446        neuroparam.save2(gen,handle_defaults ? &defaultneuro : NULL,true,!handle_defaults);
447        if (map)
448                map->add(len,gen.len()-1,neuroToMap(i));
449        }
450for (a=0;a<neurons.size();a++)
451        { // inputs
452        n=(Neuro*)neurons(a);
453//      if ((n->getInputCount()==1)&&(n->getInput(0).refno <= n->refno))
454//              continue; // already done with Neuro::conn_refno
455
456        for (b=0;b<n->getInputCount();b++)
457                {
458                float w;
459                NeuroConn nc;
460                Neuro* n2=n->getInput(b,w);
461//              if (((n2.parentcount==1)&&(n2.parent)&&(n2.parent->refno < n2.refno)) ^
462//                  (n2.neuro_refno>=0))
463//                      printf("!!!! bad Neuro::neuro_refno ?!\n");
464
465//              if ((n2.parentcount==1)&&(n2.parent)&&(n2.parent->refno < n2.refno))
466//              if (n2.neuro_refno>=0)
467//                      continue; // already done with Neuro::neuro_refno
468
469                nc.n1_refno=n->refno; nc.n2_refno=n2->refno;
470                nc.weight=w;
471                SString **s=n->inputInfo(b);
472                if ((s)&&(*s))
473                nc.info=**s;
474                connparam.select(&nc);
475                len=gen.len();
476                gen+="c:";
477                connparam.save2(gen,handle_defaults ? &defaultconn : NULL,true,!handle_defaults);
478                if (map)
479                        map->add(len,gen.len()-1,neuroToMap(n->refno));
480                }
481        }
482g=Geno(gen,'0');
483}
484
485//////////////
486
487void Model::open()
488{
489if (buildstatus==building) return;
490buildstatus=building;
491modelfromgenotype=0;
492partmappingchanged=0;
493f0genoknown=0;
494delMap();
495}
496
497void Model::checkpoint()
498{}
499
500void Model::setGeno(const Geno& newgeno)
501{
502geno=newgeno;
503}
504
505void Model::clearMap()
506{
507Part *p; Joint *j; Neuro *n;
508int i;
509delMap();
510delF0Map();
511for (i=0;p=(Part*)parts(i);i++)
512        p->clearMapping();
513for (i=0;j=(Joint*)joints(i);i++)
514        j->clearMapping();
515for (i=0;n=(Neuro*)neurons(i);i++)
516        n->clearMapping();
517}
518
519int Model::close()
520{
521if (buildstatus!=building)
522        FMprintf("Model","close",FMLV_WARN,"unexpected close() - no open()");
523if (internalcheck(1)>0)
524        {
525        buildstatus=valid;
526
527        if (partmappingchanged)
528                {
529                getMap();
530                Part *p; Joint *j; Neuro *n;
531                int i;
532                for (i=0;p=(Part*)parts(i);i++)
533                        if (p->getMapping())
534                                map->add(*p->getMapping(),partToMap(i));
535                for (i=0;j=(Joint*)joints(i);i++)
536                        if (j->getMapping())
537                                map->add(*j->getMapping(),jointToMap(i));
538                for (i=0;n=(Neuro*)neurons(i);i++)
539                        if (n->getMapping())
540                                map->add(*n->getMapping(),neuroToMap(i));
541                }
542        }
543else
544        buildstatus=invalid;
545
546return (buildstatus==valid);
547}
548
549int Model::validate()
550{
551return internalcheck(0);
552}
553
554Pt3D Model::whereDelta(const Part& start,const Pt3D& rot, const Pt3D& delta)
555{
556Orient roto;
557roto=rot;
558Orient o;
559roto.transform(o,start.o);
560//o.x=start.o/roto.x;
561//o.y=start.o/roto.y;
562//o.z=start.o/roto.z;
563return o.transform(delta)+start.p;
564}
565
566int Model::singleStepBuild(const SString &line,const MultiRange* srcrange)
567{
568int pos=0; const char*t=(const char*)line;
569for (;*t;t++,pos++)
570        if (!strchr(" \r\t",*t)) break;
571if (*t=='#') return 0;
572if (!*t) return 0;
573if (!strncmp(t,"p:",2))
574        {
575        static Param partparam(f0_part_paramtab);
576        Part *p=new Part();
577        partparam.select(p);
578        pos+=2;
579        partparam.load2(line,pos);
580        p->o.rotate(p->rot);
581        parts+=p;
582        p->owner=this;
583        if (srcrange) p->setMapping(*srcrange);
584        return getPartCount()-1;
585        }
586if (!strncmp(t,"m:",2))
587        {
588        static Param modelparam(f0_model_paramtab);
589        modelparam.select(this);
590        pos+=2;
591        modelparam.load2(line,pos);
592        return 0;
593        }
594else if (!strncmp(t,"j:",2))
595        {
596        static Param jointparam(f0_joint_paramtab);
597        Joint *j=new Joint();
598        jointparam.select(j);
599        pos+=2;
600        j->owner=this;
601        jointparam.load2(line,pos);
602        if ((j->p1_refno>=0)&&(j->p1_refno<getPartCount())&&
603           (j->p2_refno>=0)&&(j->p2_refno<getPartCount()))
604                {
605                addJoint(j);
606                if (j->d.x < (JOINT_DELTA_MARKER-1.0))
607                        j->useDelta(1);
608                j->attachToParts(j->p1_refno,j->p2_refno);
609                if (srcrange) j->setMapping(*srcrange);
610                return j->refno;
611                }
612        else
613                {
614                delete j;
615                FMprintf("Model","build",FMLV_ERROR,
616                         "invalid part reference for joint #%d",getJointCount()-1);
617                return -1;
618                }
619        }
620else if (!strncmp(t,"n:",2)) // neuro (or the old neuro object as the special case)
621        {
622        static Param neuroparam(f0_neuro_paramtab);
623        Neuro *nu=new Neuro();
624        neuroparam.select(nu);
625        pos+=2;
626        neuroparam.load2(line,pos);
627#ifdef MODEL_V1_COMPATIBLE
628        if (nu->neuro_refno>=0) // parent specified...
629                {
630                if (nu->neuro_refno >= getNeuroCount()) // and it's illegal
631                        {
632                        delete nu;
633                        return -1;
634                        }
635                Neuro *parentNU=getNeuro(nu->neuro_refno);
636                parentNU->addInput(nu,nu->weight);
637                // default class for parented units: n-n link
638                //if (nu->moredata.len()==0) nu->moredata="-";
639                }
640        else
641#endif
642                {
643                // default class for unparented units: standard neuron
644                if (nu->getClassName().len()==0) nu->setClassName("N");
645                }
646/*
647        if (nu->conn_refno>=0) // input specified...
648                {
649                if (nu->conn_refno >= getNeuroCount()) // and it's illegal
650                        {
651                        delete nu;
652                        return -1;
653                        }
654                Neuro *inputNU=getNeuro(nu->conn_refno);
655                nu->addInput(inputNU,nu->weight);
656                }
657*/
658#ifdef MODEL_V1_COMPATIBLE
659        nu->weight=1.0;
660#endif
661        nu->owner=this;
662        // attach to part/joint
663        if (nu->part_refno>=0)
664                nu->attachToPart(nu->part_refno);
665        if (nu->joint_refno>=0)
666                nu->attachToJoint(nu->joint_refno);
667        if (srcrange) nu->setMapping(*srcrange);
668        // todo: check part/joint ref#
669#ifdef MODEL_V1_COMPATIBLE
670        if (hasOldNeuroLayout())
671                {
672                int count=old_getNeuroCount();
673                neurons.insert(count,nu);
674                oldneurocount=count+1;
675                return oldneurocount-1;
676                }
677        else
678#endif
679                {
680                neurons+=nu;
681                return neurons.size()-1;
682                }
683        }
684else if (!strncmp(t,"c:",2)) // add input
685        {
686        static Param ncparam(f0_neuroconn_paramtab);
687        NeuroConn c;
688        ncparam.select(&c);
689        pos+=2;
690        ncparam.load2(line,pos);
691        if ((c.n1_refno>=0)&&(c.n1_refno<getNeuroCount())&&(c.n2_refno>=0)&&(c.n2_refno<getNeuroCount()))
692                {
693                Neuro *na=getNeuro(c.n1_refno);
694                Neuro *nb=getNeuro(c.n2_refno);
695                na->addInput(nb,c.weight,&c.info);
696                if (srcrange)
697                        na->addMapping(*srcrange);
698                return 0;
699                }
700        FMprintf("Model","build",FMLV_ERROR,
701                 "invalid neuron connection #%d <- #%d",c.n1_refno,c.n2_refno);
702        return -1;
703        }
704#ifdef MODEL_V1_COMPATIBLE
705else if (!strncmp(t,"ni:",3)) // old neuroitem
706        {
707        // we always use old layout for "ni:"
708        static Param neuroitemparam(f0_neuroitem_paramtab);
709        Neuro *nu=new Neuro();
710        neuroitemparam.select(nu);
711        pos+=3;
712        neuroitemparam.load2(line,pos);
713        // illegal parent?
714        if ((nu->neuro_refno<0)||(nu->neuro_refno>=old_getNeuroCount()))
715                {
716                delete nu;
717                return -1;
718                }
719        Neuro *parentN=getNeuro(nu->neuro_refno);
720        // copy part/joint refno from parent, if possible
721        if ((nu->part_refno<0)&&(parentN->part_refno>=0))
722                nu->part_refno=parentN->part_refno;
723        if ((nu->joint_refno<0)&&(parentN->joint_refno>=0))
724                nu->joint_refno=parentN->joint_refno;
725        nu->owner=this;
726        // attach to part/joint
727        if (nu->part_refno>=0)
728                nu->attachToPart(nu->part_refno);
729        if (nu->joint_refno>=0)
730                nu->attachToJoint(nu->joint_refno);
731        if (srcrange)
732                nu->setMapping(*srcrange);
733        // special case: old muscles
734        // PARENT neuron will be set up to be the CHILD of the current one (!)
735        if (nu->isOldEffector())
736                {
737                nu->neuro_refno=parentN->refno;
738                neurons+=nu;
739                nu->owner=this;
740                nu->addInput(parentN,nu->weight); // (!)
741                nu->weight=1.0;
742                parentN->invalidateOldItems();
743                return 0; // !!! -> ...getItemCount()-1;
744                }
745        parentN->addInput(nu,nu->weight);
746        neurons+=nu;
747        parentN->invalidateOldItems();
748        if (nu->getClassName().len()==0)
749                {
750                nu->setClassName("-");
751                // for compatibility, "ni" can define a n-n connection
752                // referring to non-existent neuron (which will be hopefully defined later)
753                // internal check will add the proper input to this unit
754                // if conn_refno >=0 and input count==0
755                oldconnections=1;
756                if (srcrange)
757                        parentN->addMapping(*srcrange);
758                }
759        else
760                nu->weight=1.0;
761        return 0; // !!! -> ...getItemCount()-1;
762        }
763#endif
764else return -1;
765}
766
767#ifdef MODEL_V1_COMPATIBLE
768int Model::addOldConnectionsInputs()
769{
770if (!oldconnections) return 1;
771Neuro* n;
772for (int i=0;i<neurons.size();i++)
773        {
774        n=(Neuro*)neurons(i);
775        if (n->conn_refno>=0)
776                if (n->isNNConnection())
777                        if (n->conn_refno < old_getNeuroCount())
778                                { // good reference
779                                Neuro* parent=n->parent; // nn connection has exactly one parent
780                                int inp=parent->findInput(n);
781                                Neuro* target=getNeuro(n->conn_refno);
782                                parent->setInput(inp,target,n->weight);
783                                removeNeuro(i,0); // no need to remove references
784                                i--;
785                                }
786                        else
787                                {
788                                FMprintf("Model","internalCheck",FMLV_ERROR,
789                                         "illegal N-N connection #%d (reference to #%d) (%s)",
790                                         i,n->conn_refno,(const char*)geno.getName());
791                                return 0;
792                                }
793        }
794oldconnections=0;
795return 1;
796}
797#endif
798
799/////////////
800
801/** change the sequence of neuro units
802    and fix references in "-" objects (n-n connections)  */
803void Model::moveNeuro(int oldpos,int newpos)
804{
805if (oldpos==newpos) return; // nop!
806Neuro *n=getNeuro(oldpos);
807neurons-=oldpos;
808neurons.insert(newpos,n);
809 // conn_refno could be broken -> fix it
810#ifdef MODEL_V1_COMPATIBLE
811for (int i=0;i<neurons.size();i++)
812        {
813        Neuro *n2=getNeuro(i);
814        if (n2->isNNConnection())
815                if (n2->conn_refno == oldpos) n2->conn_refno=newpos;
816                else
817                { if (n2->conn_refno > oldpos) n2->conn_refno--;
818                  if (n2->conn_refno >= newpos) n2->conn_refno++; }
819        }
820invalidateOldNeuroCount();
821#endif
822}
823
824#ifdef MODEL_V1_COMPATIBLE
825/** move all old neurons (class "N") to the front of the neurons list.
826    @return number of old neurons
827  */
828int Model::reorderToOldLayout()
829{
830Neuro *n;
831int neurocount=0;
832for (int i=0;i<neurons.size();i++)
833        {
834        n=(Neuro*)neurons(i);
835        if (n->isOldNeuron())
836                {
837                moveNeuro(i,neurocount);
838                neurocount++;
839                i=neurocount-1;
840                }
841        }
842return neurocount;
843}
844#endif
845////////////
846
847void Model::updateNeuroRefno()
848{
849for (int i=0;i<neurons.size();i++)
850        {
851        Neuro* n=(Neuro*)neurons(i);
852        n->refno=i;
853        }
854}
855
856#define VALIDMINMAX(var,template,field) \
857if (var -> field < getMin ## template () . field) \
858        { var->field= getMin ## template () . field; \
859        FMprintf("Model","internalCheck",FMLV_WARN,# field " too small in " # template "#%d (adjusted)",i);} \
860else if (var -> field > getMax ## template () . field) \
861        { var->field= getMax ## template ()  . field; \
862        FMprintf("Model","internalCheck",FMLV_WARN,# field " too big in " # template "#%d (adjusted)",i);}
863
864#define LINKFLAG 0x8000000
865
866void Model::updateRefno()
867{
868int i;
869for (i=0;i<getPartCount();i++) getPart(i)->refno=i;
870for (i=0;i<getJointCount();i++) getJoint(i)->refno=i;
871for (i=0;i<getNeuroCount();i++) getNeuro(i)->refno=i;
872}
873
874int Model::internalcheck(int final)
875{
876Part *p;
877Joint *j;
878Neuro *n;
879int i,k;
880int ret=1;
881if ((parts.size()==0)&&(neurons.size()==0)) return 0;
882if (parts.size()==0)
883        size=Pt3D_0;
884else
885        {
886Pt3D bbmin=((Part*)parts(0))->p, bbmax=bbmin;
887for (i=0;i<parts.size();i++)
888        {
889        p=(Part*)parts(i);
890        p->owner=this;
891        p->refno=i;
892        if (checklevel>0)
893                p->mass=0.0;
894//      VALIDMINMAX(p,part,mass);
895        VALIDMINMAX(p,Part,size);
896        VALIDMINMAX(p,Part,density);
897        VALIDMINMAX(p,Part,friction);
898        VALIDMINMAX(p,Part,ingest);
899        VALIDMINMAX(p,Part,assim);
900        p->flags&=~LINKFLAG; // for delta joint cycle detection
901        if (p->p.x-p->size < bbmin.x) bbmin.x=p->p.x-p->size;
902        if (p->p.y-p->size < bbmin.y) bbmin.y=p->p.y-p->size;
903        if (p->p.z-p->size < bbmin.z) bbmin.z=p->p.z-p->size;
904        if (p->p.x+p->size > bbmax.x) bbmax.x=p->p.x+p->size;
905        if (p->p.y+p->size > bbmax.y) bbmax.y=p->p.y+p->size;
906        if (p->p.z+p->size > bbmax.z) bbmax.z=p->p.z+p->size;
907        }
908size=bbmax-bbmin;
909for (i=0;i<joints.size();i++)
910        {
911        j=(Joint*)joints(i);
912        VALIDMINMAX(j,Joint,stamina);
913        VALIDMINMAX(j,Joint,stif);
914        VALIDMINMAX(j,Joint,rotstif);
915        j->refno=i;
916        j->owner=this;
917        if (j->part1 && j->part2 && (j->part1 != j->part2))
918                {
919                j->p1_refno=j->part1->refno;
920                j->p2_refno=j->part2->refno;
921                if (checklevel>0)
922                        {
923                        j->part1->mass+=1.0;
924                        j->part2->mass+=1.0;
925                        }
926                if ((j->usedelta)&&(j->d.x < (JOINT_DELTA_MARKER-1.0)))
927                        { // delta positioning -> calc. orient.
928                        if (j->part2->flags & LINKFLAG)
929                                {
930                                ret=0;
931                                FMprintf("Model","internalCheck",FMLV_ERROR,
932                                         "delta joint cycle detected at joint#%d (%s)",
933                                         i,(const char*)geno.getName());
934                                }
935                        j->o=j->rot;
936                        j->part1->o.transform(j->part2->o,j->o);
937//                      j->part2->o.x=j->part1->o/j->o.x;
938//                      j->part2->o.y=j->part1->o/j->o.y;
939//                      j->part2->o.z=j->part1->o/j->o.z;
940                        j->part2->p=j->part2->o.transform(j->d)+j->part1->p;
941                        j->part2->flags|=LINKFLAG; j->part1->flags|=LINKFLAG; // for delta joint cycle detection
942                        }
943                else
944                        { // abs.positioning -> calc. delta
945                        if (final)
946                        {
947                        // calc orient delta
948//                      Orient tmpo(j->part2->o);
949//                      tmpo*=j->part1->o;
950                        Orient tmpo;
951                        j->part1->o.revTransform(tmpo,j->part2->o);
952                        tmpo.getAngles(j->rot);
953                        j->o=j->rot;
954                        // calc position delta
955                        Pt3D tmpp(j->part2->p);
956                        tmpp-=j->part1->p;
957                        j->d=j->part2->o.revTransform(tmpp);
958                        }
959                        }
960                if (final)
961                        {
962                        if (j->d()>getMaxJoint().d.x)
963                        {
964                        ret=0;
965                        FMprintf("Model","internalCheck",FMLV_ERROR,"delta too big in joint #%d (%s)",
966                                 i,(const char*)geno.getName());
967                        }
968                        else if (j->d()<getMinJoint().d.x)
969                        {
970                        ret=0;
971                        FMprintf("Model","internalCheck",FMLV_ERROR,"delta too small in joint #%d (%s)",
972                                 i,(const char*)geno.getName());
973                        }
974                        }
975                }
976        else
977                {
978                FMprintf("Model","internalCheck",FMLV_ERROR,"illegal part references in joint #%d (%s)",
979                         i,(const char*)geno.getName());
980                ret=0;
981                }
982        }
983        }
984#ifdef MODEL_V1_COMPATIBLE
985if (!addOldConnectionsInputs())
986        return 0;
987#endif
988
989updateNeuroRefno(); // valid refno is important for n-n connections check (later)
990
991for (i=0;i<neurons.size();i++)
992        {
993        n=(Neuro*)neurons(i);
994        VALIDMINMAX(n,Neuro,state);
995#ifdef MODEL_V1_COMPATIBLE
996        VALIDMINMAX(n,Neuro,inertia);
997        VALIDMINMAX(n,Neuro,force);
998        VALIDMINMAX(n,Neuro,sigmo);
999        n->conn_refno=-1;
1000        n->weight=1.0;
1001        n->neuro_refno=-1;
1002#endif
1003        n->part_refno=(n->part)?n->part->refno:-1;
1004        n->joint_refno=(n->joint)?n->joint->refno:-1;
1005        }
1006
1007if (parts.size()&&(checklevel>0))
1008        {
1009        for (i=0;i<parts.size();i++)
1010                {
1011                p=(Part*)parts(i);
1012                if (p->mass<=0.001)
1013                        p->mass=1.0;
1014                p->flags&=~LINKFLAG;
1015                }
1016        getPart(0)->flags|=LINKFLAG;
1017        int change=1;
1018        while(change)
1019                {
1020                change=0;
1021                for (i=0;i<joints.size();i++)
1022                        {
1023                        j=(Joint*)joints(i);
1024                        if (j->part1->flags&LINKFLAG)
1025                                {
1026                                if (!(j->part2->flags&LINKFLAG))
1027                                        {
1028                                        change=1;
1029                                        j->part2->flags|=LINKFLAG;
1030                                        }
1031                                }
1032                        else
1033                        if (j->part2->flags&LINKFLAG)
1034                                {
1035                                if (!(j->part1->flags&LINKFLAG))
1036                                        {
1037                                        change=1;
1038                                        j->part1->flags|=LINKFLAG;
1039                                        }
1040                                }
1041                        }
1042                }
1043        for (i=0;i<parts.size();i++)
1044                {
1045                p=(Part*)parts(i);
1046                if (!(p->flags&LINKFLAG))
1047                        {
1048                        FMprintf("Model","internalCheck",FMLV_ERROR,"not all parts connected (eg.#0-#%d) (%s)",
1049                                 i,(const char*)geno.getName());
1050                        ret=0;
1051                        break;
1052                        }
1053                }
1054        }
1055
1056for (i=0;i<joints.size();i++)
1057        {
1058        j=(Joint*)joints(i);
1059        if (j->p1_refno==j->p2_refno)
1060                {
1061                FMprintf("Model","internalCheck",FMLV_ERROR,"illegal self connection, joint #%d (%s)",
1062                         i,(const char*)geno.getName());
1063                ret=0;
1064                break;
1065                }
1066        for (k=i+1;k<joints.size();k++)
1067                {
1068                Joint* j2=(Joint*)joints(k);
1069                if (((j->p1_refno==j2->p1_refno)&&(j->p2_refno==j2->p2_refno))
1070                    || ((j->p1_refno==j2->p2_refno)&&(j->p2_refno==j2->p1_refno)))
1071                        {
1072                        FMprintf("Model","internalCheck",FMLV_ERROR,"illegal duplicate joints #%d and #%d (%s)",
1073                                 i,k,(const char*)geno.getName());
1074                        ret=0;
1075                        break;
1076                        }
1077                }
1078        }
1079return ret;
1080}
1081
1082/////////////
1083
1084int Model::getErrorPosition(bool includingwarnings)
1085{
1086return includingwarnings?
1087        ((f0errorposition>=0) ? f0errorposition : f0warnposition)
1088        :
1089        f0errorposition;
1090}
1091
1092const Geno& Model::getGeno() const
1093{
1094return geno;
1095}
1096
1097const Geno& Model::getF0Geno()
1098{
1099static Geno invalidgeno("",'0',"","invalid");
1100if (buildstatus==building)
1101        FMprintf("Model","getGeno",FMLV_WARN,"model was not completed - missing close()");
1102if (buildstatus!=valid)
1103        return invalidgeno;
1104if (!f0genoknown)
1105        {
1106        if (autobuildmaps)
1107                {
1108                initF0Map();
1109                makeGeno(f0geno,f0map);
1110                }
1111        else
1112                {
1113                delF0Map();
1114                makeGeno(f0geno);
1115                }
1116        f0genoknown=1;
1117        }
1118return f0geno;
1119}
1120
1121int Model::getPartCount() const
1122{
1123return parts.size();
1124}
1125
1126Part* Model::getPart(int i) const
1127{
1128return ((Part*)parts(i));
1129}
1130
1131int Model::getJointCount() const
1132{
1133return joints.size();
1134}
1135
1136Joint* Model::getJoint(int i) const
1137{
1138return ((Joint*)joints(i));
1139}
1140
1141int Model::findJoints(SList& result,const Part* part)
1142{
1143Joint *j;
1144int n0=result.size();
1145if (part)
1146   for(int i=0;j=(Joint*)joints(i);i++)
1147     if ((j->part1 == part) || (j->part2 == part)) result+=(void*)j;
1148return result.size()-n0;
1149}
1150
1151int Model::findNeuro(Neuro* n)
1152{return neurons.find(n);}
1153
1154int Model::findPart(Part* p)
1155{return parts.find(p);}
1156
1157int Model::findJoint(Joint* j)
1158{return joints.find(j);}
1159
1160int Model::findJoint(Part *p1, Part *p2)
1161{
1162Joint* j;
1163for(int i=0;j=getJoint(i);i++)
1164        if ((j->part1==p1)&&(j->part2==p2)) return i;
1165return -1;
1166}
1167
1168
1169////////////////////
1170
1171#ifdef MODEL_V1_COMPATIBLE
1172void Model::calcOldNeuroCount()
1173{
1174if (oldneurocount>=0) return;
1175oldneurocount=reorderToOldLayout();
1176}
1177
1178int Model::old_getNeuroCount()
1179{ calcOldNeuroCount();
1180 return oldneurocount;}
1181
1182Neuro* Model::old_getNeuro(int i)
1183{calcOldNeuroCount();
1184return (i<oldneurocount)? (Neuro*)getNeuro(i) : (Neuro*)0;
1185}
1186
1187int Model::old_findNeuro(Neuro* n)
1188{calcOldNeuroCount();
1189return findNeuro(n);}
1190
1191Neuro *Model::old_addNewNeuro()
1192{
1193int count=old_getNeuroCount();
1194Neuro *nu=addNewNeuro();
1195nu->setClassName("N");
1196moveNeuro(nu->refno,oldneurocount);
1197oldneurocount=count+1;
1198return (Neuro*)nu;
1199}
1200#endif
1201
1202///////////////////////
1203
1204int Model::getNeuroCount() const
1205{return neurons.size();}
1206
1207Neuro* Model::getNeuro(int i) const
1208{return (Neuro*)neurons(i);}
1209
1210int Model::getConnectionCount() const
1211{
1212int n=0;
1213for(int i=0;i<getNeuroCount();i++)
1214        n+=getNeuro(i)->getInputCount();
1215return n;
1216}
1217
1218int Model::findNeuros(SList& result,
1219                          const char* classname,const Part* part,const Joint* joint)
1220{
1221Neuro *nu;
1222SString cn(classname);
1223int n0=result.size();
1224for(int i=0;nu=(Neuro*)neurons(i);i++)
1225        {
1226        if (part)
1227                if (nu->part != part) continue;
1228        if (joint)
1229                if (nu->joint != joint) continue;
1230        if (classname)
1231                if (nu->getClassName() != cn) continue;
1232        result+=(void*)nu;
1233        }
1234return result.size()-n0;
1235}
1236
1237///////////////////
1238
1239void Model::disturb(double amount)
1240{
1241int i;
1242if (amount<=0) return;
1243for(i=0;i<parts.size();i++)
1244        {
1245        Part *p=getPart(i);
1246        p->p.x+=(rnd01-0.5)*amount;
1247        p->p.y+=(rnd01-0.5)*amount;
1248        p->p.z+=(rnd01-0.5)*amount;
1249        }
1250for(i=0;i<joints.size();i++)
1251        {
1252        Joint *j=getJoint(i);
1253        Pt3D tmpp(j->part2->p);
1254        tmpp-=j->part1->p;
1255        j->d=j->part2->o.revTransform(tmpp);
1256        }
1257}
1258
1259//////////////////////
1260
1261class MinPart: public Part {public: MinPart() {Param par(f0_part_paramtab,this);par.setMin();}};
1262class MaxPart: public Part {public: MaxPart() {Param par(f0_part_paramtab,this);par.setMax();}};
1263class MinJoint: public Joint {public: MinJoint() {Param par(f0_joint_paramtab,this);par.setMin();}};
1264class MaxJoint: public Joint {public: MaxJoint() {Param par(f0_joint_paramtab,this);par.setMax();}};
1265class MinNeuro: public Neuro {public: MinNeuro() {Param par(f0_neuro_paramtab,this);par.setMin();}};
1266class MaxNeuro: public Neuro {public: MaxNeuro() {Param par(f0_neuro_paramtab,this);par.setMax();}};
1267
1268Part& Model::getMinPart() {static MinPart part; return part;}
1269Part& Model::getMaxPart() {static MaxPart part; return part;}
1270Part& Model::getDefPart() {static Part part; return part;}
1271Joint& Model::getMinJoint() {static MinJoint joint; return joint;}
1272Joint& Model::getMaxJoint() {static MaxJoint joint; return joint;}
1273Joint& Model::getDefJoint() {static Joint joint; return joint;}
1274Neuro& Model::getMinNeuro() {static MinNeuro neuro; return neuro;}
1275Neuro& Model::getMaxNeuro() {static MaxNeuro neuro; return neuro;}
1276Neuro& Model::getDefNeuro() {static Neuro neuro; return neuro;}
Note: See TracBrowser for help on using the repository browser.