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

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