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

Last change on this file since 501 was 501, checked in by Maciej Komosinski, 6 years ago

Fixed obvious read from the just-deleted object

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