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

Last change on this file since 815 was 815, checked in by Maciej Komosinski, 18 months ago

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

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