source: cpp/frams/genetics/f9/conv_f9.cpp @ 157

Last change on this file since 157 was 157, checked in by sz, 6 years ago

f9 and Ff converters can now detect an invalid input genotype and react appropriately

  • Property svn:eol-style set to native
File size: 4.6 KB
Line 
1// This file is a part of the Framsticks GDK.
2// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
3// Refer to http://www.framsticks.com/ for further information.
4
5#include "conv_f9.h"
6#include <frams/model/model.h>
7#include <string.h>
8#include <common/nonstd_stl.h> //ARRAY_LENGTH
9
10#define APPLY_DETERMINISTIC_BODY_NOISE //this representation easily produces perfectly vertical sticks that would stay upright forever. In most cases such infinite perfection is not desired, so we make the construct less perfect by perturbing its coordinates.
11
12GenoConv_f90::GenoConv_f90()
13{
14        name = "Turtle3D-ortho encoding";
15        in_format  = '9';
16        out_format = '0';
17        mapsupport = 0; //would be easy and nice to add!
18}
19
20
21const char* turtle_commands_f9 ="LRDUBF";
22
23//const char* turtle_commandsX_f9="-+0000";
24//const char* turtle_commandsY_f9="00-+00";
25//const char* turtle_commandsZ_f9="0000-+";
26
27SString GenoConv_f90::convert(SString &in, MultiMap *map)
28{
29        vector<XYZ_LOC> vertices;
30        XYZ_LOC current;
31        Model m;
32        m.open();
33        int recently_added=addSegment(m,vertices,current,0xDead);
34        for(int i=0;i<in.len();i++)
35        {
36                char command=in[i];
37                char *ptr=strchr((char*)turtle_commands_f9,command);
38                if (ptr)
39                {
40                        int delta[]={0,0,0};
41                        int pos=ptr-turtle_commands_f9;
42                        int axis=pos/2;
43                        int dir=pos%2;
44                        (*(delta+axis))+=dir*2-1; //+1 or -1 in the given axis
45                        current.add(delta);
46                        recently_added=addSegment(m,vertices,current,recently_added);
47                }
48        }
49#ifdef APPLY_DETERMINISTIC_BODY_NOISE
50        perturbPartLocations(m);
51#endif
52        setColors(m);
53        m.close();
54        if (m.getPartCount() < 2) //only one part <=> there were no valid turtle commands in the input genotype
55                return ""; //so we return an invalid f0 genotype
56        return m.getF0Geno().getGene();
57}
58
59int GenoConv_f90::addSegment(Model &m,vector<XYZ_LOC> &vertices,const XYZ_LOC &new_vertex,int recently_added)
60{
61        if (vertices.size()<1) //empty model?
62        {
63                return addNewVertex(m,vertices,new_vertex);
64        } else
65        {
66                int vertex_here=findVertexAt(vertices,new_vertex);
67                if (vertex_here<0) //need to create a new Part
68                {
69                        vertex_here=addNewVertex(m,vertices,new_vertex);
70                } //else there already exists a Part in new_vertex; new Joint may or may not be needed
71                Part *p1=m.getPart(recently_added);
72                Part *p2=m.getPart(vertex_here);
73                if (m.findJoint(p1,p2)<0 && m.findJoint(p2,p1)<0) //new Joint needed? should always be true if we just created a new Part (vertex_here was <0)
74                {
75                        m.addNewJoint(p1,p2);
76                }
77                return vertex_here;
78        }
79}
80
81int GenoConv_f90::findVertexAt(vector<XYZ_LOC> &vertices,const XYZ_LOC &vertex)
82{
83        for(int i=0;i<vertices.size();i++)
84                if (vertices[i].same_coordinates(vertex)) return i;
85        return -1;
86}
87
88
89int GenoConv_f90::addNewVertex(Model &m,vector<XYZ_LOC> &vertices,const XYZ_LOC &new_vertex)
90{
91        Part *p=new Part;
92        p->p.x=new_vertex.x;
93        p->p.y=new_vertex.y;
94        p->p.z=new_vertex.z;
95        m.addPart(p);
96
97        vertices.push_back(new_vertex);
98        return vertices.size()-1;
99}
100
101double mix(int *colortab,int maxind,double ind)
102{
103        int indpre=(int)ind;
104        int indpost=indpre+1;
105        if (indpost>maxind) indpost=maxind;
106        int v1=colortab[indpre];
107        int v2=colortab[indpost];
108        double d1=ind-indpre;
109        double d2=indpost-ind;
110        double v=indpre==indpost?v1:d2*v1+d1*v2; //d1+d2==1
111        return v;
112}
113
114void GenoConv_f90::setColors(Model &m) //sets fixed (independent from genes) colors and widths on a model, purely for aesthetic purposes
115{
116        //a rainbow on Joints: from the first one red, through middle green, to blue or violet - last
117        static int r[]={1,1,0,0,0,1};
118        static int g[]={0,1,1,1,0,0};
119        static int b[]={0,0,0,1,1,1};
120        int maxind=ARRAY_LENGTH(r)-1;
121
122        int joints_count=m.getJointCount();
123        for(int i=0;i<joints_count;i++)
124        {
125                Joint *j=m.getJoint(i);
126                double x=joints_count<2?0:(double)i/(joints_count-1); //0..1, postion in the rainbow
127                double ind=x*maxind;
128                j->vcolor.x=mix(r,maxind,ind);
129                j->vcolor.y=mix(g,maxind,ind);
130                j->vcolor.z=mix(b,maxind,ind);
131        }
132
133        int parts_count=m.getPartCount();
134        SList jlist;
135        for(int i=0;i<parts_count;i++)
136        {
137                Part *p=m.getPart(i);
138                jlist.clear();
139                int count=m.findJoints(jlist,p);
140                Pt3D averagecolor(0,0,0); //Parts will get averaged colors from all attached Joints
141                FOREACH(Joint*,j,jlist)
142                        averagecolor+=j->vcolor;
143                if (count>5) count=5; //avoid too fat...
144                p->vsize=0.3+count/15.0; //the more Joints is attached to a Part, the fatter it is
145                p->vcolor=averagecolor/count;
146        }
147}
148
149void GenoConv_f90::perturbPartLocations(Model &m) //deterministic "body noise", see APPLY_DETERMINISTIC_BODY_NOISE
150{
151        for(int i=0;i<m.getPartCount();i++)
152        {
153                Part *p=m.getPart(i);
154                Pt3D noise(
155                        ((i+1)  %10)-4.5  ,
156                        ((3*i+5)%10)-4.5  ,
157                        ((7*i+2)%10)-4.5
158                        ); //-4.5 .. 4.5 in each axis
159                p->p+=noise/1000;
160        }
161}
Note: See TracBrowser for help on using the repository browser.