source: cpp/frams/genetics/f9/f9_conv.cpp @ 999

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

Increased SString and std::string compatibility: introduced length(), size(), and capacity(), and removed legacy methods that have std::string equivalents

  • Property svn:eol-style set to native
File size: 5.5 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "f9_conv.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 genetic representation easily produces perfectly vertical sticks that would stay upright forever in simulation. 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 = 1;
18}
19
20
21const char* turtle_commands_f9 = "LRBFDU";
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, bool using_checkpoints)
28{
29        vector<XYZ_LOC> vertices;
30        XYZ_LOC current;
31        Model m;
32        m.open(using_checkpoints);
33        int recently_added = addSegment(m, 0, vertices, current, 0xDead);
34        for (int i = 0; i < in.length(); 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, i, vertices, current, recently_added);
47                        m.checkpoint();
48                }
49        }
50#ifdef APPLY_DETERMINISTIC_BODY_NOISE
51        perturbPartLocations(m);
52#endif
53        setColors(m, recently_added);
54        m.close();
55        if (m.getPartCount() < 2) //only one part <=> there were no valid turtle commands in the input genotype
56                return ""; //so we return an invalid f0 genotype
57        if (map != NULL)
58                m.getCurrentToF0Map(*map);
59        return m.getF0Geno().getGenes();
60}
61
62int GenoConv_f90::addSegment(Model &m, int genenr, vector<XYZ_LOC> &vertices, const XYZ_LOC &new_vertex, int recently_added)
63{
64        if (vertices.size() < 1) //empty model?
65        {
66                return addNewVertex(m, vertices, new_vertex);
67        }
68        else
69        {
70                int vertex_here = findVertexAt(vertices, new_vertex);
71                if (vertex_here < 0) //need to create a new Part
72                {
73                        vertex_here = addNewVertex(m, vertices, new_vertex);
74                } //else there already exists a Part in new_vertex; new Joint may or may not be needed
75                Part *p1 = m.getPart(recently_added);
76                Part *p2 = m.getPart(vertex_here);
77                p1->addMapping(MultiRange(genenr, genenr));
78                p2->addMapping(MultiRange(genenr, genenr));
79
80                int j12 = m.findJoint(p1, p2);
81                int j21 = m.findJoint(p2, p1);
82                if (j12 >= 0)
83                        m.getJoint(j12)->addMapping(MultiRange(genenr, genenr));
84                else if (j21 >= 0)
85                        m.getJoint(j21)->addMapping(MultiRange(genenr, genenr));
86                else //both j12<0 and j21<0. New Joint needed. Should always happen if we just created a new Part (vertex_here was <0)
87                        m.addNewJoint(p1, p2)->addMapping(MultiRange(genenr, genenr));
88                return vertex_here;
89        }
90}
91
92int GenoConv_f90::findVertexAt(vector<XYZ_LOC> &vertices, const XYZ_LOC &vertex)
93{
94        for (size_t i = 0; i < vertices.size(); i++)
95                if (vertices[i].same_coordinates(vertex)) return i;
96        return -1;
97}
98
99
100int GenoConv_f90::addNewVertex(Model &m, vector<XYZ_LOC> &vertices, const XYZ_LOC &new_vertex)
101{
102        Part *p = new Part;
103        p->p.x = new_vertex.x;
104        p->p.y = new_vertex.y;
105        p->p.z = new_vertex.z;
106        m.addPart(p);
107
108        vertices.push_back(new_vertex);
109        return vertices.size() - 1;
110}
111
112double mix(int *colortab, int maxind, double ind)
113{
114        int indpre = (int)ind;
115        int indpost = indpre + 1;
116        if (indpost > maxind) indpost = maxind;
117        int v1 = colortab[indpre];
118        int v2 = colortab[indpost];
119        double d1 = ind - indpre;
120        double d2 = indpost - ind;
121        double v = indpre == indpost ? v1 : d2 * v1 + d1 * v2; //d1+d2==1
122        return v;
123}
124
125void GenoConv_f90::setColors(Model &m, int last_added_part) //sets fixed (independent from genes) colors and widths on a model, purely for aesthetic purposes
126{
127        //a rainbow on Joints: from the first one red, through middle green, to blue or violet - last
128        static int r[] = { 1, 1, 0, 0, 0, 1 };
129        static int g[] = { 0, 1, 1, 1, 0, 0 };
130        static int b[] = { 0, 0, 0, 1, 1, 1 };
131        int maxind = ARRAY_LENGTH(r) - 1;
132
133        int joints_count = m.getJointCount();
134        for (int i = 0; i < joints_count; i++)
135        {
136                Joint *j = m.getJoint(i);
137                double x = joints_count < 2 ? 0 : (double)i / (joints_count - 1); //0..1, postion in the rainbow
138                double ind = x * maxind;
139                j->vcolor.x = mix(r, maxind, ind);
140                j->vcolor.y = mix(g, maxind, ind);
141                j->vcolor.z = mix(b, maxind, ind);
142        }
143
144        int parts_count = m.getPartCount();
145        SList jlist;
146        for (int i = 0; i < parts_count; i++)
147        {
148                Part *p = m.getPart(i);
149                jlist.clear();
150                int count = m.findJoints(jlist, p);
151                Pt3D averagecolor(0, 0, 0); //Parts will get averaged colors from all attached Joints
152                FOREACH(Joint*, j, jlist)
153                        averagecolor += j->vcolor;
154                p->vcolor = averagecolor / count;
155                if (count > 5) count = 5; //avoid too fat...
156                p->vsize = 0.3 + count / 15.0; //the more Joints is attached to a Part, the fatter it is
157        }
158        //m.getPart(0)->vcolor = Pt3D(0, 0, 0); //mark first Part black - a visual aid for easier editing
159        m.getPart(last_added_part)->vcolor = Pt3D(1, 1, 1); //mark last Part white - a visual aid for easier editing
160}
161
162void GenoConv_f90::perturbPartLocations(Model &m) //deterministic "body noise", see APPLY_DETERMINISTIC_BODY_NOISE
163{
164        for (int i = 0; i < m.getPartCount(); i++)
165        {
166                Part *p = m.getPart(i);
167                Pt3D noise(
168                        ((i + 1) % 10) - 4.5,
169                        ((3 * i + 5) % 10) - 4.5,
170                        ((7 * i + 2) % 10) - 4.5
171                ); //-4.5 .. 4.5 in each axis
172                p->p += noise / 1000;
173        }
174}
Note: See TracBrowser for help on using the repository browser.