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

Last change on this file since 736 was 736, checked in by Maciej Komosinski, 2 years ago

Added the new "using_checkpoints" argument to genetic converters so they can now call Model.checkpoint() when desired, see conv_f1.cpp for an example

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