Ignore:
Timestamp:
08/18/17 15:24:59 (4 years ago)
Author:
Maciej Komosinski
Message:

Unified property names of f1 and f4; improved docs; 3.141 -> M_PI

File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpp/frams/genetics/f1/conv_f1.cpp

    r534 r671  
    11// This file is a part of Framsticks SDK.  http://www.framsticks.com/
    2 // Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
     2// Copyright (C) 1999-2017  Maciej Komosinski and Szymon Ulatowski.
    33// See LICENSE.txt for details.
    44
     
    1010#include <ctype.h>
    1111
    12 //#define v1f1COMPATIBLE
    13 
    14 F1Props stdprops={1, 0, 1, 0.4, 0.25, 0.25, 0.25, 0.25, 0.0, 1.0, 1.0, 1,
    15                  0.2, 0.5,0.5,0.5 };
     12//#define v1f1COMPATIBLE //as in ancient Framsticks 1.x
     13
     14F1Props stdprops = { 1, 0, 1, 0.4, 0.25, 0.25, 0.25, 0.25, 0.0, 1.0, 1.0, 1,
     15        0.2, 0.5, 0.5, 0.5 };
    1616
    1717class Builder
    1818{
    1919public:
    20 Builder(const char*g,int mapping=0):invalid(0),genbegin(g),usemapping(mapping),first_part_mapping(NULL),energ(0),energ_div(0) {}
    21 ~Builder() {SAFEDELETE(first_part_mapping);}
    22 char tmp[222];
    23 bool invalid;
    24 Model model;
    25 const char *genbegin;
    26 SList neuro_f1_to_f0; // neuro_f1_to_f0(f1_refno) = actual neuro pointer
    27 Neuro *last_f1_neuro;
    28 SyntParam *neuro_cls_param;
    29 
    30 struct Connection { int n1,n2; double w;
    31 Connection(int _n1,int _n2, double _w):n1(_n1),n2(_n2),w(_w) {} };
    32 
    33 SListTempl<Connection> connections;
    34 int usemapping;
    35 MultiRange range;
    36 MultiRange *first_part_mapping;
    37 double lastjoint_muscle_power;
    38 double energ,energ_div;
    39 void grow(int part1,const char*g,Pt3D k,F1Props c);
    40 void setPartMapping(int p,const char* g);
    41 int growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g);
    42 int growPart(F1Props &c,const char *g);
    43 const char *skipNeuro(const char *z);
    44 const char* growNeuro(const char* t,F1Props &c,int&);
    45 void growConnection(const char* begin,const char* colon,const char* end,F1Props& props);
    46 int countBranches(const char*g,SList &out);
    47 SyntParam* lastNeuroClassParam();
    48 void addClassParam(const char* name,double value);
    49 void addClassParam(const char* name,const char* value);
    50 
    51 const MultiRange* makeRange(const char*g) {return makeRange(g,g);}
    52 const MultiRange* makeRange(const char*g,const char*g2);
    53 Part *getLastPart() {return getLastJoint()->part2;}
    54 Neuro *getLastNeuro() {return model.getNeuro(model.getNeuroCount()-1);}
    55 Joint *getLastJoint() {return model.getJoint(model.getJointCount()-1);}
    56 void addOrRememberInput(int n1,int n2,double w)
    57                 {
     20        Builder(const char*g, int mapping = 0) :invalid(0), genbegin(g), usemapping(mapping), first_part_mapping(NULL), model_energy(0), model_energy_max(0) {}
     21        ~Builder() { SAFEDELETE(first_part_mapping); }
     22        char tmp[222];
     23        bool invalid;
     24        Model model;
     25        const char *genbegin;
     26        SList neuro_f1_to_f0; // neuro_f1_to_f0(f1_refno) = actual neuro pointer
     27        Neuro *last_f1_neuro;
     28        SyntParam *neuro_cls_param;
     29
     30        struct Connection
     31        {
     32                int n1, n2; double w;
     33                Connection(int _n1, int _n2, double _w) :n1(_n1), n2(_n2), w(_w) {}
     34        };
     35
     36        SListTempl<Connection> connections;
     37        int usemapping;
     38        MultiRange range;
     39        MultiRange *first_part_mapping;
     40        double lastjoint_muscle_power;
     41        double model_energy, model_energy_max;
     42        void grow(int part1, const char*g, Pt3D k, F1Props c);
     43        void setPartMapping(int p, const char* g);
     44        int growJoint(int part1, int part2, Pt3D &angle, F1Props &c, const char *g);
     45        int growPart(F1Props &c, const char *g);
     46        const char *skipNeuro(const char *z);
     47        const char* growNeuro(const char* t, F1Props &c, int&);
     48        void growConnection(const char* begin, const char* colon, const char* end, F1Props& props);
     49        int countBranches(const char*g, SList &out);
     50        SyntParam* lastNeuroClassParam();
     51        void addClassParam(const char* name, double value);
     52        void addClassParam(const char* name, const char* value);
     53
     54        const MultiRange* makeRange(const char*g) { return makeRange(g, g); }
     55        const MultiRange* makeRange(const char*g, const char*g2);
     56        Part *getLastPart() { return getLastJoint()->part2; }
     57        Neuro *getLastNeuro() { return model.getNeuro(model.getNeuroCount() - 1); }
     58        Joint *getLastJoint() { return model.getJoint(model.getJointCount() - 1); }
     59        void addOrRememberInput(int n1, int n2, double w)
     60        {
    5861                //if (!addInput(n1,n2,w,false))
    59                 connections+=Connection(n1,n2,w);
    60                 }
    61 bool addInput(int n1,int n2,double w,bool final)
    62                 {
    63                 if ((n1<0) || (n2<0) || (n1>=neuro_f1_to_f0.size()) || (n2>=neuro_f1_to_f0.size()))
    64                         {
    65                         if (final) logPrintf("GenoConvF1","addInput",LOG_WARN,
    66                                             "illegal neuron connection %d <- %d (ignored)",n1,n2);
     62                connections += Connection(n1, n2, w);
     63        }
     64        bool addInput(int n1, int n2, double w, bool final)
     65        {
     66                if ((n1 < 0) || (n2 < 0) || (n1 >= neuro_f1_to_f0.size()) || (n2 >= neuro_f1_to_f0.size()))
     67                {
     68                        if (final) logPrintf("GenoConvF1", "addInput", LOG_WARN,
     69                                "illegal neuron connection %d <- %d (ignored)", n1, n2);
    6770                        return 0;
    68                         }
    69                 Neuro *neuro=(Neuro*)neuro_f1_to_f0(n1);
    70                 Neuro *input=(Neuro*)neuro_f1_to_f0(n2);
    71                 neuro->addInput(input,w);
     71                }
     72                Neuro *neuro = (Neuro*)neuro_f1_to_f0(n1);
     73                Neuro *input = (Neuro*)neuro_f1_to_f0(n2);
     74                neuro->addInput(input, w);
    7275                return 1;
    73                 }
    74 void addPendingInputs()
    75                 {
    76                 for(int i=0;i<connections.size();i++)
    77                         {
    78                         Connection *c=&connections(i);
    79                         addInput(c->n1,c->n2,c->w,true);
    80                         }
    81                 }
     76        }
     77        void addPendingInputs()
     78        {
     79                for (int i = 0; i < connections.size(); i++)
     80                {
     81                        Connection *c = &connections(i);
     82                        addInput(c->n1, c->n2, c->w, true);
     83                }
     84        }
    8285};
    8386
    84 const MultiRange* Builder::makeRange(const char*g,const char*g2)
    85 {
    86 if (!usemapping) return 0;
    87 range.clear();
    88 range.add(g-genbegin,g2-genbegin);
    89 return &range;
    90 }
    91 
    92 void F1Props::wykluczanie()
    93 {
    94 double s=ruch+asym+odpor+wchl;
    95 ruch=ruch/s;
    96 asym=asym/s;
    97 odpor=odpor/s;
    98 wchl=wchl/s;
     87const MultiRange* Builder::makeRange(const char*g, const char*g2)
     88{
     89        if (!usemapping) return 0;
     90        range.clear();
     91        range.add(g - genbegin, g2 - genbegin);
     92        return &range;
     93}
     94
     95void F1Props::normalizeBiol4()
     96{
     97        double sum = muscle_power + assimilation + stamina + ingestion;
     98        muscle_power /= sum;
     99        assimilation /= sum;
     100        stamina /= sum;
     101        ingestion /= sum;
    99102}
    100103
    101104/** main conversion function - with conversion map support */
    102 SString GenoConv_f1::convert(SString &i,MultiMap *map)
    103 {
    104 const char* g=i.c_str();
    105 Builder builder(g,map?1:0);
    106 builder.model.open();
    107 builder.grow(-1,g,Pt3D_0,stdprops); // uses Model::singleStepBuild to create model elements
    108 if (builder.invalid) return SString();
    109 builder.addPendingInputs();
    110 builder.model.startenergy=(builder.energ_div>0)?(builder.energ/builder.energ_div):1.0;
    111 builder.model.close(); // model is ready to use now
    112 if (map) builder.model.getCurrentToF0Map(*map); // generate f1-to-f0 conversion map
    113 return builder.model.getF0Geno().getGenes();
    114 }
    115 
    116 void Builder::setPartMapping(int p,const char* g)
    117 {
    118 if (!usemapping) return;
    119 const MultiRange *r=makeRange(g);
    120 if (p<0)
     105SString GenoConv_f1::convert(SString &i, MultiMap *map)
     106{
     107        const char* g = i.c_str();
     108        Builder builder(g, map ? 1 : 0);
     109        builder.model.open();
     110        builder.grow(-1, g, Pt3D_0, stdprops); // uses Model::singleStepBuild to create model elements
     111        if (builder.invalid) return SString();
     112        builder.addPendingInputs();
     113        builder.model.startenergy = (builder.model_energy_max > 0) ? (builder.model_energy / builder.model_energy_max) : 1.0;
     114        builder.model.close(); // model is ready to use now
     115        if (map) builder.model.getCurrentToF0Map(*map); // generate f1-to-f0 conversion map
     116        return builder.model.getF0Geno().getGenes();
     117}
     118
     119void Builder::setPartMapping(int p, const char* g)
     120{
     121        if (!usemapping) return;
     122        const MultiRange *r = makeRange(g);
     123        if (p < 0)
    121124        { //special case: mapping the part which is not yet created
    122         if (first_part_mapping) first_part_mapping->add(*r);
    123         else first_part_mapping=new MultiRange(*r);
    124         }
    125 else
    126         model.getPart(p)->addMapping(*r);
    127 }
    128 
    129 void Builder::grow(int part1,const char*g,Pt3D k,F1Props c)
    130 {
    131 int hasmuscles=0;
    132 k+=Pt3D(c.rot,0,c.skr);
    133 while(1)
    134 {
    135 switch(*g)
    136         {
    137         case 0: case ',': case ')': return;
    138         case 'R': k.x+=0.7853; setPartMapping(part1,g); break;
    139         case 'r': k.x-=0.7853;  setPartMapping(part1,g); break;
    140         case 'Q': c.rot+=(1.58-c.rot)*0.3; setPartMapping(part1,g); break;
    141         case 'q': c.rot+=(-1.58-c.rot)*0.3; setPartMapping(part1,g); break;
     125                if (first_part_mapping) first_part_mapping->add(*r);
     126                else first_part_mapping = new MultiRange(*r);
     127        }
     128        else
     129                model.getPart(p)->addMapping(*r);
     130}
     131
     132void Builder::grow(int part1, const char*g, Pt3D k, F1Props c)
     133{
     134        int hasmuscles = 0;
     135        k += Pt3D(c.twist, 0, c.curvedness);
     136        while (1)
     137        {
     138                switch (*g)
     139                {
     140                case 0: case ',': case ')': return;
     141                case 'R': k.x += 0.7853; setPartMapping(part1, g); break;
     142                case 'r': k.x -= 0.7853;        setPartMapping(part1, g); break;
     143                case 'Q': c.twist += (1.58 - c.twist)*0.3; setPartMapping(part1, g); break;
     144                case 'q': c.twist += (-1.58 - c.twist)*0.3; setPartMapping(part1, g); break;
    142145#ifdef v1f1COMPATIBLE
    143         case 'L': c.dlug+=(3.0-c.dlug)*0.3; setPartMapping(part1,g); break;
     146                case 'L': c.length += (3.0 - c.length)*0.3; setPartMapping(part1, g); break;
    144147#else
    145         case 'L': c.dlug+=(2.0-c.dlug)*0.3; setPartMapping(part1,g); break;
     148                case 'L': c.length += (2.0 - c.length)*0.3; setPartMapping(part1, g); break;
    146149#endif                                       
    147         case 'l': c.dlug+=(0.33-c.dlug)*0.3; setPartMapping(part1,g); break;
    148         case 'A': c.asym+=(1-c.asym)*0.8;       c.wykluczanie(); setPartMapping(part1,g);  break;
    149         case 'a': c.asym-=c.asym*0.4;   c.wykluczanie(); setPartMapping(part1,g); break;
    150         case 'I': c.wchl+=(1-c.wchl)*0.8;       c.wykluczanie(); setPartMapping(part1,g); break;
    151         case 'i': c.wchl-=c.wchl*0.4;   c.wykluczanie(); setPartMapping(part1,g); break;
    152         case 'S': c.odpor+=(1-c.odpor)*0.8; c.wykluczanie(); setPartMapping(part1,g); break;
    153         case 's': c.odpor-=c.odpor*0.4; c.wykluczanie(); setPartMapping(part1,g); break;
    154         case 'M': c.ruch+=(1-c.ruch)*0.8;       c.wykluczanie(); setPartMapping(part1,g); break;
    155         case 'm': c.ruch-=c.ruch*0.4;   c.wykluczanie(); setPartMapping(part1,g); break;
    156         case 'C': c.skr+=(2.0-c.skr)*0.25;      setPartMapping(part1,g); break;
    157         case 'c': c.skr+=(-2.0-c.skr)*0.25; setPartMapping(part1,g); break;
    158         case 'F': c.tarcie+=(4-c.tarcie)*0.2; setPartMapping(part1,g); break;
    159         case 'f': c.tarcie-=c.tarcie*0.2; setPartMapping(part1,g); break;
    160         case 'W': c.masa+=(2.0-c.masa)*0.3; setPartMapping(part1,g); break;
    161         case 'w': c.masa+=(0.5-c.masa)*0.3; setPartMapping(part1,g); break;
    162         case 'E': c.energ+=(10.0-c.energ)*0.1; setPartMapping(part1,g); break;
    163         case 'e': c.energ-=c.energ*0.1; setPartMapping(part1,g); break;
    164 
    165         case 'D': c.cred+=(1.0-c.cred)*0.25; setPartMapping(part1,g); break;
    166         case 'd': c.cred+=(0.0-c.cred)*0.25; setPartMapping(part1,g); break;
    167         case 'G': c.cgreen+=(1.0-c.cgreen)*0.25; setPartMapping(part1,g); break;
    168         case 'g': c.cgreen+=(0.0-c.cgreen)*0.25; setPartMapping(part1,g); break;
    169         case 'B': c.cblue+=(1.0-c.cblue)*0.25; setPartMapping(part1,g); break;
    170         case 'b': c.cblue+=(0.0-c.cblue)*0.25; setPartMapping(part1,g); break;
    171         case 'H': c.grub+=(0.7-c.grub)*0.25; setPartMapping(part1,g); break;
    172         case 'h': c.grub+=(0.05-c.grub)*0.25; setPartMapping(part1,g); break;
    173 
    174         case '[': //neuron
    175 //              setdebug(g-(char*)geny,DEBUGNEURO | !l_neu);
    176                 if (model.getJointCount())
    177                         g=growNeuro(g+1,c,hasmuscles);
    178                 else
    179                         {
    180                         logMessage("GenoConv_F1","grow",1,"Illegal neuron position (ignored)");
    181                         g=skipNeuro(g+1);
    182                         }
    183                 break;
    184         case 'X':
    185                 {
    186                 int freshpart=0;
    187 //setdebug(g-(char*)geny,DEBUGEST | !l_est);
    188                 if (part1<0) //initial grow
    189                         {
    190                   if (model.getPartCount()>0)
    191                             part1=0;
    192                     else
    193                             {
    194                             part1=growPart(c,g);
    195                             freshpart=1;
    196                             if (first_part_mapping)
    197                                     model.getPart(part1)->setMapping(*first_part_mapping);
    198                             }
    199                   }
    200                 if (!freshpart)
    201                         {
    202                         Part *part=model.getPart(part1);
    203                         part->density=((part->mass*part->density)+1.0/c.masa)/(part->mass+1.0); // v=m*d
    204 //                      part->volume+=1.0/c.masa;
    205                         part->mass+=1.0;
    206                         }
    207                 energ+=0.9*c.energ+0.1;
    208                 energ_div+=1.0;
    209 
    210                 int part2 = growPart(c,g);
    211                 growJoint(part1,part2,k,c,g);
    212 //              est* e = new est(*s,*s2,k,c,zz,this);
    213 
    214                 // oslabianie cech wzdluz struktury
    215                 c.dlug=0.5*c.dlug+0.5*stdprops.dlug;
    216                 c.grub=0.5*c.grub+0.5*stdprops.grub;
    217                 c.skr=0.66*c.skr;
    218                 c.rot=0.66*c.rot;
    219                 c.tarcie=0.8*c.tarcie+0.2*stdprops.tarcie;
    220 
    221                 c.asym=0.8*c.asym+0.2*stdprops.asym;
    222                 c.odpor=0.8*c.odpor+0.2*stdprops.odpor;
    223                 c.ruch=0.8*c.ruch+0.2*stdprops.ruch;
    224                 c.wchl=0.8*c.wchl+0.2*stdprops.wchl;
    225                 c.masa+=(stdprops.masa-c.masa)*0.5;
    226                 c.wykluczanie();
    227        
    228                 if (c.resetrange) c.bendrange=1.0; else c.resetrange=1;
    229                 grow(part2,g+1,Pt3D_0,c);
    230                 return;
    231                 }
    232         case '(':
    233                 {
    234                 setPartMapping(part1,g);
    235                 SList ga;
    236                 int i,ile;
    237                 ile=countBranches(g+1,ga);
    238                 c.resetrange=0;
    239                 c.bendrange=1.0/ile;
    240                 for (i=0;i<ile;i++)
    241                         grow(part1,(char*)ga(i),k+Pt3D(0,0,-3.141+(i+1)*(6.282/(ile+1))),c);
    242                 return;
    243                 }
    244         case ' ': case '\t': case '\n': case '\r': break;
    245         default: invalid=1; return;
    246         }
    247         g++;
     150                case 'l': c.length += (0.33 - c.length)*0.3; setPartMapping(part1, g); break;
     151                case 'A': c.assimilation += (1 - c.assimilation)*0.8;   c.normalizeBiol4(); setPartMapping(part1, g);  break;
     152                case 'a': c.assimilation -= c.assimilation*0.4; c.normalizeBiol4(); setPartMapping(part1, g); break;
     153                case 'I': c.ingestion += (1 - c.ingestion)*0.8; c.normalizeBiol4(); setPartMapping(part1, g); break;
     154                case 'i': c.ingestion -= c.ingestion*0.4;       c.normalizeBiol4(); setPartMapping(part1, g); break;
     155                case 'S': c.stamina += (1 - c.stamina)*0.8; c.normalizeBiol4(); setPartMapping(part1, g); break;
     156                case 's': c.stamina -= c.stamina*0.4; c.normalizeBiol4(); setPartMapping(part1, g); break;
     157                case 'M': c.muscle_power += (1 - c.muscle_power)*0.8;   c.normalizeBiol4(); setPartMapping(part1, g); break;
     158                case 'm': c.muscle_power -= c.muscle_power*0.4; c.normalizeBiol4(); setPartMapping(part1, g); break;
     159                case 'C': c.curvedness += (2.0 - c.curvedness)*0.25;    setPartMapping(part1, g); break;
     160                case 'c': c.curvedness += (-2.0 - c.curvedness)*0.25; setPartMapping(part1, g); break;
     161                case 'F': c.friction += (4 - c.friction)*0.2; setPartMapping(part1, g); break;
     162                case 'f': c.friction -= c.friction*0.2; setPartMapping(part1, g); break;
     163                case 'W': c.weight += (2.0 - c.weight)*0.3; setPartMapping(part1, g); break;
     164                case 'w': c.weight += (0.5 - c.weight)*0.3; setPartMapping(part1, g); break;
     165                case 'E': c.energy += (10.0 - c.energy)*0.1; setPartMapping(part1, g); break;
     166                case 'e': c.energy -= c.energy*0.1;     setPartMapping(part1, g); break;
     167
     168                case 'D': c.cred += (1.0 - c.cred)*0.25; setPartMapping(part1, g); break;
     169                case 'd': c.cred += (0.0 - c.cred)*0.25; setPartMapping(part1, g); break;
     170                case 'G': c.cgreen += (1.0 - c.cgreen)*0.25; setPartMapping(part1, g); break;
     171                case 'g': c.cgreen += (0.0 - c.cgreen)*0.25; setPartMapping(part1, g); break;
     172                case 'B': c.cblue += (1.0 - c.cblue)*0.25; setPartMapping(part1, g); break;
     173                case 'b': c.cblue += (0.0 - c.cblue)*0.25; setPartMapping(part1, g); break;
     174                case 'H': c.visual_size += (0.7 - c.visual_size)*0.25; setPartMapping(part1, g); break;
     175                case 'h': c.visual_size += (0.05 - c.visual_size)*0.25; setPartMapping(part1, g); break;
     176
     177                case '[': //neuron
     178                        //              setdebug(g-(char*)geny,DEBUGNEURO | !l_neu);
     179                        if (model.getJointCount())
     180                                g = growNeuro(g + 1, c, hasmuscles);
     181                        else
     182                        {
     183                                logMessage("GenoConv_F1", "grow", 1, "Illegal neuron position (ignored)");
     184                                g = skipNeuro(g + 1);
     185                        }
     186                        break;
     187                case 'X':
     188                {
     189                        int freshpart = 0;
     190                        //setdebug(g-(char*)geny,DEBUGEST | !l_est);
     191                        if (part1 < 0) //initial grow
     192                        {
     193                                if (model.getPartCount() > 0)
     194                                        part1 = 0;
     195                                else
     196                                {
     197                                        part1 = growPart(c, g);
     198                                        freshpart = 1;
     199                                        if (first_part_mapping)
     200                                                model.getPart(part1)->setMapping(*first_part_mapping);
     201                                }
     202                        }
     203                        if (!freshpart)
     204                        {
     205                                Part *part = model.getPart(part1);
     206                                part->density = ((part->mass*part->density) + 1.0 / c.weight) / (part->mass + 1.0); // v=m*d
     207                                //                      part->volume+=1.0/c.weight;
     208                                part->mass += 1.0;
     209                        }
     210                        model_energy += 0.9*c.energy + 0.1;
     211                        model_energy_max += 1.0;
     212
     213                        int part2 = growPart(c, g);
     214                        growJoint(part1, part2, k, c, g);
     215                        //              est* e = new est(*s,*s2,k,c,zz,this);
     216
     217                        // attenuate properties as they are propagated along the structure
     218                        c.length = 0.5*c.length + 0.5*stdprops.length;
     219                        c.visual_size = 0.5*c.visual_size + 0.5*stdprops.visual_size;
     220                        c.curvedness = 0.66*c.curvedness;
     221                        c.twist = 0.66*c.twist;
     222                        c.friction = 0.8*c.friction + 0.2*stdprops.friction;
     223
     224                        c.assimilation = 0.8*c.assimilation + 0.2*stdprops.assimilation;
     225                        c.stamina = 0.8*c.stamina + 0.2*stdprops.stamina;
     226                        c.muscle_power = 0.8*c.muscle_power + 0.2*stdprops.muscle_power;
     227                        c.ingestion = 0.8*c.ingestion + 0.2*stdprops.ingestion;
     228                        c.weight += (stdprops.weight - c.weight)*0.5;
     229                        c.normalizeBiol4();
     230
     231                        if (c.muscle_reset_range) c.muscle_bend_range = 1.0; else c.muscle_reset_range = true;
     232                        grow(part2, g + 1, Pt3D_0, c);
     233                        return;
     234                }
     235                case '(':
     236                {
     237                        setPartMapping(part1, g);
     238                        SList ga;
     239                        int i, count;
     240                        count = countBranches(g + 1, ga);
     241                        c.muscle_reset_range = false;
     242                        c.muscle_bend_range = 1.0 / count;
     243                        for (i = 0; i < count; i++)
     244                                grow(part1, (char*)ga(i), k + Pt3D(0, 0, -M_PI + (i + 1)*(2*M_PI / (count + 1))), c);
     245                        return;
     246                }
     247                case ' ': case '\t': case '\n': case '\r': break;
     248                default: invalid = 1; return;
     249                }
     250                g++;
    248251        }
    249252}
     
    251254SyntParam* Builder::lastNeuroClassParam()
    252255{
    253 if (!neuro_cls_param)
    254         {
    255         NeuroClass *cls=last_f1_neuro->getClass();
    256         if (cls)
    257                 {
    258                 neuro_cls_param=new SyntParam(last_f1_neuro->classProperties());
    259 // this is equivalent to:
    260 //              SyntParam tmp=last_f1_neuro->classProperties();
    261 //              neuro_cls_param=new SyntParam(tmp);
    262 // interestingly, some compilers eliminate the call to new SyntParam,
    263 // realizing that a copy constructor is redundant when the original object is
    264 // temporary. there are no side effect of such optimization, as long as the
    265 // copy-constructed object is exact equivalent of the original.
    266                 }
    267         }
    268 return neuro_cls_param;
    269 }
    270 
    271 void Builder::addClassParam(const char* name,double value)
    272 {
    273 lastNeuroClassParam();
    274 if (neuro_cls_param)
    275         neuro_cls_param->setDoubleById(name,value);
    276 }
    277 
    278 void Builder::addClassParam(const char* name,const char* value)
    279 {
    280 lastNeuroClassParam();
    281 if (neuro_cls_param)
    282         {
    283         ExtValue e(value);
    284         const ExtValue &re(e);
    285         neuro_cls_param->setById(name,re);
    286         }
    287 }
    288 
    289 int Builder::countBranches(const char*g,SList &out)
    290 {
    291 int gl=0;
    292 out+=(void*)g;
    293 while (gl>=0)
    294         {
    295         switch(*g)
    296                 {
    297                 case 0: gl=-1; break;
     256        if (!neuro_cls_param)
     257        {
     258                NeuroClass *cls = last_f1_neuro->getClass();
     259                if (cls)
     260                {
     261                        neuro_cls_param = new SyntParam(last_f1_neuro->classProperties());
     262                        // this is equivalent to:
     263                        //              SyntParam tmp=last_f1_neuro->classProperties();
     264                        //              neuro_cls_param=new SyntParam(tmp);
     265                        // interestingly, some compilers eliminate the call to new SyntParam,
     266                        // realizing that a copy constructor is redundant when the original object is
     267                        // temporary. there are no side effect of such optimization, as long as the
     268                        // copy-constructed object is exact equivalent of the original.
     269                }
     270        }
     271        return neuro_cls_param;
     272}
     273
     274void Builder::addClassParam(const char* name, double value)
     275{
     276        lastNeuroClassParam();
     277        if (neuro_cls_param)
     278                neuro_cls_param->setDoubleById(name, value);
     279}
     280
     281void Builder::addClassParam(const char* name, const char* value)
     282{
     283        lastNeuroClassParam();
     284        if (neuro_cls_param)
     285        {
     286                ExtValue e(value);
     287                const ExtValue &re(e);
     288                neuro_cls_param->setById(name, re);
     289        }
     290}
     291
     292int Builder::countBranches(const char*g, SList &out)
     293{
     294        int gl = 0;
     295        out += (void*)g;
     296        while (gl >= 0)
     297        {
     298                switch (*g)
     299                {
     300                case 0: gl = -1; break;
    298301                case '(': case '[': ++gl; break;
    299302                case ')': case ']': --gl; break;
    300                 case ',': if (!gl) out+=(void*)(g+1);
    301                 }
    302         g++;
    303         }
    304 return out.size();
    305 }
    306 
    307 int Builder::growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g)
    308 {
    309 double len=min(2.0,c.dlug);
    310 sprintf(tmp,"j:p1=%ld,p2=%ld,dx=%lg,rx=%lg,ry=%lg,rz=%lg,stam=%lg,vr=%g,vg=%g,vb=%g",
    311         part1,part2,len,angle.x,angle.y,angle.z,c.odpor, c.cred,c.cgreen,c.cblue);
    312 lastjoint_muscle_power=c.ruch;
    313 return model.singleStepBuild(tmp,makeRange(g));
    314 }
    315 
    316 int Builder::growPart(F1Props &c,const char *g)
    317 {
    318 sprintf(tmp,"p:dn=%lg,fr=%lg,ing=%lg,as=%lg,vs=%g,vr=%g,vg=%g,vb=%g",
    319         1.0/c.masa,c.tarcie,c.wchl,c.asym, c.grub, c.cred,c.cgreen,c.cblue);
    320 return model.singleStepBuild(tmp,makeRange(g));
     303                case ',': if (!gl) out += (void*)(g + 1);
     304                }
     305                g++;
     306        }
     307        return out.size();
     308}
     309
     310int Builder::growJoint(int part1, int part2, Pt3D &angle, F1Props &c, const char *g)
     311{
     312        double len = min(2.0, c.length);
     313        sprintf(tmp, "j:p1=%ld,p2=%ld,dx=%lg,rx=%lg,ry=%lg,rz=%lg,stam=%lg,vr=%g,vg=%g,vb=%g",
     314                part1, part2, len, angle.x, angle.y, angle.z, c.stamina, c.cred, c.cgreen, c.cblue);
     315        lastjoint_muscle_power = c.muscle_power;
     316        return model.singleStepBuild(tmp, makeRange(g));
     317}
     318
     319int Builder::growPart(F1Props &c, const char *g)
     320{
     321        sprintf(tmp, "p:dn=%lg,fr=%lg,ing=%lg,as=%lg,vs=%g,vr=%g,vg=%g,vb=%g",
     322                1.0 / c.weight, c.friction, c.ingestion, c.assimilation, c.visual_size, c.cred, c.cgreen, c.cblue);
     323        return model.singleStepBuild(tmp, makeRange(g));
    321324}
    322325
    323326const char *Builder::skipNeuro(const char *z)
    324327{
    325 for (;*z;z++) if ((*z==']')||(*z==')')) break;
    326 return z-1;
    327 }
    328 
    329 const char* Builder::growNeuro(const char* t, F1Props& props,int &hasmuscles)
    330 {
    331 const char*neuroend=skipNeuro(t);
    332 last_f1_neuro=model.addNewNeuro();
    333 neuro_cls_param=NULL;
    334 last_f1_neuro->attachToPart(getLastPart());
    335 const MultiRange *mr=makeRange(t-1,neuroend+1);
    336 if (mr) last_f1_neuro->addMapping(*mr);
    337 neuro_f1_to_f0+=last_f1_neuro;
    338 
    339 SString clsname;
    340 bool haveclass=0;
    341 while(*t && *t<=' ') t++;
    342 const char* next=(*t)?(t+1):t;
    343 while(*next && *next<=' ') next++;
    344 if (*t && *next!=',' && *next!=']') // old style muscles [|rest] or [@rest]
    345 switch(*t)
    346         {
    347         case '@': if (t[1]==':') break;
    348                 haveclass=1;
    349 //              if (!(hasmuscles&1))
    350                 {
    351                   hasmuscles|=1;
    352                   Neuro *muscle=model.addNewNeuro();
    353                   sprintf(tmp,"@:p=%lg",lastjoint_muscle_power);
    354                   muscle->addInput(last_f1_neuro);
    355                   muscle->setDetails(tmp);
    356                   muscle->attachToJoint(getLastJoint());
    357                   if (usemapping) muscle->addMapping(*makeRange(t));
    358                 }
    359                 t++;
    360                 break;
    361         case '|': if (t[1]==':') break;
    362                 haveclass=1;
    363 //              if (!(hasmuscles&2))
    364                 {
    365                   hasmuscles|=2;
    366                   Neuro *muscle=model.addNewNeuro();
    367                   sprintf(tmp,"|:p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
    368                   muscle->addInput(last_f1_neuro);
    369                   muscle->setDetails(tmp);
    370                   muscle->attachToJoint(getLastJoint());
    371                   if (usemapping) muscle->addMapping(*makeRange(t));
    372                 }
    373                 t++;
    374                 break;
    375         }
    376 while(*t && *t<=' ') t++;
    377 bool finished=0;
    378 const char *begin=t;
    379 const char* colon=0;
    380 SString classparams;
    381 while(!finished)
    382         {
    383         switch (*t)
    384                 {
    385                 case ':': colon=t; break;
    386                 case 0: case ']': case ')': finished=1;
     328        for (; *z; z++) if ((*z == ']') || (*z == ')')) break;
     329        return z - 1;
     330}
     331
     332const char* Builder::growNeuro(const char* t, F1Props& props, int &hasmuscles)
     333{
     334        const char*neuroend = skipNeuro(t);
     335        last_f1_neuro = model.addNewNeuro();
     336        neuro_cls_param = NULL;
     337        last_f1_neuro->attachToPart(getLastPart());
     338        const MultiRange *mr = makeRange(t - 1, neuroend + 1);
     339        if (mr) last_f1_neuro->addMapping(*mr);
     340        neuro_f1_to_f0 += last_f1_neuro;
     341
     342        SString clsname;
     343        bool haveclass = 0;
     344        while (*t && *t <= ' ') t++;
     345        const char* next = (*t) ? (t + 1) : t;
     346        while (*next && *next <= ' ') next++;
     347        if (*t && *next != ',' && *next != ']') // old style muscles [|rest] or [@rest]
     348                switch (*t)
     349        {
     350                case '@': if (t[1] == ':') break;
     351                        haveclass = 1;
     352                        //              if (!(hasmuscles&1))
     353                        {
     354                                hasmuscles |= 1;
     355                                Neuro *muscle = model.addNewNeuro();
     356                                sprintf(tmp, "@:p=%lg", lastjoint_muscle_power);
     357                                muscle->addInput(last_f1_neuro);
     358                                muscle->setDetails(tmp);
     359                                muscle->attachToJoint(getLastJoint());
     360                                if (usemapping) muscle->addMapping(*makeRange(t));
     361                        }
     362                        t++;
     363                        break;
     364                case '|': if (t[1] == ':') break;
     365                        haveclass = 1;
     366                        //              if (!(hasmuscles&2))
     367                        {
     368                                hasmuscles |= 2;
     369                                Neuro *muscle = model.addNewNeuro();
     370                                sprintf(tmp, "|:p=%lg,r=%lg", lastjoint_muscle_power, props.muscle_bend_range);
     371                                muscle->addInput(last_f1_neuro);
     372                                muscle->setDetails(tmp);
     373                                muscle->attachToJoint(getLastJoint());
     374                                if (usemapping) muscle->addMapping(*makeRange(t));
     375                        }
     376                        t++;
     377                        break;
     378        }
     379        while (*t && *t <= ' ') t++;
     380        bool finished = 0;
     381        const char *begin = t;
     382        const char* colon = 0;
     383        SString classparams;
     384        while (!finished)
     385        {
     386                switch (*t)
     387                {
     388                case ':': colon = t; break;
     389                case 0: case ']': case ')': finished = 1;
    387390                        // NO break!
    388391                case ',':
    389                         if ( !haveclass && !colon && t>begin )
     392                        if (!haveclass && !colon && t > begin)
     393                        {
     394                                haveclass = 1;
     395                                SString clsname(begin, t - begin);
     396                                clsname = trim(clsname);
     397                                last_f1_neuro->setClassName(clsname);
     398                                NeuroClass *cls = last_f1_neuro->getClass();
     399                                if (cls)
    390400                                {
    391                                 haveclass=1;
    392                                 SString clsname(begin,t-begin);
    393                                 clsname=trim(clsname);
    394                                 last_f1_neuro->setClassName(clsname);
    395                                 NeuroClass *cls=last_f1_neuro->getClass();
    396                                 if (cls)
    397                                         {
    398                                         if (cls->getPreferredLocation()==2)
     401                                        if (cls->getPreferredLocation() == 2)
    399402                                                last_f1_neuro->attachToJoint(getLastJoint());
    400                                         else if (cls->getPreferredLocation()==1)
     403                                        else if (cls->getPreferredLocation() == 1)
    401404                                                last_f1_neuro->attachToPart(getLastPart());
    402405
    403406                                        lastNeuroClassParam();
    404407                                        //special handling: muscle properties (can be overwritten by subsequent property assignments)
    405                                         if (!strcmp(cls->getName().c_str(),"|"))
    406                                                 {
    407                                                 neuro_cls_param->setDoubleById("p",lastjoint_muscle_power);
    408                                                 neuro_cls_param->setDoubleById("r",props.bendrange);
    409                                                 }
    410                                         else if (!strcmp(cls->getName().c_str(),"@"))
    411                                                 {
    412                                                 neuro_cls_param->setDoubleById("p",lastjoint_muscle_power);
    413                                                 }
     408                                        if (!strcmp(cls->getName().c_str(), "|"))
     409                                        {
     410                                                neuro_cls_param->setDoubleById("p", lastjoint_muscle_power);
     411                                                neuro_cls_param->setDoubleById("r", props.muscle_bend_range);
     412                                        }
     413                                        else if (!strcmp(cls->getName().c_str(), "@"))
     414                                        {
     415                                                neuro_cls_param->setDoubleById("p", lastjoint_muscle_power);
    414416                                        }
    415417                                }
    416                         else if (colon && (colon>begin) && (t>colon))
    417                                 growConnection(begin,colon,t,props);
    418                         if (t[0]!=',') t--;
    419                         begin=t+1; colon=0;
     418                        }
     419                        else if (colon && (colon > begin) && (t > colon))
     420                                growConnection(begin, colon, t, props);
     421                        if (t[0] != ',') t--;
     422                        begin = t + 1; colon = 0;
    420423                        break;
    421424                }
    422         t++;
    423         }
    424 SAFEDELETE(neuro_cls_param);
    425 return t;
    426 }
    427 void Builder::growConnection(const char* begin, const char* colon,const char* end,F1Props& props)
    428 {
    429 while(*begin && *begin<=' ') begin++;
    430 int i;
    431 if (isdigit(begin[0]) || (begin[0]=='-'))
    432         {
    433         double weight=ExtValue::getDouble(trim(SString(colon+1,end-(colon+1))).c_str());
    434         paInt relative=ExtValue::getInt(trim(SString(begin,colon-begin)).c_str(),false);
    435         int this_refno=neuro_f1_to_f0.size()-1;
    436         addOrRememberInput(this_refno,this_refno+relative,weight);
    437         }
    438 else if ((i=last_f1_neuro->extraProperties().findIdn(begin,colon-begin))>=0)
    439         {
    440         last_f1_neuro->extraProperties().set(i,colon+1);
    441         }
    442 else if (isupper(begin[0]) || strchr("*|@",begin[0]))
    443         {
    444         SString clsname(begin,colon-begin);
    445         trim(clsname);
    446         Neuro *receptor=model.addNewNeuro();
    447         receptor->setClassName(clsname);
    448         NeuroClass *cls=receptor->getClass();
    449         if (cls)
    450                 {
    451                 if (cls->getPreferredLocation()==2) receptor->attachToJoint(getLastJoint());
    452                 else if (cls->getPreferredLocation()==1) receptor->attachToPart(getLastPart());
    453                 }
    454         last_f1_neuro->addInput(receptor,ExtValue::getDouble(trim(SString(colon+1,end-(colon+1))).c_str()));
    455         if (usemapping) receptor->addMapping(*makeRange(begin,end-1));
    456         }
    457 else if ((begin[0]=='>')&&(begin[1]))
    458         {
    459         Neuro *out=model.addNewNeuro();
    460         out->addInput(last_f1_neuro,ExtValue::getDouble(trim(SString(colon+1,end-(colon+1))).c_str()));
    461         out->setClassName(SString(begin+1,end-colon-1));
    462         if (begin[1]=='@')
    463                 {
    464                 sprintf(tmp,"p=%lg",lastjoint_muscle_power);
    465                 out->setClassParams(tmp);
    466                 }
    467         else if (begin[1]=='|')
    468                 {
    469                 sprintf(tmp,"p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
    470                 out->setClassParams(tmp);
    471                 }
    472         NeuroClass *cls=out->getClass();
    473         if (cls)
    474                 {
    475                 if (cls->getPreferredLocation()==2) out->attachToJoint(getLastJoint());
    476                 else if (cls->getPreferredLocation()==1) out->attachToPart(getLastPart());
    477                 }
    478         if (usemapping) out->addMapping(*makeRange(begin,end-1));
    479         }
    480 else if (*begin=='!') addClassParam("fo",ExtValue::getDouble(trim(SString(colon+1,end-(colon+1))).c_str()));
    481 else if (*begin=='=') addClassParam("in",ExtValue::getDouble(trim(SString(colon+1,end-(colon+1))).c_str()));
    482 else if (*begin=='/') addClassParam("si",ExtValue::getDouble(trim(SString(colon+1,end-(colon+1))).c_str()));
    483 else if (islower(begin[0]))
    484         {
    485         SString name(begin,colon-begin);
    486         SString value(colon+1,end-(colon+1));
    487         addClassParam(name.c_str(),value.c_str());
    488         }
    489 }
     425                t++;
     426        }
     427        SAFEDELETE(neuro_cls_param);
     428        return t;
     429}
     430void Builder::growConnection(const char* begin, const char* colon, const char* end, F1Props& props)
     431{
     432        while (*begin && *begin <= ' ') begin++;
     433        int i;
     434        if (isdigit(begin[0]) || (begin[0] == '-'))
     435        {
     436                double conn_weight = ExtValue::getDouble(trim(SString(colon + 1, end - (colon + 1))).c_str());
     437                paInt relative = ExtValue::getInt(trim(SString(begin, colon - begin)).c_str(), false);
     438                int this_refno = neuro_f1_to_f0.size() - 1;
     439                addOrRememberInput(this_refno, this_refno + relative, conn_weight);
     440        }
     441        else if ((i = last_f1_neuro->extraProperties().findIdn(begin, colon - begin)) >= 0)
     442        {
     443                last_f1_neuro->extraProperties().set(i, colon + 1);
     444        }
     445        else if (isupper(begin[0]) || strchr("*|@", begin[0]))
     446        {
     447                SString clsname(begin, colon - begin);
     448                trim(clsname);
     449                Neuro *receptor = model.addNewNeuro();
     450                receptor->setClassName(clsname);
     451                NeuroClass *cls = receptor->getClass();
     452                if (cls)
     453                {
     454                        if (cls->getPreferredLocation() == 2) receptor->attachToJoint(getLastJoint());
     455                        else if (cls->getPreferredLocation() == 1) receptor->attachToPart(getLastPart());
     456                }
     457                last_f1_neuro->addInput(receptor, ExtValue::getDouble(trim(SString(colon + 1, end - (colon + 1))).c_str()));
     458                if (usemapping) receptor->addMapping(*makeRange(begin, end - 1));
     459        }
     460        else if ((begin[0] == '>') && (begin[1]))
     461        {
     462                Neuro *out = model.addNewNeuro();
     463                out->addInput(last_f1_neuro, ExtValue::getDouble(trim(SString(colon + 1, end - (colon + 1))).c_str()));
     464                out->setClassName(SString(begin + 1, end - colon - 1));
     465                if (begin[1] == '@')
     466                {
     467                        sprintf(tmp, "p=%lg", lastjoint_muscle_power);
     468                        out->setClassParams(tmp);
     469                }
     470                else if (begin[1] == '|')
     471                {
     472                        sprintf(tmp, "p=%lg,r=%lg", lastjoint_muscle_power, props.muscle_bend_range);
     473                        out->setClassParams(tmp);
     474                }
     475                NeuroClass *cls = out->getClass();
     476                if (cls)
     477                {
     478                        if (cls->getPreferredLocation() == 2) out->attachToJoint(getLastJoint());
     479                        else if (cls->getPreferredLocation() == 1) out->attachToPart(getLastPart());
     480                }
     481                if (usemapping) out->addMapping(*makeRange(begin, end - 1));
     482        }
     483        else if (*begin == '!') addClassParam("fo", ExtValue::getDouble(trim(SString(colon + 1, end - (colon + 1))).c_str()));
     484        else if (*begin == '=') addClassParam("in", ExtValue::getDouble(trim(SString(colon + 1, end - (colon + 1))).c_str()));
     485        else if (*begin == '/') addClassParam("si", ExtValue::getDouble(trim(SString(colon + 1, end - (colon + 1))).c_str()));
     486        else if (islower(begin[0]))
     487        {
     488                SString name(begin, colon - begin);
     489                SString value(colon + 1, end - (colon + 1));
     490                addClassParam(name.c_str(), value.c_str());
     491        }
     492}
Note: See TracChangeset for help on using the changeset viewer.