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

Last change on this file since 427 was 393, checked in by sz, 9 years ago

f0 parsing corrections and enhancements:

  • f0 genotype becomes invalid if any of its numeric fields can't be parsed
  • ParamInterface::set and ParamInterface::load2 return the error flag if a numeric parsing error occured
  • fixed a bug in load2 (was failing on quoted fields containing a comma)
  • Property svn:eol-style set to native
File size: 28.9 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,autobuildmaps ? (&frommap) : 0)==-1)
329                {
330                buildstatus=invalid;
331                logPrintf("Model","build",LOG_ERROR,
332                         geno.getName().len()?"illegal f0 code at line %d (%s)":"illegal f0 code at line %d",
333                         lnum,geno.getName().c_str());
334                f0errorposition=lastpos;
335                if (convmap) delete convmap;
336                return;
337                }
338        if (mh.getWarningCount())
339                {if (f0warnposition<0) f0warnposition=lastpos;}
340        lastpos=pos;
341        }
342mh.disable();
343close();
344if (convmap)
345        {
346        *f0map=*map;
347        if (geno.getFormat()!='0')
348                {
349                MultiMap tmp;
350                tmp.addCombined(*convmap,getMap());
351                *map=tmp;
352                }
353        delete convmap;
354        }
355}
356
357const MultiMap& Model::getF0Map()
358{
359if (!f0map)
360        {
361        f0map=new MultiMap();
362        makeGeno(f0geno,f0map);
363        f0genoknown=1;
364        }
365return *f0map;
366}
367
368Geno Model::rawGeno()
369{
370Geno tmpgen;
371makeGeno(tmpgen);
372return tmpgen;
373}
374
375void Model::makeGeno(Geno &g,MultiMap *map,bool handle_defaults)
376{
377if ((buildstatus!=valid)&&(buildstatus!=building))
378        {
379        g=Geno(0,0,0,"invalid model");
380        return;
381        }
382
383SString gen;
384
385Param modelparam(f0_model_paramtab);
386Param partparam(f0_part_paramtab);
387Param jointparam(f0_joint_paramtab);
388Param neuroparam(f0_neuro_paramtab);
389Param connparam(f0_neuroconn_paramtab);
390
391static Part defaultpart;
392static Joint defaultjoint;
393static Neuro defaultneuro;
394static Model defaultmodel;
395static NeuroConn defaultconn;
396//static NeuroItem defaultneuroitem;
397
398Part *p;
399Joint *j;
400Neuro *n;
401int i;
402int len;
403int a,b;
404//NeuroItem *ni;
405
406SString mod_props;
407modelparam.select(this);
408modelparam.save2(mod_props,handle_defaults ? &defaultmodel : NULL,true,!handle_defaults);
409if (mod_props.len()>0) //are there any non-default values?
410        {
411        gen+="m:";
412        gen+=mod_props;
413        }
414
415for (i=0;p=(Part*)parts(i);i++)
416        {
417        partparam.select(p);
418        len=gen.len();
419        gen+="p:";
420        partparam.save2(gen,handle_defaults ? &defaultpart : NULL,true,!handle_defaults);
421        if (map)
422                map->add(len,gen.len()-1,partToMap(i));
423        }
424for (i=0;j=(Joint*)joints(i);i++)
425        {
426        jointparam.select(j);
427        len=gen.len();
428        jointparam.setParamTab(j->usedelta?f0_joint_paramtab:f0_nodeltajoint_paramtab);
429        gen+="j:";
430        jointparam.save2(gen,handle_defaults ? &defaultjoint : NULL,true,!handle_defaults);
431        if (map)
432                map->add(len,gen.len()-1,jointToMap(i));
433        }
434for (i=0;n=(Neuro*)neurons(i);i++)
435        {
436        neuroparam.select(n);
437        len=gen.len();
438        gen+="n:";
439        neuroparam.save2(gen,handle_defaults ? &defaultneuro : NULL,true,!handle_defaults);
440        if (map)
441                map->add(len,gen.len()-1,neuroToMap(i));
442        }
443for (a=0;a<neurons.size();a++)
444        { // inputs
445        n=(Neuro*)neurons(a);
446//      if ((n->getInputCount()==1)&&(n->getInput(0).refno <= n->refno))
447//              continue; // already done with Neuro::conn_refno
448
449        for (b=0;b<n->getInputCount();b++)
450                {
451                double w;
452                NeuroConn nc;
453                Neuro* n2=n->getInput(b,w);
454//              if (((n2.parentcount==1)&&(n2.parent)&&(n2.parent->refno < n2.refno)) ^
455//                  (n2.neuro_refno>=0))
456//                      printf("!!!! bad Neuro::neuro_refno ?!\n");
457
458//              if ((n2.parentcount==1)&&(n2.parent)&&(n2.parent->refno < n2.refno))
459//              if (n2.neuro_refno>=0)
460//                      continue; // already done with Neuro::neuro_refno
461
462                nc.n1_refno=n->refno; nc.n2_refno=n2->refno;
463                nc.weight=w;
464                SString **s=n->inputInfo(b);
465                if ((s)&&(*s))
466                nc.info=**s;
467                connparam.select(&nc);
468                len=gen.len();
469                gen+="c:";
470                connparam.save2(gen,handle_defaults ? &defaultconn : NULL,true,!handle_defaults);
471                if (map)
472                        map->add(len,gen.len()-1,neuroToMap(n->refno));
473                }
474        }
475g=Geno(gen.c_str(),'0');
476}
477
478//////////////
479
480void Model::open()
481{
482if (buildstatus==building) return;
483buildstatus=building;
484modelfromgenotype=0;
485partmappingchanged=0;
486f0genoknown=0;
487delMap();
488}
489
490void Model::checkpoint()
491{}
492
493void Model::setGeno(const Geno& newgeno)
494{
495geno=newgeno;
496}
497
498void Model::clearMap()
499{
500Part *p; Joint *j; Neuro *n;
501int i;
502delMap();
503delF0Map();
504for (i=0;p=(Part*)parts(i);i++)
505        p->clearMapping();
506for (i=0;j=(Joint*)joints(i);i++)
507        j->clearMapping();
508for (i=0;n=(Neuro*)neurons(i);i++)
509        n->clearMapping();
510}
511
512int Model::close()
513{
514if (buildstatus!=building)
515        logPrintf("Model","close",LOG_WARN,"unexpected close() - no open()");
516if (internalcheck(1)>0)
517        {
518        buildstatus=valid;
519
520        if (partmappingchanged)
521                {
522                getMap();
523                Part *p; Joint *j; Neuro *n;
524                int i;
525                for (i=0;p=(Part*)parts(i);i++)
526                        if (p->getMapping())
527                                map->add(*p->getMapping(),partToMap(i));
528                for (i=0;j=(Joint*)joints(i);i++)
529                        if (j->getMapping())
530                                map->add(*j->getMapping(),jointToMap(i));
531                for (i=0;n=(Neuro*)neurons(i);i++)
532                        if (n->getMapping())
533                                map->add(*n->getMapping(),neuroToMap(i));
534                }
535        }
536else
537        buildstatus=invalid;
538
539return (buildstatus==valid);
540}
541
542int Model::validate()
543{
544return internalcheck(0);
545}
546
547Pt3D Model::whereDelta(const Part& start,const Pt3D& rot, const Pt3D& delta)
548{
549Orient roto;
550roto=rot;
551Orient o;
552roto.transform(o,start.o);
553//o.x=start.o/roto.x;
554//o.y=start.o/roto.y;
555//o.z=start.o/roto.z;
556return o.transform(delta)+start.p;
557}
558
559int Model::singleStepBuild(const SString &line,const MultiRange* srcrange)
560{
561int pos=0; const char*t=line.c_str();
562for (;*t;t++,pos++)
563        if (!strchr(" \r\t",*t)) break;
564if (*t=='#') return 0;
565if (!*t) return 0;
566if (!strncmp(t,"p:",2))
567        {
568        Param partparam(f0_part_paramtab);
569        Part *p=new Part();
570        partparam.select(p);
571        pos+=2;
572        if (partparam.load2(line,pos) & ParamInterface::LOAD2_PARSE_FAILED) return -1;
573        p->o.rotate(p->rot);
574        parts+=p;
575        p->owner=this;
576        if (srcrange) p->setMapping(*srcrange);
577        return getPartCount()-1;
578        }
579if (!strncmp(t,"m:",2))
580        {
581        Param modelparam(f0_model_paramtab);
582        modelparam.select(this);
583        pos+=2;
584        if (modelparam.load2(line,pos) & ParamInterface::LOAD2_PARSE_FAILED) return -1;
585        return 0;
586        }
587else if (!strncmp(t,"j:",2))
588        {
589        Param jointparam(f0_joint_paramtab);
590        Joint *j=new Joint();
591        jointparam.select(j);
592        pos+=2;
593        j->owner=this;
594        if (jointparam.load2(line,pos) & ParamInterface::LOAD2_PARSE_FAILED) return -1;
595        if ((j->p1_refno>=0)&&(j->p1_refno<getPartCount())&&
596           (j->p2_refno>=0)&&(j->p2_refno<getPartCount()))
597                {
598                addJoint(j);
599                if ((j->d.x != JOINT_DELTA_MARKER) || (j->d.y != JOINT_DELTA_MARKER) || (j->d.z != JOINT_DELTA_MARKER))
600                        {
601                        j->useDelta(1);
602                        j->resetDeltaMarkers();
603                        }
604                j->attachToParts(j->p1_refno,j->p2_refno);
605                if (srcrange) j->setMapping(*srcrange);
606                return j->refno;
607                }
608        else
609                {
610                delete j;
611                logPrintf("Model","build",LOG_ERROR,
612                         "invalid part reference for joint #%d",getJointCount()-1);
613                return -1;
614                }
615        }
616else if (!strncmp(t,"n:",2)) // neuro (or the old neuro object as the special case)
617        {
618        Param neuroparam(f0_neuro_paramtab);
619        Neuro *nu=new Neuro();
620        neuroparam.select(nu);
621        pos+=2;
622        if (neuroparam.load2(line,pos) & ParamInterface::LOAD2_PARSE_FAILED) return -1;
623#ifdef MODEL_V1_COMPATIBLE
624        if (nu->neuro_refno>=0) // parent specified...
625                {
626                if (nu->neuro_refno >= getNeuroCount()) // and it's illegal
627                        {
628                        delete nu;
629                        return -1;
630                        }
631                Neuro *parentNU=getNeuro(nu->neuro_refno);
632                parentNU->addInput(nu,nu->weight);
633                // default class for parented units: n-n link
634                //if (nu->moredata.len()==0) nu->moredata="-";
635                }
636        else
637#endif
638                {
639                // default class for unparented units: standard neuron
640                if (nu->getClassName().len()==0) nu->setClassName("N");
641                }
642/*
643        if (nu->conn_refno>=0) // input specified...
644                {
645                if (nu->conn_refno >= getNeuroCount()) // and it's illegal
646                        {
647                        delete nu;
648                        return -1;
649                        }
650                Neuro *inputNU=getNeuro(nu->conn_refno);
651                nu->addInput(inputNU,nu->weight);
652                }
653*/
654#ifdef MODEL_V1_COMPATIBLE
655        nu->weight=1.0;
656#endif
657        nu->owner=this;
658        // attach to part/joint
659        if (nu->part_refno>=0)
660                nu->attachToPart(nu->part_refno);
661        if (nu->joint_refno>=0)
662                nu->attachToJoint(nu->joint_refno);
663        if (srcrange) nu->setMapping(*srcrange);
664        // todo: check part/joint ref#
665#ifdef MODEL_V1_COMPATIBLE
666        if (hasOldNeuroLayout())
667                {
668                int count=old_getNeuroCount();
669                neurons.insert(count,nu);
670                oldneurocount=count+1;
671                return oldneurocount-1;
672                }
673        else
674#endif
675                {
676                neurons+=nu;
677                return neurons.size()-1;
678                }
679        }
680else if (!strncmp(t,"c:",2)) // add input
681        {
682        Param ncparam(f0_neuroconn_paramtab);
683        NeuroConn c;
684        ncparam.select(&c);
685        pos+=2;
686        if (ncparam.load2(line,pos) & ParamInterface::LOAD2_PARSE_FAILED) return -1;
687        if ((c.n1_refno>=0)&&(c.n1_refno<getNeuroCount())&&(c.n2_refno>=0)&&(c.n2_refno<getNeuroCount()))
688                {
689                Neuro *na=getNeuro(c.n1_refno);
690                Neuro *nb=getNeuro(c.n2_refno);
691                na->addInput(nb,c.weight,&c.info);
692                if (srcrange)
693                        na->addMapping(*srcrange);
694                return 0;
695                }
696        logPrintf("Model","build",LOG_ERROR,
697                 "invalid neuron connection #%d <- #%d",c.n1_refno,c.n2_refno);
698        return -1;
699        }
700#ifdef MODEL_V1_COMPATIBLE
701else if (!strncmp(t,"ni:",3)) // old neuroitem
702        {
703        // we always use old layout for "ni:"
704        Param neuroitemparam(f0_neuroitem_paramtab);
705        Neuro *nu=new Neuro();
706        neuroitemparam.select(nu);
707        pos+=3;
708        if (neuroitemparam.load2(line,pos) & ParamInterface::LOAD2_PARSE_FAILED) return -1;
709        // illegal parent?
710        if ((nu->neuro_refno<0)||(nu->neuro_refno>=old_getNeuroCount()))
711                {
712                delete nu;
713                return -1;
714                }
715        Neuro *parentN=getNeuro(nu->neuro_refno);
716        // copy part/joint refno from parent, if possible
717        if ((nu->part_refno<0)&&(parentN->part_refno>=0))
718                nu->part_refno=parentN->part_refno;
719        if ((nu->joint_refno<0)&&(parentN->joint_refno>=0))
720                nu->joint_refno=parentN->joint_refno;
721        nu->owner=this;
722        // attach to part/joint
723        if (nu->part_refno>=0)
724                nu->attachToPart(nu->part_refno);
725        if (nu->joint_refno>=0)
726                nu->attachToJoint(nu->joint_refno);
727        if (srcrange)
728                nu->setMapping(*srcrange);
729        // special case: old muscles
730        // PARENT neuron will be set up to be the CHILD of the current one (!)
731        if (nu->isOldEffector())
732                {
733                nu->neuro_refno=parentN->refno;
734                neurons+=nu;
735                nu->owner=this;
736                nu->addInput(parentN,nu->weight); // (!)
737                nu->weight=1.0;
738                parentN->invalidateOldItems();
739                return 0; // !!! -> ...getItemCount()-1;
740                }
741        parentN->addInput(nu,nu->weight);
742        neurons+=nu;
743        parentN->invalidateOldItems();
744        if (nu->getClassName().len()==0)
745                {
746                nu->setClassName("-");
747                // for compatibility, "ni" can define a n-n connection
748                // referring to non-existent neuron (which will be hopefully defined later)
749                // internal check will add the proper input to this unit
750                // if conn_refno >=0 and input count==0
751                oldconnections=1;
752                if (srcrange)
753                        parentN->addMapping(*srcrange);
754                }
755        else
756                nu->weight=1.0;
757        return 0; // !!! -> ...getItemCount()-1;
758        }
759#endif
760else return -1;
761}
762
763#ifdef MODEL_V1_COMPATIBLE
764int Model::addOldConnectionsInputs()
765{
766if (!oldconnections) return 1;
767Neuro* n;
768for (int i=0;i<neurons.size();i++)
769        {
770        n=(Neuro*)neurons(i);
771        if (n->conn_refno>=0)
772                if (n->isNNConnection())
773                        if (n->conn_refno < old_getNeuroCount())
774                                { // good reference
775                                Neuro* parent=n->parent; // nn connection has exactly one parent
776                                int inp=parent->findInput(n);
777                                Neuro* target=getNeuro(n->conn_refno);
778                                parent->setInput(inp,target,n->weight);
779                                removeNeuro(i,0); // no need to remove references
780                                i--;
781                                }
782                        else
783                                {
784                                logPrintf("Model","internalCheck",LOG_ERROR,
785                                         "illegal N-N connection #%d (reference to #%d) (%s)",
786                                         i,n->conn_refno,(const char*)geno.getName());
787                                return 0;
788                                }
789        }
790oldconnections=0;
791return 1;
792}
793#endif
794
795/////////////
796
797/** change the sequence of neuro units
798    and fix references in "-" objects (n-n connections)  */
799void Model::moveNeuro(int oldpos,int newpos)
800{
801if (oldpos==newpos) return; // nop!
802Neuro *n=getNeuro(oldpos);
803neurons-=oldpos;
804neurons.insert(newpos,n);
805 // conn_refno could be broken -> fix it
806#ifdef MODEL_V1_COMPATIBLE
807for (int i=0;i<neurons.size();i++)
808        {
809        Neuro *n2=getNeuro(i);
810        if (n2->isNNConnection())
811                if (n2->conn_refno == oldpos) n2->conn_refno=newpos;
812                else
813                { if (n2->conn_refno > oldpos) n2->conn_refno--;
814                  if (n2->conn_refno >= newpos) n2->conn_refno++; }
815        }
816invalidateOldNeuroCount();
817#endif
818}
819
820#ifdef MODEL_V1_COMPATIBLE
821/** move all old neurons (class "N") to the front of the neurons list.
822    @return number of old neurons
823  */
824int Model::reorderToOldLayout()
825{
826Neuro *n;
827int neurocount=0;
828for (int i=0;i<neurons.size();i++)
829        {
830        n=(Neuro*)neurons(i);
831        if (n->isOldNeuron())
832                {
833                moveNeuro(i,neurocount);
834                neurocount++;
835                i=neurocount-1;
836                }
837        }
838return neurocount;
839}
840#endif
841////////////
842
843void Model::updateNeuroRefno()
844{
845for (int i=0;i<neurons.size();i++)
846        {
847        Neuro* n=(Neuro*)neurons(i);
848        n->refno=i;
849        }
850}
851
852#define VALIDMINMAX(var,template,field) \
853if (var -> field < getMin ## template () . field) \
854        { var->field= getMin ## template () . field; \
855        logPrintf("Model","internalCheck",LOG_WARN,# field " too small in " # template "#%d (adjusted)",i);} \
856else if (var -> field > getMax ## template () . field) \
857        { var->field= getMax ## template ()  . field; \
858        logPrintf("Model","internalCheck",LOG_WARN,# field " too big in " # template "#%d (adjusted)",i);}
859
860#define LINKFLAG 0x8000000
861
862void Model::updateRefno()
863{
864int i;
865for (i=0;i<getPartCount();i++) getPart(i)->refno=i;
866for (i=0;i<getJointCount();i++) getJoint(i)->refno=i;
867for (i=0;i<getNeuroCount();i++) getNeuro(i)->refno=i;
868}
869
870int Model::internalcheck(int final)
871{
872Part *p;
873Joint *j;
874Neuro *n;
875int i,k;
876int ret=1;
877shape=SHAPE_UNKNOWN;
878if ((parts.size()==0)&&(neurons.size()==0)) return 0;
879if (parts.size()==0)
880        size=Pt3D_0;
881else
882        {
883Pt3D bbmin=((Part*)parts(0))->p, bbmax=bbmin;
884for (i=0;i<parts.size();i++)
885        {
886        p=(Part*)parts(i);
887        p->owner=this;
888        p->refno=i;
889        if (p->shape==0)
890                {
891                if (checklevel>0)
892                        p->mass=0.0;
893                }
894//      VALIDMINMAX(p,part,mass);
895        VALIDMINMAX(p,Part,size);
896        VALIDMINMAX(p,Part,density);
897        VALIDMINMAX(p,Part,friction);
898        VALIDMINMAX(p,Part,ingest);
899        VALIDMINMAX(p,Part,assim);
900        p->flags&=~LINKFLAG; // for delta joint cycle detection
901        if (p->p.x-p->size < bbmin.x) bbmin.x=p->p.x-p->size;
902        if (p->p.y-p->size < bbmin.y) bbmin.y=p->p.y-p->size;
903        if (p->p.z-p->size < bbmin.z) bbmin.z=p->p.z-p->size;
904        if (p->p.x+p->size > bbmax.x) bbmax.x=p->p.x+p->size;
905        if (p->p.y+p->size > bbmax.y) bbmax.y=p->p.y+p->size;
906        if (p->p.z+p->size > bbmax.z) bbmax.z=p->p.z+p->size;
907        if (shape==SHAPE_UNKNOWN)
908                shape=(p->shape==Part::SHAPE_DEFAULT)?SHAPE_OLD:SHAPE_NEW;
909        else if (shape!=SHAPE_ILLEGAL)
910                {
911                if ((p->shape==Part::SHAPE_DEFAULT) ^ (shape==SHAPE_OLD))
912                        {
913                        shape=SHAPE_ILLEGAL;
914                        logPrintf("Model","internalCheck",LOG_WARN,"Inconsistent part shapes (mixed old and new shapes)");
915                        }
916                }
917        }
918size=bbmax-bbmin;
919for (i=0;i<joints.size();i++)
920        {
921        j=(Joint*)joints(i);
922        VALIDMINMAX(j,Joint,stamina);
923        VALIDMINMAX(j,Joint,stif);
924        VALIDMINMAX(j,Joint,rotstif);
925        j->refno=i;
926        j->owner=this;
927        if (j->part1 && j->part2 && (j->part1 != j->part2))
928                {
929                j->p1_refno=j->part1->refno;
930                j->p2_refno=j->part2->refno;
931                if (checklevel>0)
932                        {
933                        if (j->part1->shape==0)
934                                j->part1->mass+=1.0;
935                        if (j->part2->shape==0)
936                                j->part2->mass+=1.0;
937                        }
938                if ((j->usedelta)&&((j->d.x!=JOINT_DELTA_MARKER)||(j->d.y!=JOINT_DELTA_MARKER)||(j->d.z!=JOINT_DELTA_MARKER)))
939                        { // delta positioning -> calc. orient.
940                        if (j->part2->flags & LINKFLAG)
941                                {
942                                ret=0;
943                                logPrintf("Model","internalCheck",LOG_ERROR,
944                                         "delta joint cycle detected at joint#%d (%s)",
945                                         i,geno.getName().c_str());
946                                }
947                        j->resetDeltaMarkers();
948                        j->o=j->rot;
949                        j->part1->o.transform(j->part2->o,j->o);
950//                      j->part2->o.x=j->part1->o/j->o.x;
951//                      j->part2->o.y=j->part1->o/j->o.y;
952//                      j->part2->o.z=j->part1->o/j->o.z;
953                        j->part2->p=j->part2->o.transform(j->d)+j->part1->p;
954                        j->part2->flags|=LINKFLAG; j->part1->flags|=LINKFLAG; // for delta joint cycle detection
955                        }
956                else
957                        { // abs.positioning -> calc. delta
958                        if (final)
959                        {
960                        // calc orient delta
961//                      Orient tmpo(j->part2->o);
962//                      tmpo*=j->part1->o;
963                        Orient tmpo;
964                        j->part1->o.revTransform(tmpo,j->part2->o);
965                        tmpo.getAngles(j->rot);
966                        j->o=j->rot;
967                        // calc position delta
968                        Pt3D tmpp(j->part2->p);
969                        tmpp-=j->part1->p;
970                        j->d=j->part2->o.revTransform(tmpp);
971                        }
972                        }
973                if (final)
974                        {
975                        if (j->shape!=Joint::SHAPE_SOLID)
976                                {
977                        if (j->d()>getMaxJoint().d.x)
978                        {
979                        ret=0;
980                        logPrintf("Model","internalCheck",LOG_ERROR,"delta too big in joint #%d (%s)",
981                                 i,geno.getName().c_str());
982                        }
983                        else if (j->d()<getMinJoint().d.x)
984                        {
985                        ret=0;
986                        logPrintf("Model","internalCheck",LOG_ERROR,"delta too small in joint #%d (%s)",
987                                 i,geno.getName().c_str());
988                        }
989                                }
990                        }
991                }
992        else
993                {
994                logPrintf("Model","internalCheck",LOG_ERROR,"illegal part references in joint #%d (%s)",
995                         i,geno.getName().c_str());
996                ret=0;
997                }
998        if (shape!=SHAPE_ILLEGAL)
999                {
1000                if ((j->shape==Joint::SHAPE_DEFAULT) ^ (shape==SHAPE_OLD))
1001                        {
1002                        shape=SHAPE_ILLEGAL;
1003                        logPrintf("Model","internalCheck",LOG_WARN,"Inconsistent joint shapes (mixed old and new shapes)");
1004                        }
1005                }
1006        }
1007        }
1008#ifdef MODEL_V1_COMPATIBLE
1009if (!addOldConnectionsInputs())
1010        return 0;
1011#endif
1012
1013updateNeuroRefno(); // valid refno is important for n-n connections check (later)
1014
1015for (i=0;i<neurons.size();i++)
1016        {
1017        n=(Neuro*)neurons(i);
1018        VALIDMINMAX(n,Neuro,state);
1019#ifdef MODEL_V1_COMPATIBLE
1020        VALIDMINMAX(n,Neuro,inertia);
1021        VALIDMINMAX(n,Neuro,force);
1022        VALIDMINMAX(n,Neuro,sigmo);
1023        n->conn_refno=-1;
1024        n->weight=1.0;
1025        n->neuro_refno=-1;
1026#endif
1027        n->part_refno=(n->part)?n->part->refno:-1;
1028        n->joint_refno=(n->joint)?n->joint->refno:-1;
1029        }
1030
1031if (parts.size()&&(checklevel>0))
1032        {
1033        for (i=0;i<parts.size();i++)
1034                {
1035                p=(Part*)parts(i);
1036                if (p->shape==0)
1037                        if (p->mass<=0.001)
1038                                p->mass=1.0;
1039                p->flags&=~LINKFLAG;
1040                }
1041        getPart(0)->flags|=LINKFLAG;
1042        int change=1;
1043        while(change)
1044                {
1045                change=0;
1046                for (i=0;i<joints.size();i++)
1047                        {
1048                        j=(Joint*)joints(i);
1049                        if (j->part1->flags&LINKFLAG)
1050                                {
1051                                if (!(j->part2->flags&LINKFLAG))
1052                                        {
1053                                        change=1;
1054                                        j->part2->flags|=LINKFLAG;
1055                                        }
1056                                }
1057                        else
1058                        if (j->part2->flags&LINKFLAG)
1059                                {
1060                                if (!(j->part1->flags&LINKFLAG))
1061                                        {
1062                                        change=1;
1063                                        j->part1->flags|=LINKFLAG;
1064                                        }
1065                                }
1066                        }
1067                }
1068        for (i=0;i<parts.size();i++)
1069                {
1070                p=(Part*)parts(i);
1071                if (!(p->flags&LINKFLAG))
1072                        {
1073                        logPrintf("Model","internalCheck",LOG_ERROR,"not all parts connected (eg.#0-#%d) (%s)",
1074                                 i,geno.getName().c_str());
1075                        ret=0;
1076                        break;
1077                        }
1078                }
1079        }
1080
1081for (i=0;i<joints.size();i++)
1082        {
1083        j=(Joint*)joints(i);
1084        if (j->p1_refno==j->p2_refno)
1085                {
1086                logPrintf("Model","internalCheck",LOG_ERROR,"illegal self connection, joint #%d (%s)",
1087                         i,geno.getName().c_str());
1088                ret=0;
1089                break;
1090                }
1091        for (k=i+1;k<joints.size();k++)
1092                {
1093                Joint* j2=(Joint*)joints(k);
1094                if (((j->p1_refno==j2->p1_refno)&&(j->p2_refno==j2->p2_refno))
1095                    || ((j->p1_refno==j2->p2_refno)&&(j->p2_refno==j2->p1_refno)))
1096                        {
1097                        logPrintf("Model","internalCheck",LOG_ERROR,"illegal duplicate joints #%d and #%d (%s)",
1098                                 i,k,geno.getName().c_str());
1099                        ret=0;
1100                        break;
1101                        }
1102                }
1103        }
1104if (shape==SHAPE_ILLEGAL)
1105        ret=0;
1106return ret;
1107}
1108
1109/////////////
1110
1111int Model::getErrorPosition(bool includingwarnings)
1112{
1113return includingwarnings?
1114        ((f0errorposition>=0) ? f0errorposition : f0warnposition)
1115        :
1116        f0errorposition;
1117}
1118
1119const Geno& Model::getGeno() const
1120{
1121return geno;
1122}
1123
1124const Geno Model::getF0Geno()
1125{
1126if (buildstatus==building)
1127        logPrintf("Model","getGeno",LOG_WARN,"model was not completed - missing close()");
1128if (buildstatus!=valid)
1129        return Geno("",'0',"","invalid");
1130if (!f0genoknown)
1131        {
1132        if (autobuildmaps)
1133                {
1134                initF0Map();
1135                makeGeno(f0geno,f0map);
1136                }
1137        else
1138                {
1139                delF0Map();
1140                makeGeno(f0geno);
1141                }
1142        f0genoknown=1;
1143        }
1144return f0geno;
1145}
1146
1147int Model::getPartCount() const
1148{
1149return parts.size();
1150}
1151
1152Part* Model::getPart(int i) const
1153{
1154return ((Part*)parts(i));
1155}
1156
1157int Model::getJointCount() const
1158{
1159return joints.size();
1160}
1161
1162Joint* Model::getJoint(int i) const
1163{
1164return ((Joint*)joints(i));
1165}
1166
1167int Model::findJoints(SList& result,const Part* part)
1168{
1169Joint *j;
1170int n0=result.size();
1171if (part)
1172   for(int i=0;j=(Joint*)joints(i);i++)
1173     if ((j->part1 == part) || (j->part2 == part)) result+=(void*)j;
1174return result.size()-n0;
1175}
1176
1177int Model::findNeuro(Neuro* n)
1178{return neurons.find(n);}
1179
1180int Model::findPart(Part* p)
1181{return parts.find(p);}
1182
1183int Model::findJoint(Joint* j)
1184{return joints.find(j);}
1185
1186int Model::findJoint(Part *p1, Part *p2)
1187{
1188Joint* j;
1189for(int i=0;j=getJoint(i);i++)
1190        if ((j->part1==p1)&&(j->part2==p2)) return i;
1191return -1;
1192}
1193
1194
1195////////////////////
1196
1197#ifdef MODEL_V1_COMPATIBLE
1198void Model::calcOldNeuroCount()
1199{
1200if (oldneurocount>=0) return;
1201oldneurocount=reorderToOldLayout();
1202}
1203
1204int Model::old_getNeuroCount()
1205{ calcOldNeuroCount();
1206 return oldneurocount;}
1207
1208Neuro* Model::old_getNeuro(int i)
1209{calcOldNeuroCount();
1210return (i<oldneurocount)? (Neuro*)getNeuro(i) : (Neuro*)0;
1211}
1212
1213int Model::old_findNeuro(Neuro* n)
1214{calcOldNeuroCount();
1215return findNeuro(n);}
1216
1217Neuro *Model::old_addNewNeuro()
1218{
1219int count=old_getNeuroCount();
1220Neuro *nu=addNewNeuro();
1221nu->setClassName("N");
1222moveNeuro(nu->refno,oldneurocount);
1223oldneurocount=count+1;
1224return (Neuro*)nu;
1225}
1226#endif
1227
1228///////////////////////
1229
1230int Model::getNeuroCount() const
1231{return neurons.size();}
1232
1233Neuro* Model::getNeuro(int i) const
1234{return (Neuro*)neurons(i);}
1235
1236int Model::getConnectionCount() const
1237{
1238int n=0;
1239for(int i=0;i<getNeuroCount();i++)
1240        n+=getNeuro(i)->getInputCount();
1241return n;
1242}
1243
1244int Model::findNeuros(SList& result,
1245                          const char* classname,const Part* part,const Joint* joint)
1246{
1247Neuro *nu;
1248SString cn(classname);
1249int n0=result.size();
1250for(int i=0;nu=(Neuro*)neurons(i);i++)
1251        {
1252        if (part)
1253                if (nu->part != part) continue;
1254        if (joint)
1255                if (nu->joint != joint) continue;
1256        if (classname)
1257                if (nu->getClassName() != cn) continue;
1258        result+=(void*)nu;
1259        }
1260return result.size()-n0;
1261}
1262
1263///////////////////
1264
1265void Model::disturb(double amount)
1266{
1267int i;
1268if (amount<=0) return;
1269for(i=0;i<parts.size();i++)
1270        {
1271        Part *p=getPart(i);
1272        p->p.x+=(rnd01-0.5)*amount;
1273        p->p.y+=(rnd01-0.5)*amount;
1274        p->p.z+=(rnd01-0.5)*amount;
1275        }
1276for(i=0;i<joints.size();i++)
1277        {
1278        Joint *j=getJoint(i);
1279        Pt3D tmpp(j->part2->p);
1280        tmpp-=j->part1->p;
1281        j->d=j->part2->o.revTransform(tmpp);
1282        }
1283}
1284
1285void Model::move(const Pt3D& shift)
1286{
1287FOREACH(Part*,p,parts)
1288        p->p+=shift;
1289}
1290
1291void Model::rotate(const Orient& rotation)
1292{
1293FOREACH(Part*,p,parts)
1294        {
1295        p->p=rotation.transform(p->p);
1296        p->setOrient(rotation.transform(p->o));
1297        }
1298}
1299
1300void Model::buildUsingNewShapes(const Model& old, Part::Shape default_shape, float thickness)
1301{
1302for(int i=0;i<old.getJointCount();i++)
1303        {
1304        Joint *oj=old.getJoint(i);
1305        Part *p = addNewPart(default_shape);
1306        p->p=(oj->part1->p+oj->part2->p)/2;
1307        Orient o;
1308        o.lookAt(oj->part1->p-oj->part2->p);
1309        p->rot=o.getAngles();
1310        p->scale.x=oj->part1->p.distanceTo(oj->part2->p)/2;
1311        p->scale.y = thickness;
1312        p->scale.z = thickness;
1313        }
1314for(int i=0;i<old.getPartCount();i++)
1315        {
1316        Part *op=old.getPart(i);
1317        for(int j=0;j<old.getJointCount();j++)
1318                {
1319                Joint *oj=old.getJoint(j);
1320                if ((oj->part1==op)||(oj->part2==op))
1321                        {
1322                        for(int j2=j+1;j2<old.getJointCount();j2++)
1323                                {
1324                                Joint *oj2=old.getJoint(j2);
1325                                if ((oj2->part1==op)||(oj2->part2==op))
1326                                        {
1327                                        addNewJoint(getPart(j),getPart(j2),Joint::SHAPE_SOLID);
1328                                        }
1329                                }
1330                        break;
1331                        }
1332                }
1333        }
1334}
1335
1336//////////////////////
1337
1338class MinPart: public Part {public: MinPart() {Param par(f0_part_paramtab,this);par.setMin();}};
1339class MaxPart: public Part {public: MaxPart() {Param par(f0_part_paramtab,this);par.setMax();}};
1340class MinJoint: public Joint {public: MinJoint() {Param par(f0_joint_paramtab,this);par.setMin();}};
1341class MaxJoint: public Joint {public: MaxJoint() {Param par(f0_joint_paramtab,this);par.setMax();}};
1342class MinNeuro: public Neuro {public: MinNeuro() {Param par(f0_neuro_paramtab,this);par.setMin();}};
1343class MaxNeuro: public Neuro {public: MaxNeuro() {Param par(f0_neuro_paramtab,this);par.setMax();}};
1344
1345Part& Model::getMinPart() {static MinPart part; return part;}
1346Part& Model::getMaxPart() {static MaxPart part; return part;}
1347Part& Model::getDefPart() {static Part part; return part;}
1348Joint& Model::getMinJoint() {static MinJoint joint; return joint;}
1349Joint& Model::getMaxJoint() {static MaxJoint joint; return joint;}
1350Joint& Model::getDefJoint() {static Joint joint; return joint;}
1351Neuro& Model::getMinNeuro() {static MinNeuro neuro; return neuro;}
1352Neuro& Model::getMaxNeuro() {static MaxNeuro neuro; return neuro;}
1353Neuro& Model::getDefNeuro() {static Neuro neuro; return neuro;}
Note: See TracBrowser for help on using the repository browser.