source: cpp/frams/model/model.cpp @ 109

Last change on this file since 109 was 109, checked in by sz, 10 years ago

source reorganization (see README)
new feature added: part/joint shapes (see frams/_demos/part_shapes.cpp)

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