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

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

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

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