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

Last change on this file since 955 was 955, checked in by Maciej Komosinski, 4 years ago

Genetic format ID becomes a string (no longer limited to a single character)

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