source: cpp/frams/genetics/fF/conv_fF.cpp @ 178

Last change on this file since 178 was 178, checked in by Maciej Komosinski, 8 years ago

Changed cryptic double[4] into a meaningful struct

  • Property svn:eol-style set to native
File size: 8.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_fF.h"
6#include "fF_genotype.h"
7#include <frams/model/model.h>
8#include <common/nonstd_stl.h>
9
10GenoConv_fF0::GenoConv_fF0()
11{
12        name = "7-value Foraminifera encoding";
13        in_format = 'F';
14        out_format = '0';
15        mapsupport = 0;
16        cosines = new double[fF_LATITUDE_NUM];
17        sines = new double[fF_LATITUDE_NUM];
18        precompute_cos_and_sin();
19}
20
21GenoConv_fF0::~GenoConv_fF0()
22{
23        delete[] cosines;
24        delete[] sines;
25}
26
27SString GenoConv_fF0::convert(SString &in, MultiMap *map)
28{
29        fF_growth_params gp;
30        if (!gp.load(in)) //invalid input genotype?
31                return ""; //so we return an invalid f0 genotype
32
33        double div_radius_length = 1; //div_radius_length=1 or kx=ky=kz=1
34        double radius = 1;
35
36        Model m;
37        m.open();
38
39        m.vis_style = "foram"; //dedicated visual look for Foraminifera
40
41        // subsequent parts (chambers) are placed relative to the previous part's orientation and location
42        Part *p1, *p2;
43
44        fF_chamber3d **chambers = new fF_chamber3d*[gp.number_of_chambers];
45
46        for (int i = 0; i < gp.number_of_chambers; i++)
47                createSphere(i, chambers, radius, div_radius_length, gp.translation, gp.angle1, gp.angle2, gp.scalex, gp.scaley, gp.scalez);
48
49        p1 = m.addNewPart(Part::SHAPE_ELLIPSOID);
50        p1->p = Pt3D(chambers[0]->centerX, chambers[0]->centerY, chambers[0]->centerZ);
51
52
53        for (int i = 1; i < gp.number_of_chambers; i++, p1 = p2)
54        {
55                p2 = m.addNewPart(Part::SHAPE_ELLIPSOID);
56                p2->scale = p1->scale.entrywiseProduct(Pt3D(gp.scalex, gp.scaley, gp.scalez)); //each part's scale is its predecessor's scale * scaling
57
58                p2->p = Pt3D(chambers[i]->centerX, chambers[i]->centerY, chambers[i]->centerZ);
59
60                m.addNewJoint(p1, p2, Joint::SHAPE_SOLID); //all parts must be connected
61        }
62
63        for (int i = 0; i < gp.number_of_chambers; i++)
64                delete chambers[i];
65        delete[]chambers;
66
67        m.close();
68        return m.getF0Geno().getGene();
69}
70
71void GenoConv_fF0::createSphere(int which, fF_chamber3d **chambers, double radius_, double div_radius_length_, double div_vector_length_,
72        double alpha_, double gamma_, double kx_, double ky_, double kz_)
73{
74        chambers[which] = new fF_chamber3d(0.0f, 0.0f, 0.0f,
75                (float)radius_, (float)radius_ * (float)kx_, 0.0f, 0.0f,
76                (float)(radius_ * div_vector_length_), 0.0f, 0.0f, 0.0f, 0.0f);
77        if (which == 0)
78                chambers[which]->points = generate_points(chambers[which], which, kx_, ky_, kz_);
79        if (which > 0) {
80                /* old radius */
81                double radiusOld, radius;
82                radiusOld = chambers[which - 1]->radius;
83                radius = div_radius_length_ * radiusOld;
84                /* new growth vector length */
85                double len = radius * div_vector_length_;
86                if (radius < fF_TOO_LITTLE) {
87                        radius = fF_TOO_LITTLE;
88                        if (fabs(len) >(fF_TOO_MUCH * radius)) {
89                                len = ((len < 0) ? (-1) : 1) * fF_TOO_MUCH * radius;
90                        }
91                }
92                if (len == 0) {
93                        len = -0.0000001;
94                }
95
96                /* aperture of the previous chamber */
97                double pzx = chambers[which - 1]->holeX;
98                double pzy = chambers[which - 1]->holeY;
99                double pzz = chambers[which - 1]->holeZ;
100
101                //center of the previous chamber
102                double pcx = chambers[which - 1]->centerX;
103                double pcy = chambers[which - 1]->centerY;
104                double pcz = chambers[which - 1]->centerZ;
105
106                /* aperture of the next to last chamber */
107                double ppx;
108                double ppy;
109                double ppz;
110
111                if (which == 1)
112                {
113                        ppx = pcx;
114                        ppy = pcy;
115                        ppz = pcz;
116                }
117                else
118                {
119                        ppx = chambers[which - 2]->holeX;
120                        ppy = chambers[which - 2]->holeY;
121                        ppz = chambers[which - 2]->holeZ;
122                }
123
124                double pzxprim = pzx - ppx;
125                double pzyprim = pzy - ppy;
126                double angle;
127
128                angle = atan2(pzyprim, pzxprim);
129                double alpha = angle - alpha_;
130
131
132                double gamma = chambers[which - 1]->phi + gamma_;
133
134                /* x */
135                double wx = len * cos(alpha);
136                /* y */
137                double wy = len * sin(alpha);
138                /* y */
139                double wz = len * sin(alpha) * sin(gamma);
140
141                /*center of the new sphere*/
142                double x = pzx + wx;
143                double y = pzy + wy;
144                double z = pzz + wz;
145
146                chambers[which]->centerX = (float)x;
147                chambers[which]->centerY = (float)y;
148                chambers[which]->centerZ = (float)z;
149                chambers[which]->radius = (float)radius;
150                chambers[which]->vectorTfX = (float)wx;
151                chambers[which]->vectorTfY = (float)wy;
152                chambers[which]->vectorTfZ = (float)wz;
153                chambers[which]->beta = (float)alpha;
154                chambers[which]->phi = (float)gamma;
155
156                chambers[which]->points = generate_points(chambers[which], which, kx_, ky_, kz_);
157                search_hid(which, chambers, kx_, ky_, kz_);
158                int pun;
159                pun = find_hole(which, pzx, pzy, pzz, chambers, kx_, ky_, kz_);
160
161                chambers[which]->holeX = (float)chambers[which]->points[pun].x;
162                chambers[which]->holeY = (float)chambers[which]->points[pun].y;
163                chambers[which]->holeZ = (float)chambers[which]->points[pun].z;
164        }
165}
166
167void GenoConv_fF0::precompute_cos_and_sin()
168{
169        int i;
170        double pi = acos(-1.0);
171        double angle = pi / (((double)fF_LATITUDE_NUM)*0.5);
172        for (i = 0; i < fF_LATITUDE_NUM; i++)
173        {
174                cosines[i] = cos((double)i * angle);
175                sines[i] = sin((double)i * angle);
176        }
177}
178
179fF_point* GenoConv_fF0::generate_points(fF_chamber3d *chamber, int which, double kx_, double ky_, double kz_)
180{
181        float radius = chamber->radius;
182        float cenx = chamber->centerX;
183        float ceny = chamber->centerY;
184        float cenz = chamber->centerZ;
185
186        double maxX = 0;
187        double maxY = 0;
188        double minX = 0;
189        double minY = 0;
190        double minZ = 0;
191
192        double kx = 1;
193        double ky = 1;
194        double kz = 1;
195
196        if (which > 0)
197        {
198                for (int kt = 1; kt < (which + 1); kt++)
199                {
200                        kx = kx * kx_;
201                        ky = ky * ky_;
202                        kz = kz * kz_;
203                }
204        }
205
206        bool all_k_ones = kx_ == 1 && ky_ == 1 && kz_ == 1;
207
208        double rx = all_k_ones ? radius : kx;
209        double ry = all_k_ones ? radius : ky;
210        double rz = all_k_ones ? radius : kz;
211
212        fF_point *points = new fF_point[fF_SIZE];
213
214        for (int i = 0; i < fF_LONGITUDE_NUM; i++)
215        {
216                double y = ceny + ry * cosines[i];
217
218                for (int j = 0; j < fF_LATITUDE_NUM; j++)
219                {
220                        double x = cenx + rx * cosines[j] * sines[i];
221                        double z = cenz + rz * sines[j] * sines[i];
222                        fF_point &p = points[(i * fF_LATITUDE_NUM) + j];
223                        p.x = x;
224                        p.y = y;
225                        p.z = z;
226                        p.inside = false;
227
228                        if (x < minX) minX = x;
229                        if (x > maxX) maxX = x;
230                        if (y < minY) minY = y;
231                        if (y > maxY) maxY = y;
232
233                        if (z < minZ) minZ = z;
234                }
235        }
236        return points;
237
238}
239
240double GenoConv_fF0::dist(double x1, double y1, double z1, double x2, double y2, double z2)
241{
242        return sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1) + (z2 - z1)*(z2 - z1));
243}
244
245void GenoConv_fF0::search_hid(int nr, fF_chamber3d **spheres, double kx_, double ky_, double kz_)
246{
247        double kxsq = kx_*kx_;
248        double kysq = ky_*ky_;
249        double kzsq = kz_*kz_;
250
251        for (int i = 0; i < nr; i++)
252        {
253                double srX0 = spheres[i]->centerX;
254                double srY0 = spheres[i]->centerY;
255                double srZ0 = spheres[i]->centerZ;
256
257                double radsq = spheres[i]->radius * spheres[i]->radius;
258
259                double a2 = kx_ != 1 ? kxsq : radsq;
260                double b2 = ky_ != 1 ? kysq : radsq;
261                double c2 = kzsq * radsq;
262
263                for (int j = 0; j < fF_AMOUNT; j++)
264                {
265                        fF_point &p = spheres[nr]->points[j];
266
267                        double up1 = (p.x - srX0) * (p.x - srX0);
268                        double up2 = (p.y - srY0) * (p.y - srY0);
269                        double up3 = (p.z - srZ0) * (p.z - srZ0);
270
271                        double exp1 = up1 / a2;
272                        double exp2 = up2 / b2;
273                        double exp3 = up3 / c2;
274
275                        double result = exp1 + exp2 + exp3;
276
277                        if (result < fF_THICK_RATIO)
278                        {
279                                p.inside = true;
280                        }
281                }
282        }
283}
284
285int GenoConv_fF0::find_hole(int which, double x, double y, double z, fF_chamber3d **chambers, double kx_, double ky_, double kz_)
286{
287        int found = -1;
288        double distsq_found;
289
290        double kxsq = kx_*kx_;
291        double kysq = ky_*ky_;
292        double kzsq = kz_*kz_;
293
294        for (int i = 0; i < fF_AMOUNT; i++)
295        {
296                fF_point &p = chambers[which]->points[i];
297                if (!p.inside) //it is not inside another chamber
298                {
299                        double distancesq = (p.x - x)*(p.x - x) + (p.y - y)*(p.y - y) + (p.z - z)*(p.z - z);
300                        if (found < 0)
301                        {
302                                found = i;
303                                distsq_found = distancesq;
304                        }
305                        if (distancesq < distsq_found)
306                        {
307                                if (which != 0)
308                                {
309                                        bool good = true;
310                                        for (int j = 0; j < which && good; j++)
311                                        {
312                                                double srX0 = chambers[j]->centerX;
313                                                double srY0 = chambers[j]->centerY;
314                                                double srZ0 = chambers[j]->centerZ;
315
316                                                double radsq = chambers[j]->radius * chambers[j]->radius;
317
318                                                double a2 = kxsq * radsq;
319                                                double b2 = kysq * radsq;
320                                                double c2 = kzsq * radsq;
321
322                                                double up1 = (p.x - srX0) * (p.x - srX0);
323                                                double up2 = (p.y - srY0) * (p.y - srY0);
324                                                double up3 = (p.z - srZ0) * (p.z - srZ0);
325
326                                                double exp1 = up1 / a2;
327                                                double exp2 = up2 / b2;
328                                                double exp3 = up3 / c2;
329
330                                                double result = exp1 + exp2 + exp3;
331                                                if (result < 1.0)
332                                                {
333                                                        good = false;
334                                                }
335                                        }
336                                        if (good)
337                                        {
338                                                found = i;
339                                                distsq_found = distancesq;
340                                        }
341                                }
342                        }
343                }
344        }
345
346        return found;
347}
Note: See TracBrowser for help on using the repository browser.