// This file is a part of Framsticks SDK. http://www.framsticks.com/ // Copyright (C) 1999-2015 Maciej Komosinski and Szymon Ulatowski. // See LICENSE.txt for details. #include #include "model.h" #include #include #include Model::Model() { autobuildmaps=false; init(); } void Model::init() { partmappingchanged=0; buildstatus=empty; modelfromgenotype=0; startenergy=1.0; checklevel=1; #ifdef MODEL_V1_COMPATIBLE oldneurocount=-1; // == unknown oldconnections=0; #endif map=0; f0map=0; f0genoknown=1; shape=SHAPE_UNKNOWN; } void Model::moveElementsFrom(Model &source) { int i; open(); for (i=0;iattachToParts(oldj->part1->refno,oldj->part2->refno); }} {for (int i=0;ipart_refno>=0) n->attachToPart(oldn->part_refno); else n->attachToJoint(oldn->joint_refno); }} for (int i=0;igetInputCount();ni++) { double w; Neuro *oldinput=oldn->getInput(ni,w); SString info=n->getInputInfo(ni); n->addInput(getNeuro(oldinput->refno),w,&info); } } } } Model::Model(const Geno &src,bool buildmaps) :autobuildmaps(buildmaps) {init(src);} void Model::operator=(const Model &mod) { clear(); open(); internalCopy(mod); buildstatus=mod.buildstatus; } Model::Model(const Model &mod,bool buildmaps) :autobuildmaps(buildmaps) { init(); open(); internalCopy(mod); buildstatus=mod.buildstatus; } void Model::init(const Geno &src) { init(); modelfromgenotype=1; geno=src; build(); } void Model::resetAllDelta() { for (int i=0;iresetDelta(); } void Model::useAllDelta(bool yesno) { for (int i=0;iuseDelta(yesno); } Model::~Model() { delmodel_list.action((intptr_t)this); clear(); } void Model::clear() { FOREACH(Part*,p,parts) delete p; FOREACH(Joint*,j,joints) delete j; FOREACH(Neuro*,n,neurons) delete n; parts.clear(); joints.clear(); neurons.clear(); delMap(); delF0Map(); init(); geno=Geno(); f0geno=Geno(); } Part *Model::addPart(Part *p) { p->owner=this; p->refno=parts.size(); parts+=p; return p; } Joint *Model::addJoint(Joint *j) { j->owner=this; j->refno=joints.size(); joints+=j; return j; } Neuro *Model::addNeuro(Neuro *n) { n->owner=this; n->refno=neurons.size(); neurons+=n; return n; } void Model::removeNeuros(SList &nlist) { FOREACH(Neuro*,nu,nlist) { int i=findNeuro(nu); if (i>=0) removeNeuro(i); } } void Model::removePart(int partindex,int removeattachedjoints,int removeattachedneurons) { Part *p=getPart(partindex); if (removeattachedjoints) { SList jlist; findJoints(jlist,p); FOREACH(Joint*,j,jlist) { int i=findJoint(j); if (i>=0) removeJoint(i,removeattachedneurons); } } if (removeattachedneurons) { SList nlist; findNeuros(nlist,0,p); removeNeuros(nlist); } parts-=partindex; delete p; } void Model::removeJoint(int jointindex,int removeattachedneurons) { Joint *j=getJoint(jointindex); if (removeattachedneurons) { SList nlist; findNeuros(nlist,0,0,j); removeNeuros(nlist); } joints-=jointindex; delete j; } void Model::removeNeuro(int neuroindex,bool removereferences) { Neuro* thisN=getNeuro(neuroindex); if (removereferences) { Neuro* n; // remove all references to thisN for (int i=0;n=(Neuro*)neurons(i);i++) { Neuro *inp; for (int j=0;inp=n->getInput(j);j++) if (inp==thisN) { n->removeInput(j); j--; } } } neurons-=neuroindex; delete thisN; } MultiMap& Model::getMap() { if (!map) map=new MultiMap(); return *map; } void Model::delMap() { if (map) {delete map; map=0;} } void Model::delF0Map() { if (f0map) {delete f0map; f0map=0;} } void Model::makeGenToGenMap(MultiMap& result,const MultiMap& gen1tomodel,const MultiMap& gen2tomodel) { result.clear(); MultiMap m; m.addReversed(gen2tomodel); result.addCombined(gen1tomodel,m); } void Model::getCurrentToF0Map(MultiMap& result) { result.clear(); if (!map) return; const MultiMap& f0m=getF0Map(); makeGenToGenMap(result,*map,f0m); } void Model::rebuild(bool buildm) { autobuildmaps=buildm; clear(); build(); } void Model::initMap() { if (!map) map=new MultiMap(); else map->clear(); } void Model::initF0Map() { if (!f0map) f0map=new MultiMap(); else f0map->clear(); } void Model::build() { f0errorposition=-1; f0warnposition=-1; MultiMap *convmap=autobuildmaps ? new MultiMap() : NULL; f0geno=(geno.getFormat()=='0')? geno : geno.getConverted('0',convmap); f0genoknown=1; if (f0geno.isInvalid()) { buildstatus=invalid; if (convmap) delete convmap; return; } SString f0txt=f0geno.getGene(); buildstatus=building; // was: open(); if (autobuildmaps) { partmappingchanged=0; initMap(); initF0Map(); } int pos=0,lnum=1,lastpos=0; SString line; MultiRange frommap; LoggerToMemory mh(LoggerBase::Enable | LoggerBase::DontBlock); for (;f0txt.getNextToken(pos,line,'\n');lnum++) { if (autobuildmaps) { frommap.clear(); frommap.add(lastpos,pos-1); } mh.reset(); if (singleStepBuild(line,autobuildmaps ? (&frommap) : 0)==-1) { buildstatus=invalid; logPrintf("Model","build",LOG_ERROR, geno.getName().len()?"illegal f0 code at line %d (%s)":"illegal f0 code at line %d", lnum,geno.getName().c_str()); f0errorposition=lastpos; if (convmap) delete convmap; return; } if (mh.getWarningCount()) {if (f0warnposition<0) f0warnposition=lastpos;} lastpos=pos; } mh.disable(); close(); if (convmap) { *f0map=*map; if (geno.getFormat()!='0') { MultiMap tmp; tmp.addCombined(*convmap,getMap()); *map=tmp; } delete convmap; } } const MultiMap& Model::getF0Map() { if (!f0map) { f0map=new MultiMap(); makeGeno(f0geno,f0map); f0genoknown=1; } return *f0map; } Geno Model::rawGeno() { Geno tmpgen; makeGeno(tmpgen); return tmpgen; } void Model::makeGeno(Geno &g,MultiMap *map,bool handle_defaults) { if ((buildstatus!=valid)&&(buildstatus!=building)) { g=Geno(0,0,0,"invalid model"); return; } SString gen; Param modelparam(f0_model_paramtab); Param partparam(f0_part_paramtab); Param jointparam(f0_joint_paramtab); Param neuroparam(f0_neuro_paramtab); Param connparam(f0_neuroconn_paramtab); static Part defaultpart; static Joint defaultjoint; static Neuro defaultneuro; static Model defaultmodel; static NeuroConn defaultconn; //static NeuroItem defaultneuroitem; Part *p; Joint *j; Neuro *n; int i; int len; int a,b; //NeuroItem *ni; SString mod_props; modelparam.select(this); modelparam.save2(mod_props,handle_defaults ? &defaultmodel : NULL,true,!handle_defaults); if (mod_props.len()>0) //are there any non-default values? { gen+="m:"; gen+=mod_props; } for (i=0;p=(Part*)parts(i);i++) { partparam.select(p); len=gen.len(); gen+="p:"; partparam.save2(gen,handle_defaults ? &defaultpart : NULL,true,!handle_defaults); if (map) map->add(len,gen.len()-1,partToMap(i)); } for (i=0;j=(Joint*)joints(i);i++) { jointparam.select(j); len=gen.len(); jointparam.setParamTab(j->usedelta?f0_joint_paramtab:f0_nodeltajoint_paramtab); gen+="j:"; jointparam.save2(gen,handle_defaults ? &defaultjoint : NULL,true,!handle_defaults); if (map) map->add(len,gen.len()-1,jointToMap(i)); } for (i=0;n=(Neuro*)neurons(i);i++) { neuroparam.select(n); len=gen.len(); gen+="n:"; neuroparam.save2(gen,handle_defaults ? &defaultneuro : NULL,true,!handle_defaults); if (map) map->add(len,gen.len()-1,neuroToMap(i)); } for (a=0;agetInputCount()==1)&&(n->getInput(0).refno <= n->refno)) // continue; // already done with Neuro::conn_refno for (b=0;bgetInputCount();b++) { double w; NeuroConn nc; Neuro* n2=n->getInput(b,w); // if (((n2.parentcount==1)&&(n2.parent)&&(n2.parent->refno < n2.refno)) ^ // (n2.neuro_refno>=0)) // printf("!!!! bad Neuro::neuro_refno ?!\n"); // if ((n2.parentcount==1)&&(n2.parent)&&(n2.parent->refno < n2.refno)) // if (n2.neuro_refno>=0) // continue; // already done with Neuro::neuro_refno nc.n1_refno=n->refno; nc.n2_refno=n2->refno; nc.weight=w; SString **s=n->inputInfo(b); if ((s)&&(*s)) nc.info=**s; connparam.select(&nc); len=gen.len(); gen+="c:"; connparam.save2(gen,handle_defaults ? &defaultconn : NULL,true,!handle_defaults); if (map) map->add(len,gen.len()-1,neuroToMap(n->refno)); } } g=Geno(gen.c_str(),'0'); } ////////////// void Model::open() { if (buildstatus==building) return; buildstatus=building; modelfromgenotype=0; partmappingchanged=0; f0genoknown=0; delMap(); } void Model::checkpoint() {} void Model::setGeno(const Geno& newgeno) { geno=newgeno; } void Model::clearMap() { Part *p; Joint *j; Neuro *n; int i; delMap(); delF0Map(); for (i=0;p=(Part*)parts(i);i++) p->clearMapping(); for (i=0;j=(Joint*)joints(i);i++) j->clearMapping(); for (i=0;n=(Neuro*)neurons(i);i++) n->clearMapping(); } int Model::close() { if (buildstatus!=building) logPrintf("Model","close",LOG_WARN,"unexpected close() - no open()"); if (internalcheck(1)>0) { buildstatus=valid; if (partmappingchanged) { getMap(); Part *p; Joint *j; Neuro *n; int i; for (i=0;p=(Part*)parts(i);i++) if (p->getMapping()) map->add(*p->getMapping(),partToMap(i)); for (i=0;j=(Joint*)joints(i);i++) if (j->getMapping()) map->add(*j->getMapping(),jointToMap(i)); for (i=0;n=(Neuro*)neurons(i);i++) if (n->getMapping()) map->add(*n->getMapping(),neuroToMap(i)); } } else buildstatus=invalid; return (buildstatus==valid); } int Model::validate() { return internalcheck(0); } Pt3D Model::whereDelta(const Part& start,const Pt3D& rot, const Pt3D& delta) { Orient roto; roto=rot; Orient o; roto.transform(o,start.o); //o.x=start.o/roto.x; //o.y=start.o/roto.y; //o.z=start.o/roto.z; return o.transform(delta)+start.p; } int Model::singleStepBuild(const SString &line,const MultiRange* srcrange) { int pos=0; const char*t=line.c_str(); for (;*t;t++,pos++) if (!strchr(" \r\t",*t)) break; if (*t=='#') return 0; if (!*t) return 0; if (!strncmp(t,"p:",2)) { Param partparam(f0_part_paramtab); Part *p=new Part(); partparam.select(p); pos+=2; partparam.load2(line,pos); p->o.rotate(p->rot); parts+=p; p->owner=this; if (srcrange) p->setMapping(*srcrange); return getPartCount()-1; } if (!strncmp(t,"m:",2)) { Param modelparam(f0_model_paramtab); modelparam.select(this); pos+=2; modelparam.load2(line,pos); return 0; } else if (!strncmp(t,"j:",2)) { Param jointparam(f0_joint_paramtab); Joint *j=new Joint(); jointparam.select(j); pos+=2; j->owner=this; jointparam.load2(line,pos); if ((j->p1_refno>=0)&&(j->p1_refnop2_refno>=0)&&(j->p2_refnod.x != JOINT_DELTA_MARKER) || (j->d.y != JOINT_DELTA_MARKER) || (j->d.z != JOINT_DELTA_MARKER)) { j->useDelta(1); j->resetDeltaMarkers(); } j->attachToParts(j->p1_refno,j->p2_refno); if (srcrange) j->setMapping(*srcrange); return j->refno; } else { delete j; logPrintf("Model","build",LOG_ERROR, "invalid part reference for joint #%d",getJointCount()-1); return -1; } } else if (!strncmp(t,"n:",2)) // neuro (or the old neuro object as the special case) { Param neuroparam(f0_neuro_paramtab); Neuro *nu=new Neuro(); neuroparam.select(nu); pos+=2; neuroparam.load2(line,pos); #ifdef MODEL_V1_COMPATIBLE if (nu->neuro_refno>=0) // parent specified... { if (nu->neuro_refno >= getNeuroCount()) // and it's illegal { delete nu; return -1; } Neuro *parentNU=getNeuro(nu->neuro_refno); parentNU->addInput(nu,nu->weight); // default class for parented units: n-n link //if (nu->moredata.len()==0) nu->moredata="-"; } else #endif { // default class for unparented units: standard neuron if (nu->getClassName().len()==0) nu->setClassName("N"); } /* if (nu->conn_refno>=0) // input specified... { if (nu->conn_refno >= getNeuroCount()) // and it's illegal { delete nu; return -1; } Neuro *inputNU=getNeuro(nu->conn_refno); nu->addInput(inputNU,nu->weight); } */ #ifdef MODEL_V1_COMPATIBLE nu->weight=1.0; #endif nu->owner=this; // attach to part/joint if (nu->part_refno>=0) nu->attachToPart(nu->part_refno); if (nu->joint_refno>=0) nu->attachToJoint(nu->joint_refno); if (srcrange) nu->setMapping(*srcrange); // todo: check part/joint ref# #ifdef MODEL_V1_COMPATIBLE if (hasOldNeuroLayout()) { int count=old_getNeuroCount(); neurons.insert(count,nu); oldneurocount=count+1; return oldneurocount-1; } else #endif { neurons+=nu; return neurons.size()-1; } } else if (!strncmp(t,"c:",2)) // add input { Param ncparam(f0_neuroconn_paramtab); NeuroConn c; ncparam.select(&c); pos+=2; ncparam.load2(line,pos); if ((c.n1_refno>=0)&&(c.n1_refno=0)&&(c.n2_refnoaddInput(nb,c.weight,&c.info); if (srcrange) na->addMapping(*srcrange); return 0; } logPrintf("Model","build",LOG_ERROR, "invalid neuron connection #%d <- #%d",c.n1_refno,c.n2_refno); return -1; } #ifdef MODEL_V1_COMPATIBLE else if (!strncmp(t,"ni:",3)) // old neuroitem { // we always use old layout for "ni:" Param neuroitemparam(f0_neuroitem_paramtab); Neuro *nu=new Neuro(); neuroitemparam.select(nu); pos+=3; neuroitemparam.load2(line,pos); // illegal parent? if ((nu->neuro_refno<0)||(nu->neuro_refno>=old_getNeuroCount())) { delete nu; return -1; } Neuro *parentN=getNeuro(nu->neuro_refno); // copy part/joint refno from parent, if possible if ((nu->part_refno<0)&&(parentN->part_refno>=0)) nu->part_refno=parentN->part_refno; if ((nu->joint_refno<0)&&(parentN->joint_refno>=0)) nu->joint_refno=parentN->joint_refno; nu->owner=this; // attach to part/joint if (nu->part_refno>=0) nu->attachToPart(nu->part_refno); if (nu->joint_refno>=0) nu->attachToJoint(nu->joint_refno); if (srcrange) nu->setMapping(*srcrange); // special case: old muscles // PARENT neuron will be set up to be the CHILD of the current one (!) if (nu->isOldEffector()) { nu->neuro_refno=parentN->refno; neurons+=nu; nu->owner=this; nu->addInput(parentN,nu->weight); // (!) nu->weight=1.0; parentN->invalidateOldItems(); return 0; // !!! -> ...getItemCount()-1; } parentN->addInput(nu,nu->weight); neurons+=nu; parentN->invalidateOldItems(); if (nu->getClassName().len()==0) { nu->setClassName("-"); // for compatibility, "ni" can define a n-n connection // referring to non-existent neuron (which will be hopefully defined later) // internal check will add the proper input to this unit // if conn_refno >=0 and input count==0 oldconnections=1; if (srcrange) parentN->addMapping(*srcrange); } else nu->weight=1.0; return 0; // !!! -> ...getItemCount()-1; } #endif else return -1; } #ifdef MODEL_V1_COMPATIBLE int Model::addOldConnectionsInputs() { if (!oldconnections) return 1; Neuro* n; for (int i=0;iconn_refno>=0) if (n->isNNConnection()) if (n->conn_refno < old_getNeuroCount()) { // good reference Neuro* parent=n->parent; // nn connection has exactly one parent int inp=parent->findInput(n); Neuro* target=getNeuro(n->conn_refno); parent->setInput(inp,target,n->weight); removeNeuro(i,0); // no need to remove references i--; } else { logPrintf("Model","internalCheck",LOG_ERROR, "illegal N-N connection #%d (reference to #%d) (%s)", i,n->conn_refno,(const char*)geno.getName()); return 0; } } oldconnections=0; return 1; } #endif ///////////// /** change the sequence of neuro units and fix references in "-" objects (n-n connections) */ void Model::moveNeuro(int oldpos,int newpos) { if (oldpos==newpos) return; // nop! Neuro *n=getNeuro(oldpos); neurons-=oldpos; neurons.insert(newpos,n); // conn_refno could be broken -> fix it #ifdef MODEL_V1_COMPATIBLE for (int i=0;iisNNConnection()) if (n2->conn_refno == oldpos) n2->conn_refno=newpos; else { if (n2->conn_refno > oldpos) n2->conn_refno--; if (n2->conn_refno >= newpos) n2->conn_refno++; } } invalidateOldNeuroCount(); #endif } #ifdef MODEL_V1_COMPATIBLE /** move all old neurons (class "N") to the front of the neurons list. @return number of old neurons */ int Model::reorderToOldLayout() { Neuro *n; int neurocount=0; for (int i=0;iisOldNeuron()) { moveNeuro(i,neurocount); neurocount++; i=neurocount-1; } } return neurocount; } #endif //////////// void Model::updateNeuroRefno() { for (int i=0;irefno=i; } } #define VALIDMINMAX(var,template,field) \ if (var -> field < getMin ## template () . field) \ { var->field= getMin ## template () . field; \ logPrintf("Model","internalCheck",LOG_WARN,# field " too small in " # template "#%d (adjusted)",i);} \ else if (var -> field > getMax ## template () . field) \ { var->field= getMax ## template () . field; \ logPrintf("Model","internalCheck",LOG_WARN,# field " too big in " # template "#%d (adjusted)",i);} #define LINKFLAG 0x8000000 void Model::updateRefno() { int i; for (i=0;irefno=i; for (i=0;irefno=i; for (i=0;irefno=i; } int Model::internalcheck(int final) { Part *p; Joint *j; Neuro *n; int i,k; int ret=1; shape=SHAPE_UNKNOWN; if ((parts.size()==0)&&(neurons.size()==0)) return 0; if (parts.size()==0) size=Pt3D_0; else { Pt3D bbmin=((Part*)parts(0))->p, bbmax=bbmin; for (i=0;iowner=this; p->refno=i; if (p->shape==0) { if (checklevel>0) p->mass=0.0; } // VALIDMINMAX(p,part,mass); VALIDMINMAX(p,Part,size); VALIDMINMAX(p,Part,density); VALIDMINMAX(p,Part,friction); VALIDMINMAX(p,Part,ingest); VALIDMINMAX(p,Part,assim); p->flags&=~LINKFLAG; // for delta joint cycle detection if (p->p.x-p->size < bbmin.x) bbmin.x=p->p.x-p->size; if (p->p.y-p->size < bbmin.y) bbmin.y=p->p.y-p->size; if (p->p.z-p->size < bbmin.z) bbmin.z=p->p.z-p->size; if (p->p.x+p->size > bbmax.x) bbmax.x=p->p.x+p->size; if (p->p.y+p->size > bbmax.y) bbmax.y=p->p.y+p->size; if (p->p.z+p->size > bbmax.z) bbmax.z=p->p.z+p->size; if (shape==SHAPE_UNKNOWN) shape=(p->shape==Part::SHAPE_DEFAULT)?SHAPE_OLD:SHAPE_NEW; else if (shape!=SHAPE_ILLEGAL) { if ((p->shape==Part::SHAPE_DEFAULT) ^ (shape==SHAPE_OLD)) { shape=SHAPE_ILLEGAL; logPrintf("Model","internalCheck",LOG_WARN,"Inconsistent part shapes (mixed old and new shapes)"); } } } size=bbmax-bbmin; for (i=0;irefno=i; j->owner=this; if (j->part1 && j->part2 && (j->part1 != j->part2)) { j->p1_refno=j->part1->refno; j->p2_refno=j->part2->refno; if (checklevel>0) { if (j->part1->shape==0) j->part1->mass+=1.0; if (j->part2->shape==0) j->part2->mass+=1.0; } if ((j->usedelta)&&((j->d.x!=JOINT_DELTA_MARKER)||(j->d.y!=JOINT_DELTA_MARKER)||(j->d.z!=JOINT_DELTA_MARKER))) { // delta positioning -> calc. orient. if (j->part2->flags & LINKFLAG) { ret=0; logPrintf("Model","internalCheck",LOG_ERROR, "delta joint cycle detected at joint#%d (%s)", i,geno.getName().c_str()); } j->resetDeltaMarkers(); j->o=j->rot; j->part1->o.transform(j->part2->o,j->o); // j->part2->o.x=j->part1->o/j->o.x; // j->part2->o.y=j->part1->o/j->o.y; // j->part2->o.z=j->part1->o/j->o.z; j->part2->p=j->part2->o.transform(j->d)+j->part1->p; j->part2->flags|=LINKFLAG; j->part1->flags|=LINKFLAG; // for delta joint cycle detection } else { // abs.positioning -> calc. delta if (final) { // calc orient delta // Orient tmpo(j->part2->o); // tmpo*=j->part1->o; Orient tmpo; j->part1->o.revTransform(tmpo,j->part2->o); tmpo.getAngles(j->rot); j->o=j->rot; // calc position delta Pt3D tmpp(j->part2->p); tmpp-=j->part1->p; j->d=j->part2->o.revTransform(tmpp); } } if (final) { if (j->shape!=Joint::SHAPE_SOLID) { if (j->d()>getMaxJoint().d.x) { ret=0; logPrintf("Model","internalCheck",LOG_ERROR,"delta too big in joint #%d (%s)", i,geno.getName().c_str()); } else if (j->d()shape==Joint::SHAPE_DEFAULT) ^ (shape==SHAPE_OLD)) { shape=SHAPE_ILLEGAL; logPrintf("Model","internalCheck",LOG_WARN,"Inconsistent joint shapes (mixed old and new shapes)"); } } } } #ifdef MODEL_V1_COMPATIBLE if (!addOldConnectionsInputs()) return 0; #endif updateNeuroRefno(); // valid refno is important for n-n connections check (later) for (i=0;iconn_refno=-1; n->weight=1.0; n->neuro_refno=-1; #endif n->part_refno=(n->part)?n->part->refno:-1; n->joint_refno=(n->joint)?n->joint->refno:-1; } if (parts.size()&&(checklevel>0)) { for (i=0;ishape==0) if (p->mass<=0.001) p->mass=1.0; p->flags&=~LINKFLAG; } getPart(0)->flags|=LINKFLAG; int change=1; while(change) { change=0; for (i=0;ipart1->flags&LINKFLAG) { if (!(j->part2->flags&LINKFLAG)) { change=1; j->part2->flags|=LINKFLAG; } } else if (j->part2->flags&LINKFLAG) { if (!(j->part1->flags&LINKFLAG)) { change=1; j->part1->flags|=LINKFLAG; } } } } for (i=0;iflags&LINKFLAG)) { logPrintf("Model","internalCheck",LOG_ERROR,"not all parts connected (eg.#0-#%d) (%s)", i,geno.getName().c_str()); ret=0; break; } } } for (i=0;ip1_refno==j->p2_refno) { logPrintf("Model","internalCheck",LOG_ERROR,"illegal self connection, joint #%d (%s)", i,geno.getName().c_str()); ret=0; break; } for (k=i+1;kp1_refno==j2->p1_refno)&&(j->p2_refno==j2->p2_refno)) || ((j->p1_refno==j2->p2_refno)&&(j->p2_refno==j2->p1_refno))) { logPrintf("Model","internalCheck",LOG_ERROR,"illegal duplicate joints #%d and #%d (%s)", i,k,geno.getName().c_str()); ret=0; break; } } } if (shape==SHAPE_ILLEGAL) ret=0; return ret; } ///////////// int Model::getErrorPosition(bool includingwarnings) { return includingwarnings? ((f0errorposition>=0) ? f0errorposition : f0warnposition) : f0errorposition; } const Geno& Model::getGeno() const { return geno; } const Geno Model::getF0Geno() { if (buildstatus==building) logPrintf("Model","getGeno",LOG_WARN,"model was not completed - missing close()"); if (buildstatus!=valid) return Geno("",'0',"","invalid"); if (!f0genoknown) { if (autobuildmaps) { initF0Map(); makeGeno(f0geno,f0map); } else { delF0Map(); makeGeno(f0geno); } f0genoknown=1; } return f0geno; } int Model::getPartCount() const { return parts.size(); } Part* Model::getPart(int i) const { return ((Part*)parts(i)); } int Model::getJointCount() const { return joints.size(); } Joint* Model::getJoint(int i) const { return ((Joint*)joints(i)); } int Model::findJoints(SList& result,const Part* part) { Joint *j; int n0=result.size(); if (part) for(int i=0;j=(Joint*)joints(i);i++) if ((j->part1 == part) || (j->part2 == part)) result+=(void*)j; return result.size()-n0; } int Model::findNeuro(Neuro* n) {return neurons.find(n);} int Model::findPart(Part* p) {return parts.find(p);} int Model::findJoint(Joint* j) {return joints.find(j);} int Model::findJoint(Part *p1, Part *p2) { Joint* j; for(int i=0;j=getJoint(i);i++) if ((j->part1==p1)&&(j->part2==p2)) return i; return -1; } //////////////////// #ifdef MODEL_V1_COMPATIBLE void Model::calcOldNeuroCount() { if (oldneurocount>=0) return; oldneurocount=reorderToOldLayout(); } int Model::old_getNeuroCount() { calcOldNeuroCount(); return oldneurocount;} Neuro* Model::old_getNeuro(int i) {calcOldNeuroCount(); return (isetClassName("N"); moveNeuro(nu->refno,oldneurocount); oldneurocount=count+1; return (Neuro*)nu; } #endif /////////////////////// int Model::getNeuroCount() const {return neurons.size();} Neuro* Model::getNeuro(int i) const {return (Neuro*)neurons(i);} int Model::getConnectionCount() const { int n=0; for(int i=0;igetInputCount(); return n; } int Model::findNeuros(SList& result, const char* classname,const Part* part,const Joint* joint) { Neuro *nu; SString cn(classname); int n0=result.size(); for(int i=0;nu=(Neuro*)neurons(i);i++) { if (part) if (nu->part != part) continue; if (joint) if (nu->joint != joint) continue; if (classname) if (nu->getClassName() != cn) continue; result+=(void*)nu; } return result.size()-n0; } /////////////////// void Model::disturb(double amount) { int i; if (amount<=0) return; for(i=0;ip.x+=(rnd01-0.5)*amount; p->p.y+=(rnd01-0.5)*amount; p->p.z+=(rnd01-0.5)*amount; } for(i=0;ipart2->p); tmpp-=j->part1->p; j->d=j->part2->o.revTransform(tmpp); } } void Model::move(const Pt3D& shift) { FOREACH(Part*,p,parts) p->p+=shift; } void Model::rotate(const Orient& rotation) { FOREACH(Part*,p,parts) { p->p=rotation.transform(p->p); p->setOrient(rotation.transform(p->o)); } } void Model::buildUsingNewShapes(const Model& old, Part::Shape default_shape, float thickness) { for(int i=0;ip=(oj->part1->p+oj->part2->p)/2; Orient o; o.lookAt(oj->part1->p-oj->part2->p); p->rot=o.getAngles(); p->scale.x=oj->part1->p.distanceTo(oj->part2->p)/2; p->scale.y = thickness; p->scale.z = thickness; } for(int i=0;ipart1==op)||(oj->part2==op)) { for(int j2=j+1;j2part1==op)||(oj2->part2==op)) { addNewJoint(getPart(j),getPart(j2),Joint::SHAPE_SOLID); } } break; } } } } ////////////////////// class MinPart: public Part {public: MinPart() {Param par(f0_part_paramtab,this);par.setMin();}}; class MaxPart: public Part {public: MaxPart() {Param par(f0_part_paramtab,this);par.setMax();}}; class MinJoint: public Joint {public: MinJoint() {Param par(f0_joint_paramtab,this);par.setMin();}}; class MaxJoint: public Joint {public: MaxJoint() {Param par(f0_joint_paramtab,this);par.setMax();}}; class MinNeuro: public Neuro {public: MinNeuro() {Param par(f0_neuro_paramtab,this);par.setMin();}}; class MaxNeuro: public Neuro {public: MaxNeuro() {Param par(f0_neuro_paramtab,this);par.setMax();}}; Part& Model::getMinPart() {static MinPart part; return part;} Part& Model::getMaxPart() {static MaxPart part; return part;} Part& Model::getDefPart() {static Part part; return part;} Joint& Model::getMinJoint() {static MinJoint joint; return joint;} Joint& Model::getMaxJoint() {static MaxJoint joint; return joint;} Joint& Model::getDefJoint() {static Joint joint; return joint;} Neuro& Model::getMinNeuro() {static MinNeuro neuro; return neuro;} Neuro& Model::getMaxNeuro() {static MaxNeuro neuro; return neuro;} Neuro& Model::getDefNeuro() {static Neuro neuro; return neuro;}