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

Last change on this file since 166 was 165, checked in by sz, 11 years ago

Model object does not enforce p.m when new style shape is used

  • Property svn:eol-style set to native
File size: 27.0 KB
Line 
1// This file is a part of the Framsticks GDK.
2// Copyright (C) 2002-2014  Maciej Komosinski and 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{
137FOREACH(Part*,p,parts)
138        delete p;
139FOREACH(Joint*,j,joints)
140        delete j;
141FOREACH(Neuro*,n,neurons)
142        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) || (j->d.y != JOINT_DELTA_MARKER) || (j->d.z != JOINT_DELTA_MARKER))
597                        {
598                        j->useDelta(1);
599                        j->resetDeltaMarkers();
600                        }
601                j->attachToParts(j->p1_refno,j->p2_refno);
602                if (srcrange) j->setMapping(*srcrange);
603                return j->refno;
604                }
605        else
606                {
607                delete j;
608                FMprintf("Model","build",FMLV_ERROR,
609                         "invalid part reference for joint #%d",getJointCount()-1);
610                return -1;
611                }
612        }
613else if (!strncmp(t,"n:",2)) // neuro (or the old neuro object as the special case)
614        {
615        Param neuroparam(f0_neuro_paramtab);
616        Neuro *nu=new Neuro();
617        neuroparam.select(nu);
618        pos+=2;
619        neuroparam.load2(line,pos);
620#ifdef MODEL_V1_COMPATIBLE
621        if (nu->neuro_refno>=0) // parent specified...
622                {
623                if (nu->neuro_refno >= getNeuroCount()) // and it's illegal
624                        {
625                        delete nu;
626                        return -1;
627                        }
628                Neuro *parentNU=getNeuro(nu->neuro_refno);
629                parentNU->addInput(nu,nu->weight);
630                // default class for parented units: n-n link
631                //if (nu->moredata.len()==0) nu->moredata="-";
632                }
633        else
634#endif
635                {
636                // default class for unparented units: standard neuron
637                if (nu->getClassName().len()==0) nu->setClassName("N");
638                }
639/*
640        if (nu->conn_refno>=0) // input specified...
641                {
642                if (nu->conn_refno >= getNeuroCount()) // and it's illegal
643                        {
644                        delete nu;
645                        return -1;
646                        }
647                Neuro *inputNU=getNeuro(nu->conn_refno);
648                nu->addInput(inputNU,nu->weight);
649                }
650*/
651#ifdef MODEL_V1_COMPATIBLE
652        nu->weight=1.0;
653#endif
654        nu->owner=this;
655        // attach to part/joint
656        if (nu->part_refno>=0)
657                nu->attachToPart(nu->part_refno);
658        if (nu->joint_refno>=0)
659                nu->attachToJoint(nu->joint_refno);
660        if (srcrange) nu->setMapping(*srcrange);
661        // todo: check part/joint ref#
662#ifdef MODEL_V1_COMPATIBLE
663        if (hasOldNeuroLayout())
664                {
665                int count=old_getNeuroCount();
666                neurons.insert(count,nu);
667                oldneurocount=count+1;
668                return oldneurocount-1;
669                }
670        else
671#endif
672                {
673                neurons+=nu;
674                return neurons.size()-1;
675                }
676        }
677else if (!strncmp(t,"c:",2)) // add input
678        {
679        Param ncparam(f0_neuroconn_paramtab);
680        NeuroConn c;
681        ncparam.select(&c);
682        pos+=2;
683        ncparam.load2(line,pos);
684        if ((c.n1_refno>=0)&&(c.n1_refno<getNeuroCount())&&(c.n2_refno>=0)&&(c.n2_refno<getNeuroCount()))
685                {
686                Neuro *na=getNeuro(c.n1_refno);
687                Neuro *nb=getNeuro(c.n2_refno);
688                na->addInput(nb,c.weight,&c.info);
689                if (srcrange)
690                        na->addMapping(*srcrange);
691                return 0;
692                }
693        FMprintf("Model","build",FMLV_ERROR,
694                 "invalid neuron connection #%d <- #%d",c.n1_refno,c.n2_refno);
695        return -1;
696        }
697#ifdef MODEL_V1_COMPATIBLE
698else if (!strncmp(t,"ni:",3)) // old neuroitem
699        {
700        // we always use old layout for "ni:"
701        Param neuroitemparam(f0_neuroitem_paramtab);
702        Neuro *nu=new Neuro();
703        neuroitemparam.select(nu);
704        pos+=3;
705        neuroitemparam.load2(line,pos);
706        // illegal parent?
707        if ((nu->neuro_refno<0)||(nu->neuro_refno>=old_getNeuroCount()))
708                {
709                delete nu;
710                return -1;
711                }
712        Neuro *parentN=getNeuro(nu->neuro_refno);
713        // copy part/joint refno from parent, if possible
714        if ((nu->part_refno<0)&&(parentN->part_refno>=0))
715                nu->part_refno=parentN->part_refno;
716        if ((nu->joint_refno<0)&&(parentN->joint_refno>=0))
717                nu->joint_refno=parentN->joint_refno;
718        nu->owner=this;
719        // attach to part/joint
720        if (nu->part_refno>=0)
721                nu->attachToPart(nu->part_refno);
722        if (nu->joint_refno>=0)
723                nu->attachToJoint(nu->joint_refno);
724        if (srcrange)
725                nu->setMapping(*srcrange);
726        // special case: old muscles
727        // PARENT neuron will be set up to be the CHILD of the current one (!)
728        if (nu->isOldEffector())
729                {
730                nu->neuro_refno=parentN->refno;
731                neurons+=nu;
732                nu->owner=this;
733                nu->addInput(parentN,nu->weight); // (!)
734                nu->weight=1.0;
735                parentN->invalidateOldItems();
736                return 0; // !!! -> ...getItemCount()-1;
737                }
738        parentN->addInput(nu,nu->weight);
739        neurons+=nu;
740        parentN->invalidateOldItems();
741        if (nu->getClassName().len()==0)
742                {
743                nu->setClassName("-");
744                // for compatibility, "ni" can define a n-n connection
745                // referring to non-existent neuron (which will be hopefully defined later)
746                // internal check will add the proper input to this unit
747                // if conn_refno >=0 and input count==0
748                oldconnections=1;
749                if (srcrange)
750                        parentN->addMapping(*srcrange);
751                }
752        else
753                nu->weight=1.0;
754        return 0; // !!! -> ...getItemCount()-1;
755        }
756#endif
757else return -1;
758}
759
760#ifdef MODEL_V1_COMPATIBLE
761int Model::addOldConnectionsInputs()
762{
763if (!oldconnections) return 1;
764Neuro* n;
765for (int i=0;i<neurons.size();i++)
766        {
767        n=(Neuro*)neurons(i);
768        if (n->conn_refno>=0)
769                if (n->isNNConnection())
770                        if (n->conn_refno < old_getNeuroCount())
771                                { // good reference
772                                Neuro* parent=n->parent; // nn connection has exactly one parent
773                                int inp=parent->findInput(n);
774                                Neuro* target=getNeuro(n->conn_refno);
775                                parent->setInput(inp,target,n->weight);
776                                removeNeuro(i,0); // no need to remove references
777                                i--;
778                                }
779                        else
780                                {
781                                FMprintf("Model","internalCheck",FMLV_ERROR,
782                                         "illegal N-N connection #%d (reference to #%d) (%s)",
783                                         i,n->conn_refno,(const char*)geno.getName());
784                                return 0;
785                                }
786        }
787oldconnections=0;
788return 1;
789}
790#endif
791
792/////////////
793
794/** change the sequence of neuro units
795    and fix references in "-" objects (n-n connections)  */
796void Model::moveNeuro(int oldpos,int newpos)
797{
798if (oldpos==newpos) return; // nop!
799Neuro *n=getNeuro(oldpos);
800neurons-=oldpos;
801neurons.insert(newpos,n);
802 // conn_refno could be broken -> fix it
803#ifdef MODEL_V1_COMPATIBLE
804for (int i=0;i<neurons.size();i++)
805        {
806        Neuro *n2=getNeuro(i);
807        if (n2->isNNConnection())
808                if (n2->conn_refno == oldpos) n2->conn_refno=newpos;
809                else
810                { if (n2->conn_refno > oldpos) n2->conn_refno--;
811                  if (n2->conn_refno >= newpos) n2->conn_refno++; }
812        }
813invalidateOldNeuroCount();
814#endif
815}
816
817#ifdef MODEL_V1_COMPATIBLE
818/** move all old neurons (class "N") to the front of the neurons list.
819    @return number of old neurons
820  */
821int Model::reorderToOldLayout()
822{
823Neuro *n;
824int neurocount=0;
825for (int i=0;i<neurons.size();i++)
826        {
827        n=(Neuro*)neurons(i);
828        if (n->isOldNeuron())
829                {
830                moveNeuro(i,neurocount);
831                neurocount++;
832                i=neurocount-1;
833                }
834        }
835return neurocount;
836}
837#endif
838////////////
839
840void Model::updateNeuroRefno()
841{
842for (int i=0;i<neurons.size();i++)
843        {
844        Neuro* n=(Neuro*)neurons(i);
845        n->refno=i;
846        }
847}
848
849#define VALIDMINMAX(var,template,field) \
850if (var -> field < getMin ## template () . field) \
851        { var->field= getMin ## template () . field; \
852        FMprintf("Model","internalCheck",FMLV_WARN,# field " too small in " # template "#%d (adjusted)",i);} \
853else if (var -> field > getMax ## template () . field) \
854        { var->field= getMax ## template ()  . field; \
855        FMprintf("Model","internalCheck",FMLV_WARN,# field " too big in " # template "#%d (adjusted)",i);}
856
857#define LINKFLAG 0x8000000
858
859void Model::updateRefno()
860{
861int i;
862for (i=0;i<getPartCount();i++) getPart(i)->refno=i;
863for (i=0;i<getJointCount();i++) getJoint(i)->refno=i;
864for (i=0;i<getNeuroCount();i++) getNeuro(i)->refno=i;
865}
866
867int Model::internalcheck(int final)
868{
869Part *p;
870Joint *j;
871Neuro *n;
872int i,k;
873int ret=1;
874if ((parts.size()==0)&&(neurons.size()==0)) return 0;
875if (parts.size()==0)
876        size=Pt3D_0;
877else
878        {
879Pt3D bbmin=((Part*)parts(0))->p, bbmax=bbmin;
880for (i=0;i<parts.size();i++)
881        {
882        p=(Part*)parts(i);
883        p->owner=this;
884        p->refno=i;
885        if (p->shape==0)
886                {
887                if (checklevel>0)
888                        p->mass=0.0;
889                }
890//      VALIDMINMAX(p,part,mass);
891        VALIDMINMAX(p,Part,size);
892        VALIDMINMAX(p,Part,density);
893        VALIDMINMAX(p,Part,friction);
894        VALIDMINMAX(p,Part,ingest);
895        VALIDMINMAX(p,Part,assim);
896        p->flags&=~LINKFLAG; // for delta joint cycle detection
897        if (p->p.x-p->size < bbmin.x) bbmin.x=p->p.x-p->size;
898        if (p->p.y-p->size < bbmin.y) bbmin.y=p->p.y-p->size;
899        if (p->p.z-p->size < bbmin.z) bbmin.z=p->p.z-p->size;
900        if (p->p.x+p->size > bbmax.x) bbmax.x=p->p.x+p->size;
901        if (p->p.y+p->size > bbmax.y) bbmax.y=p->p.y+p->size;
902        if (p->p.z+p->size > bbmax.z) bbmax.z=p->p.z+p->size;
903        }
904size=bbmax-bbmin;
905for (i=0;i<joints.size();i++)
906        {
907        j=(Joint*)joints(i);
908        VALIDMINMAX(j,Joint,stamina);
909        VALIDMINMAX(j,Joint,stif);
910        VALIDMINMAX(j,Joint,rotstif);
911        j->refno=i;
912        j->owner=this;
913        if (j->part1 && j->part2 && (j->part1 != j->part2))
914                {
915                j->p1_refno=j->part1->refno;
916                j->p2_refno=j->part2->refno;
917                if (checklevel>0)
918                        {
919                        if (j->part1->shape==0)
920                                j->part1->mass+=1.0;
921                        if (j->part2->shape==0)
922                                j->part2->mass+=1.0;
923                        }
924                if ((j->usedelta)&&((j->d.x!=JOINT_DELTA_MARKER)||(j->d.y!=JOINT_DELTA_MARKER)||(j->d.z!=JOINT_DELTA_MARKER)))
925                        { // delta positioning -> calc. orient.
926                        if (j->part2->flags & LINKFLAG)
927                                {
928                                ret=0;
929                                FMprintf("Model","internalCheck",FMLV_ERROR,
930                                         "delta joint cycle detected at joint#%d (%s)",
931                                         i,(const char*)geno.getName());
932                                }
933                        j->resetDeltaMarkers();
934                        j->o=j->rot;
935                        j->part1->o.transform(j->part2->o,j->o);
936//                      j->part2->o.x=j->part1->o/j->o.x;
937//                      j->part2->o.y=j->part1->o/j->o.y;
938//                      j->part2->o.z=j->part1->o/j->o.z;
939                        j->part2->p=j->part2->o.transform(j->d)+j->part1->p;
940                        j->part2->flags|=LINKFLAG; j->part1->flags|=LINKFLAG; // for delta joint cycle detection
941                        }
942                else
943                        { // abs.positioning -> calc. delta
944                        if (final)
945                        {
946                        // calc orient delta
947//                      Orient tmpo(j->part2->o);
948//                      tmpo*=j->part1->o;
949                        Orient tmpo;
950                        j->part1->o.revTransform(tmpo,j->part2->o);
951                        tmpo.getAngles(j->rot);
952                        j->o=j->rot;
953                        // calc position delta
954                        Pt3D tmpp(j->part2->p);
955                        tmpp-=j->part1->p;
956                        j->d=j->part2->o.revTransform(tmpp);
957                        }
958                        }
959                if (final)
960                        {
961                        if (j->shape!=Joint::SHAPE_SOLID)
962                                {
963                        if (j->d()>getMaxJoint().d.x)
964                        {
965                        ret=0;
966                        FMprintf("Model","internalCheck",FMLV_ERROR,"delta too big in joint #%d (%s)",
967                                 i,(const char*)geno.getName());
968                        }
969                        else if (j->d()<getMinJoint().d.x)
970                        {
971                        ret=0;
972                        FMprintf("Model","internalCheck",FMLV_ERROR,"delta too small in joint #%d (%s)",
973                                 i,(const char*)geno.getName());
974                        }
975                                }
976                        }
977                }
978        else
979                {
980                FMprintf("Model","internalCheck",FMLV_ERROR,"illegal part references in joint #%d (%s)",
981                         i,(const char*)geno.getName());
982                ret=0;
983                }
984        }
985        }
986#ifdef MODEL_V1_COMPATIBLE
987if (!addOldConnectionsInputs())
988        return 0;
989#endif
990
991updateNeuroRefno(); // valid refno is important for n-n connections check (later)
992
993for (i=0;i<neurons.size();i++)
994        {
995        n=(Neuro*)neurons(i);
996        VALIDMINMAX(n,Neuro,state);
997#ifdef MODEL_V1_COMPATIBLE
998        VALIDMINMAX(n,Neuro,inertia);
999        VALIDMINMAX(n,Neuro,force);
1000        VALIDMINMAX(n,Neuro,sigmo);
1001        n->conn_refno=-1;
1002        n->weight=1.0;
1003        n->neuro_refno=-1;
1004#endif
1005        n->part_refno=(n->part)?n->part->refno:-1;
1006        n->joint_refno=(n->joint)?n->joint->refno:-1;
1007        }
1008
1009if (parts.size()&&(checklevel>0))
1010        {
1011        for (i=0;i<parts.size();i++)
1012                {
1013                p=(Part*)parts(i);
1014                if (p->shape==0)
1015                        if (p->mass<=0.001)
1016                                p->mass=1.0;
1017                p->flags&=~LINKFLAG;
1018                }
1019        getPart(0)->flags|=LINKFLAG;
1020        int change=1;
1021        while(change)
1022                {
1023                change=0;
1024                for (i=0;i<joints.size();i++)
1025                        {
1026                        j=(Joint*)joints(i);
1027                        if (j->part1->flags&LINKFLAG)
1028                                {
1029                                if (!(j->part2->flags&LINKFLAG))
1030                                        {
1031                                        change=1;
1032                                        j->part2->flags|=LINKFLAG;
1033                                        }
1034                                }
1035                        else
1036                        if (j->part2->flags&LINKFLAG)
1037                                {
1038                                if (!(j->part1->flags&LINKFLAG))
1039                                        {
1040                                        change=1;
1041                                        j->part1->flags|=LINKFLAG;
1042                                        }
1043                                }
1044                        }
1045                }
1046        for (i=0;i<parts.size();i++)
1047                {
1048                p=(Part*)parts(i);
1049                if (!(p->flags&LINKFLAG))
1050                        {
1051                        FMprintf("Model","internalCheck",FMLV_ERROR,"not all parts connected (eg.#0-#%d) (%s)",
1052                                 i,(const char*)geno.getName());
1053                        ret=0;
1054                        break;
1055                        }
1056                }
1057        }
1058
1059for (i=0;i<joints.size();i++)
1060        {
1061        j=(Joint*)joints(i);
1062        if (j->p1_refno==j->p2_refno)
1063                {
1064                FMprintf("Model","internalCheck",FMLV_ERROR,"illegal self connection, joint #%d (%s)",
1065                         i,(const char*)geno.getName());
1066                ret=0;
1067                break;
1068                }
1069        for (k=i+1;k<joints.size();k++)
1070                {
1071                Joint* j2=(Joint*)joints(k);
1072                if (((j->p1_refno==j2->p1_refno)&&(j->p2_refno==j2->p2_refno))
1073                    || ((j->p1_refno==j2->p2_refno)&&(j->p2_refno==j2->p1_refno)))
1074                        {
1075                        FMprintf("Model","internalCheck",FMLV_ERROR,"illegal duplicate joints #%d and #%d (%s)",
1076                                 i,k,(const char*)geno.getName());
1077                        ret=0;
1078                        break;
1079                        }
1080                }
1081        }
1082return ret;
1083}
1084
1085/////////////
1086
1087int Model::getErrorPosition(bool includingwarnings)
1088{
1089return includingwarnings?
1090        ((f0errorposition>=0) ? f0errorposition : f0warnposition)
1091        :
1092        f0errorposition;
1093}
1094
1095const Geno& Model::getGeno() const
1096{
1097return geno;
1098}
1099
1100const Geno Model::getF0Geno()
1101{
1102if (buildstatus==building)
1103        FMprintf("Model","getGeno",FMLV_WARN,"model was not completed - missing close()");
1104if (buildstatus!=valid)
1105        return Geno("",'0',"","invalid");
1106if (!f0genoknown)
1107        {
1108        if (autobuildmaps)
1109                {
1110                initF0Map();
1111                makeGeno(f0geno,f0map);
1112                }
1113        else
1114                {
1115                delF0Map();
1116                makeGeno(f0geno);
1117                }
1118        f0genoknown=1;
1119        }
1120return f0geno;
1121}
1122
1123int Model::getPartCount() const
1124{
1125return parts.size();
1126}
1127
1128Part* Model::getPart(int i) const
1129{
1130return ((Part*)parts(i));
1131}
1132
1133int Model::getJointCount() const
1134{
1135return joints.size();
1136}
1137
1138Joint* Model::getJoint(int i) const
1139{
1140return ((Joint*)joints(i));
1141}
1142
1143int Model::findJoints(SList& result,const Part* part)
1144{
1145Joint *j;
1146int n0=result.size();
1147if (part)
1148   for(int i=0;j=(Joint*)joints(i);i++)
1149     if ((j->part1 == part) || (j->part2 == part)) result+=(void*)j;
1150return result.size()-n0;
1151}
1152
1153int Model::findNeuro(Neuro* n)
1154{return neurons.find(n);}
1155
1156int Model::findPart(Part* p)
1157{return parts.find(p);}
1158
1159int Model::findJoint(Joint* j)
1160{return joints.find(j);}
1161
1162int Model::findJoint(Part *p1, Part *p2)
1163{
1164Joint* j;
1165for(int i=0;j=getJoint(i);i++)
1166        if ((j->part1==p1)&&(j->part2==p2)) return i;
1167return -1;
1168}
1169
1170
1171////////////////////
1172
1173#ifdef MODEL_V1_COMPATIBLE
1174void Model::calcOldNeuroCount()
1175{
1176if (oldneurocount>=0) return;
1177oldneurocount=reorderToOldLayout();
1178}
1179
1180int Model::old_getNeuroCount()
1181{ calcOldNeuroCount();
1182 return oldneurocount;}
1183
1184Neuro* Model::old_getNeuro(int i)
1185{calcOldNeuroCount();
1186return (i<oldneurocount)? (Neuro*)getNeuro(i) : (Neuro*)0;
1187}
1188
1189int Model::old_findNeuro(Neuro* n)
1190{calcOldNeuroCount();
1191return findNeuro(n);}
1192
1193Neuro *Model::old_addNewNeuro()
1194{
1195int count=old_getNeuroCount();
1196Neuro *nu=addNewNeuro();
1197nu->setClassName("N");
1198moveNeuro(nu->refno,oldneurocount);
1199oldneurocount=count+1;
1200return (Neuro*)nu;
1201}
1202#endif
1203
1204///////////////////////
1205
1206int Model::getNeuroCount() const
1207{return neurons.size();}
1208
1209Neuro* Model::getNeuro(int i) const
1210{return (Neuro*)neurons(i);}
1211
1212int Model::getConnectionCount() const
1213{
1214int n=0;
1215for(int i=0;i<getNeuroCount();i++)
1216        n+=getNeuro(i)->getInputCount();
1217return n;
1218}
1219
1220int Model::findNeuros(SList& result,
1221                          const char* classname,const Part* part,const Joint* joint)
1222{
1223Neuro *nu;
1224SString cn(classname);
1225int n0=result.size();
1226for(int i=0;nu=(Neuro*)neurons(i);i++)
1227        {
1228        if (part)
1229                if (nu->part != part) continue;
1230        if (joint)
1231                if (nu->joint != joint) continue;
1232        if (classname)
1233                if (nu->getClassName() != cn) continue;
1234        result+=(void*)nu;
1235        }
1236return result.size()-n0;
1237}
1238
1239///////////////////
1240
1241void Model::disturb(double amount)
1242{
1243int i;
1244if (amount<=0) return;
1245for(i=0;i<parts.size();i++)
1246        {
1247        Part *p=getPart(i);
1248        p->p.x+=(rnd01-0.5)*amount;
1249        p->p.y+=(rnd01-0.5)*amount;
1250        p->p.z+=(rnd01-0.5)*amount;
1251        }
1252for(i=0;i<joints.size();i++)
1253        {
1254        Joint *j=getJoint(i);
1255        Pt3D tmpp(j->part2->p);
1256        tmpp-=j->part1->p;
1257        j->d=j->part2->o.revTransform(tmpp);
1258        }
1259}
1260
1261//////////////////////
1262
1263class MinPart: public Part {public: MinPart() {Param par(f0_part_paramtab,this);par.setMin();}};
1264class MaxPart: public Part {public: MaxPart() {Param par(f0_part_paramtab,this);par.setMax();}};
1265class MinJoint: public Joint {public: MinJoint() {Param par(f0_joint_paramtab,this);par.setMin();}};
1266class MaxJoint: public Joint {public: MaxJoint() {Param par(f0_joint_paramtab,this);par.setMax();}};
1267class MinNeuro: public Neuro {public: MinNeuro() {Param par(f0_neuro_paramtab,this);par.setMin();}};
1268class MaxNeuro: public Neuro {public: MaxNeuro() {Param par(f0_neuro_paramtab,this);par.setMax();}};
1269
1270Part& Model::getMinPart() {static MinPart part; return part;}
1271Part& Model::getMaxPart() {static MaxPart part; return part;}
1272Part& Model::getDefPart() {static Part part; return part;}
1273Joint& Model::getMinJoint() {static MinJoint joint; return joint;}
1274Joint& Model::getMaxJoint() {static MaxJoint joint; return joint;}
1275Joint& Model::getDefJoint() {static Joint joint; return joint;}
1276Neuro& Model::getMinNeuro() {static MinNeuro neuro; return neuro;}
1277Neuro& Model::getMaxNeuro() {static MaxNeuro neuro; return neuro;}
1278Neuro& Model::getDefNeuro() {static Neuro neuro; return neuro;}
Note: See TracBrowser for help on using the repository browser.