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

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

Use double for consistency (using float to store double value of 0.2 would cause imprecision when 0.2f becomes 0.2 in Part shape properties)

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