source: cpp/gdk/conv_f1.cpp @ 80

Last change on this file since 80 was 80, checked in by Maciej Komosinski, 11 years ago
  • new properties in Parts and Joints: visual red, green, blue, thickness
  • updated list of Neurons and their properties
  • Property svn:eol-style set to native
File size: 12.3 KB
Line 
1// This file is a part of the Framsticks GDK library.
2// Copyright (C) 2002-2011  Szymon Ulatowski.  See LICENSE.txt for details.
3// Refer to http://www.framsticks.com/ for further information.
4
5#include "conv_f1.h"
6#include "nonstd_stl.h"
7#include "framsg.h"
8#include "multirange.h"
9#include "multimap.h"
10#include <ctype.h>
11
12//#define v1f1COMPATIBLE
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 };
16
17class Builder
18{
19public:
20Builder(const char*g,int mapping=0):genbegin(g),usemapping(mapping),energ(0),energ_div(0),invalid(0) {}
21char tmp[222];
22bool invalid;
23Model model;
24const char *genbegin;
25SList neuro_f1_to_f0; // neuro_f1_to_f0(f1_refno) = actual neuro pointer
26Neuro *last_f1_neuro;
27        struct Connection { int n1,n2; double w;
28                Connection(int _n1,int _n2, double _w):n1(_n1),n2(_n2),w(_w) {} };
29SListTempl<Connection> connections;
30int usemapping;
31MultiRange range;
32double lastjoint_muscle_power;
33double energ,energ_div;
34void grow(int part1,const char*g,Pt3D k,F1Props c);
35int growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g);
36int growPart(F1Props &c,const char *g);
37const char *skipNeuro(const char *z);
38const char* growNeuro(const char* t,F1Props &c,int&);
39void growConnection(const char* begin,const char* colon,const char* end,F1Props& props);
40int countBranches(const char*g,SList &out);
41void addClassParam(const SString& newparam);
42void addClassParam(const char* name,double value);
43
44const MultiRange* makeRange(const char*g) {return makeRange(g,g);}
45const MultiRange* makeRange(const char*g,const char*g2);
46Part *getLastPart() {return getLastJoint()->part2;}
47Neuro *getLastNeuro() {return model.getNeuro(model.getNeuroCount()-1);}
48Joint *getLastJoint() {return model.getJoint(model.getJointCount()-1);}
49void addOrRememberInput(int n1,int n2,float w)
50                {
51                //if (!addInput(n1,n2,w,false))
52                connections+=Connection(n1,n2,w);
53                }
54bool addInput(int n1,int n2,float w,bool final)
55                {
56                if ((n1<0) || (n2<0) || (n1>=neuro_f1_to_f0.size()) || (n2>=neuro_f1_to_f0.size()))
57                        {
58                        if (final) FMprintf("GenoConvF1","addInput",FMLV_WARN,
59                                            "illegal neuron connection %d <- %d (ignored)",n1,n2);
60                        return 0;
61                        }
62                Neuro *neuro=(Neuro*)neuro_f1_to_f0(n1);
63                Neuro *input=(Neuro*)neuro_f1_to_f0(n2);
64                neuro->addInput(input,w);
65                return 1;
66                }
67void addPendingInputs()
68                {
69                for(int i=0;i<connections.size();i++)
70                        {
71                        Connection *c=&connections(i);
72                        addInput(c->n1,c->n2,c->w,true);
73                        }
74                }
75};
76
77const MultiRange* Builder::makeRange(const char*g,const char*g2)
78{
79if (!usemapping) return 0;
80range.clear();
81range.add(g-genbegin,g2-genbegin);
82return &range;
83}
84
85void F1Props::wykluczanie()
86{
87double s=ruch+asym+odpor+wchl;
88ruch=ruch/s;
89asym=asym/s;
90odpor=odpor/s;
91wchl=wchl/s;
92}
93
94/** main conversion function - with conversion map support */
95SString GenoConv_F1::convert(SString &i,MultiMap *map)
96{
97const char* g=(const char*)i;
98Builder builder(g,map?1:0);
99builder.model.open();
100builder.grow(-1,g,Pt3D_0,stdprops); // uses Model::singleStepBuild to create model elements
101if (builder.invalid) return SString();
102builder.addPendingInputs();
103builder.model.startenergy=(builder.energ_div>0)?(builder.energ/builder.energ_div):1.0;
104builder.model.close(); // model is ready to use now
105if (map) builder.model.getCurrentToF0Map(*map); // generate f1-to-f0 conversion map
106return builder.model.getF0Geno().getGene();
107}
108
109void Builder::grow(int part1,const char*g,Pt3D k,F1Props c)
110{
111int hasmuscles=0;
112k+=Pt3D(c.rot,0,c.skr);
113while(1)
114{
115switch(*g)
116        {
117        case 0: case ',': case ')': return;
118        case 'R': k.x+=0.7853;  break;
119        case 'r': k.x-=0.7853;  break;
120        case 'Q': c.rot+=(1.58-c.rot)*0.3;      break;
121        case 'q': c.rot+=(-1.58-c.rot)*0.3;     break;
122#ifdef v1f1COMPATIBLE
123        case 'L': c.dlug+=(3.0-c.dlug)*0.3; break;
124#else
125        case 'L': c.dlug+=(2.0-c.dlug)*0.3; break;
126#endif                                       
127        case 'l': c.dlug+=(0.33-c.dlug)*0.3; break;
128        case 'A': c.asym+=(1-c.asym)*0.8;       c.wykluczanie(); break;
129        case 'a': c.asym-=c.asym*0.4;   c.wykluczanie(); break;
130        case 'I': c.wchl+=(1-c.wchl)*0.8;       c.wykluczanie(); break;
131        case 'i': c.wchl-=c.wchl*0.4;   c.wykluczanie(); break;
132        case 'S': c.odpor+=(1-c.odpor)*0.8; c.wykluczanie(); break;
133        case 's': c.odpor-=c.odpor*0.4; c.wykluczanie(); break;
134        case 'M': c.ruch+=(1-c.ruch)*0.8;       c.wykluczanie(); break;
135        case 'm': c.ruch-=c.ruch*0.4;   c.wykluczanie(); break;
136        case 'C': c.skr+=(2.0-c.skr)*0.25;      break;
137        case 'c': c.skr+=(-2.0-c.skr)*0.25;break;
138        case 'F': c.tarcie+=(4-c.tarcie)*0.2;   break;
139        case 'f': c.tarcie-=c.tarcie*0.2;               break;
140        case 'W': c.masa+=(2.0-c.masa)*0.3;     break;
141        case 'w': c.masa+=(0.5-c.masa)*0.3;     break;
142        case 'E': c.energ+=(10.0-c.energ)*0.1;  break;
143        case 'e': c.energ-=c.energ*0.1;         break;
144
145        case 'D': c.cred+=(1.0-c.cred)*0.25;break;
146        case 'd': c.cred+=(0.0-c.cred)*0.25;break;
147        case 'G': c.cgreen+=(1.0-c.cgreen)*0.25;break;
148        case 'g': c.cgreen+=(0.0-c.cgreen)*0.25;break;
149        case 'B': c.cblue+=(1.0-c.cblue)*0.25;break;
150        case 'b': c.cblue+=(0.0-c.cblue)*0.25;break;
151        case 'H': c.grub+=(0.7-c.grub)*0.25;break;
152        case 'h': c.grub+=(0.05-c.grub)*0.25;break;
153
154        case '[': //neuron
155//              setdebug(g-(char*)geny,DEBUGNEURO | !l_neu);
156                if (model.getJointCount())
157                        g=growNeuro(g+1,c,hasmuscles);
158                else
159                        {
160                        FramMessage("GenoConv_F1","grow","Illegal neuron position (ignored)",1);
161                        g=skipNeuro(g+1);
162                        }
163                break;
164        case 'X':
165                {
166                int freshpart=0;
167//setdebug(g-(char*)geny,DEBUGEST | !l_est);
168                if (part1<0) //initial grow
169                        {
170                  if (model.getPartCount()>0)
171                            part1=0;
172                    else
173                            {
174                            part1=growPart(c,g);
175                            freshpart=1;
176                            }
177                  }
178                if (!freshpart)
179                        {
180                        Part *part=model.getPart(part1);
181                        part->density=((part->mass*part->density)+1.0/c.masa)/(part->mass+1.0); // v=m*d
182//                      part->volume+=1.0/c.masa;
183                        part->mass+=1.0;
184                        }
185                energ+=0.9*c.energ+0.1;
186                energ_div+=1.0;
187
188                int part2 = growPart(c,g);
189                growJoint(part1,part2,k,c,g);
190//              est* e = new est(*s,*s2,k,c,zz,this);
191
192                // oslabianie cech wzdluz struktury
193                c.dlug=0.5*c.dlug+0.5*stdprops.dlug;
194                c.grub=0.5*c.grub+0.5*stdprops.grub;
195                c.skr=0.66*c.skr;
196                c.rot=0.66*c.rot;
197                c.tarcie=0.8*c.tarcie+0.2*stdprops.tarcie;
198
199                c.asym=0.8*c.asym+0.2*stdprops.asym;
200                c.odpor=0.8*c.odpor+0.2*stdprops.odpor;
201                c.ruch=0.8*c.ruch+0.2*stdprops.ruch;
202                c.wchl=0.8*c.wchl+0.2*stdprops.wchl;
203                c.masa+=(stdprops.masa-c.masa)*0.5;
204                c.wykluczanie();
205       
206                if (c.resetrange) c.bendrange=1.0; else c.resetrange=1;
207                grow(part2,g+1,Pt3D_0,c);
208                return;
209                }
210        case '(':
211                {
212                SList ga;
213                int i,ile;
214                ile=countBranches(g+1,ga);
215                c.resetrange=0;
216                c.bendrange=1.0/ile;
217                for (i=0;i<ile;i++)
218                        grow(part1,(char*)ga(i),k+Pt3D(0,0,-3.141+(i+1)*(6.282/(ile+1))),c);
219                return;
220                }
221        case ' ': case '\t': case '\n': case '\r': break;
222        default: invalid=1; return;
223        }
224        g++;
225        }
226}
227
228void Builder::addClassParam(const SString& newparam)
229{
230SString allparams=last_f1_neuro->getClassParams();
231if (allparams.len()) allparams+=',';
232allparams+=newparam;
233last_f1_neuro->setClassParams(allparams);
234}
235void Builder::addClassParam(const char* name,double value)
236{
237SString t;
238sprintf(t.directWrite(30),"%s=%g",name,value);
239t.endWrite();
240addClassParam(t);
241}
242
243
244int Builder::countBranches(const char*g,SList &out)
245{
246int gl=0;
247out+=(void*)g;
248while (gl>=0)
249        {
250        switch(*g)
251                {
252                case 0: gl=-1; break;
253                case '(': case '[': ++gl; break;
254                case ')': case ']': --gl; break;
255                case ',': if (!gl) out+=(void*)(g+1);
256                }
257        g++;
258        }
259return !out;
260}
261
262int Builder::growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g)
263{
264double len=min(2.0,c.dlug);
265sprintf(tmp,"j:p1=%ld,p2=%ld,dx=%lg,rx=%lg,ry=%lg,rz=%lg,stam=%lg,vr=%g,vg=%g,vb=%g",
266        part1,part2,len,angle.x,angle.y,angle.z,c.odpor, c.cred,c.cgreen,c.cblue);
267lastjoint_muscle_power=c.ruch;
268return model.singleStepBuild(tmp,makeRange(g));
269}
270
271int Builder::growPart(F1Props &c,const char *g)
272{
273sprintf(tmp,"p:m=1,dn=%lg,fr=%lg,ing=%lg,as=%lg,vs=%g,vr=%g,vg=%g,vb=%g",
274        1.0/c.masa,c.tarcie,c.wchl,c.asym, c.grub, c.cred,c.cgreen,c.cblue);
275return model.singleStepBuild(tmp,makeRange(g));
276}
277
278const char *Builder::skipNeuro(const char *z)
279{
280for (;*z;z++) if ((*z==']')||(*z==')')) break;
281return z-1;
282}
283
284const char* Builder::growNeuro(const char* t, F1Props& props,int &hasmuscles)
285{
286const char*neuroend=skipNeuro(t);
287last_f1_neuro=model.addNewNeuro();
288last_f1_neuro->attachToPart(getLastPart());
289const MultiRange *mr=makeRange(t-1,neuroend+1);
290if (mr) last_f1_neuro->setMapping(*mr);
291neuro_f1_to_f0+=last_f1_neuro;
292
293SString clsname;
294bool haveclass=0;
295while(*t && *t<=' ') t++;
296const char* next=(*t)?(t+1):t;
297while(*next && *next<=' ') next++;
298if (*t && *next!=',' && *next!=']') // old style muscles [|rest] or [@rest]
299switch(*t)
300        {
301        case '@': if (t[1]==':') break;
302                haveclass=1;
303//              if (!(hasmuscles&1))
304                {
305                  hasmuscles|=1;
306                  Neuro *muscle=model.addNewNeuro();
307                  sprintf(tmp,"@:p=%lg",lastjoint_muscle_power);
308                  muscle->addInput(last_f1_neuro);
309                  muscle->setDetails(tmp);
310                  muscle->attachToJoint(getLastJoint());
311                  if (usemapping) muscle->setMapping(*makeRange(t));
312                }
313                t++;
314                break;
315        case '|': if (t[1]==':') break;
316                haveclass=1;
317//              if (!(hasmuscles&2))
318                {
319                  hasmuscles|=2;
320                  Neuro *muscle=model.addNewNeuro();
321                  sprintf(tmp,"|:p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
322                  muscle->addInput(last_f1_neuro);
323                  muscle->setDetails(tmp);
324                  muscle->attachToJoint(getLastJoint());
325                  if (usemapping) muscle->setMapping(*makeRange(t));
326                }
327                t++;
328                break;
329        }
330while(*t && *t<=' ') t++;
331bool finished=0;
332const char *begin=t;
333const char* colon=0;
334SString classparams;
335while(!finished)
336        {
337        switch (*t)
338                {
339                case ':': colon=t; break;
340                case 0: case ']': case ')': finished=1;
341                        // NO break!
342                case ',':
343                        if ( !haveclass && !colon && t>begin )
344                                {
345                                haveclass=1;
346                                SString clsname(begin,t-begin);
347                                clsname=trim(clsname);
348                                last_f1_neuro->setClassName(clsname);
349                                NeuroClass *cls=last_f1_neuro->getClass();
350                                if (cls)
351                                        {
352                                        if (cls->getPreferredLocation()==2)
353                                                last_f1_neuro->attachToJoint(getLastJoint());
354                                        else if (cls->getPreferredLocation()==1)
355                                                last_f1_neuro->attachToPart(getLastPart());
356                                        }
357                                }
358                        else if (colon && (colon>begin) && (t>colon))
359                                growConnection(begin,colon,t,props);
360                        if (t[0]!=',') t--;
361                        begin=t+1; colon=0;
362                        break;
363                }
364        t++;
365        }
366return t;
367}
368void Builder::growConnection(const char* begin, const char* colon,const char* end,F1Props& props)
369{
370while(*begin && *begin<=' ') begin++;
371int i;
372if (isdigit(begin[0]) || (begin[0]=='-'))
373        {
374        float weight=atof(colon+1);
375        int relative=atoi(begin);
376        int this_refno=neuro_f1_to_f0.size()-1;
377        addOrRememberInput(this_refno,this_refno+relative,weight);
378        }
379else if ((i=last_f1_neuro->extraProperties().findIdn(begin,colon-begin))>=0)
380        {
381        last_f1_neuro->extraProperties().set(i,colon+1);
382        }
383else if (isupper(begin[0]) || strchr("*|@",begin[0]))
384        {
385        SString clsname(begin,colon-begin);
386        trim(clsname);
387        Neuro *receptor=model.addNewNeuro();
388        receptor->setClassName(clsname);
389        NeuroClass *cls=receptor->getClass();
390        if (cls)
391                {
392                if (cls->getPreferredLocation()==2) receptor->attachToJoint(getLastJoint());
393                else if (cls->getPreferredLocation()==1) receptor->attachToPart(getLastPart());
394                }
395        last_f1_neuro->addInput(receptor,atof(colon+1));
396        if (usemapping) receptor->setMapping(*makeRange(begin,end-1));
397        }
398else if ((begin[0]=='>')&&(begin[1]))
399        {
400        Neuro *out=model.addNewNeuro();
401        out->addInput(last_f1_neuro,atof(colon+1));
402        out->setClassName(SString(begin+1,end-colon-1));
403        if (begin[1]=='@')
404                {
405                sprintf(tmp,"p=%lg",lastjoint_muscle_power);
406                out->setClassParams(tmp);
407                }
408        else if (begin[1]=='|')
409                {
410                sprintf(tmp,"p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
411                out->setClassParams(tmp);
412                }
413        NeuroClass *cls=out->getClass();
414        if (cls)
415                {
416                if (cls->getPreferredLocation()==2) out->attachToJoint(getLastJoint());
417                else if (cls->getPreferredLocation()==1) out->attachToPart(getLastPart());
418                }
419        if (usemapping) out->setMapping(*makeRange(begin,end-1));
420        }
421else if (*begin=='!') addClassParam("fo",max(0.0,min(1.0,atof(colon+1))));
422else if (*begin=='=') addClassParam("in",max(0.0,min(1.0,atof(colon+1))));
423else if (*begin=='/') addClassParam("si",atof(colon+1));
424/*else if (*begin=='!') last_f1_neuro->force=max(0.0,min(1.0,atof(colon+1)));
425else if (*begin=='=') last_f1_neuro->inertia=max(0.0,min(1.0,atof(colon+1)));
426else if (*begin=='/') last_f1_neuro->sigmo=atof(colon+1);
427*/
428else if (islower(begin[0]))
429        {
430        SString newparam(begin,end-begin);
431        trim(newparam);
432        newparam.directWrite()[colon-begin]='='; // ':' -> '='
433        addClassParam(newparam);
434        }
435}
Note: See TracBrowser for help on using the repository browser.