Changed back to 50.
[pysvrt.git] / shape.cc
1 /*
2  *  svrt is the ``Synthetic Visual Reasoning Test'', an image
3  *  generator for evaluating classification performance of machine
4  *  learning systems, humans and primates.
5  *
6  *  Copyright (c) 2009 Idiap Research Institute, http://www.idiap.ch/
7  *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
8  *
9  *  This file is part of svrt.
10  *
11  *  svrt is free software: you can redistribute it and/or modify it
12  *  under the terms of the GNU General Public License version 3 as
13  *  published by the Free Software Foundation.
14  *
15  *  svrt is distributed in the hope that it will be useful, but
16  *  WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include "shape.h"
26
27 int Shape::generate_part_part(scalar_t *xp, scalar_t *yp, int *nb_pixels,
28                               scalar_t radius, scalar_t hole_radius,
29                               scalar_t x1, scalar_t y1, scalar_t x2, scalar_t y2) {
30   if(abs(x1 - x2) > gap_max || abs(y1 - y2) > gap_max) {
31
32     scalar_t d = sqrt(scalar_t(sq(x1 - x2) + sq(y1 - y2)))/5;
33     scalar_t x3, y3, dx, dy;
34
35     do {
36       // Isotropic jump
37       do {
38         dx = (2 * random_uniform_0_1() - 1) * d;
39         dy = (2 * random_uniform_0_1() - 1) * d;
40       } while(sq(dx) + sq(dy) > sq(d));
41       x3 = (x1 + x2) / 2 + dx;
42       y3 = (y1 + y2) / 2 + dy;
43     } while(sq(x3) + sq(y3) > sq(radius));
44
45     if(generate_part_part(xp, yp, nb_pixels,
46                           radius, hole_radius, x1, y1, x3, y3)) {
47       return 1;
48     }
49
50     if(generate_part_part(xp, yp, nb_pixels,
51                           radius, hole_radius, x3, y3, x2, y2)) {
52       return 1;
53     }
54
55   } else {
56
57     if(sq(x1) + sq(y1) >= sq(radius) || sq(x1) + sq(y1) < sq(hole_radius)) {
58       return 1;
59     }
60
61     xp[*nb_pixels] = x1;
62     yp[*nb_pixels] = y1;
63     (*nb_pixels)++;
64
65   }
66
67   return 0;
68 }
69
70 void Shape::generate_part(scalar_t *xp, scalar_t *yp, int *nb_pixels,
71                           scalar_t radius, scalar_t hole_radius) {
72   scalar_t x1, y1, x2, y2, x3, y3, x4, y4;
73   int err1, err2, err3, err4;
74
75   do {
76     *nb_pixels = 0;
77
78     do {
79       x1 = random_uniform_0_1() * radius;
80       y1 = random_uniform_0_1() * radius;
81     } while(sq(x1) + sq(y1) > sq(radius) || sq(x1) + sq(y1) < sq(hole_radius));
82
83     do {
84       x2 = -random_uniform_0_1() * radius;
85       y2 = random_uniform_0_1() * radius;
86     } while(sq(x2) + sq(y2) > sq(radius) || sq(x2) + sq(y2) < sq(hole_radius));
87
88     do {
89       x3 = -random_uniform_0_1() * radius;
90       y3 = -random_uniform_0_1() * radius;
91     } while(sq(x3) + sq(y3) > sq(radius) || sq(x3) + sq(y3) < sq(hole_radius));
92
93     do {
94       x4 = random_uniform_0_1() * radius;
95       y4 = -random_uniform_0_1() * radius;
96     } while(sq(x4) + sq(y4) > sq(radius) || sq(x4) + sq(y4) < sq(hole_radius));
97
98     n_pixels1 = *nb_pixels;
99     err1 = generate_part_part(xp, yp, nb_pixels, radius, hole_radius, x1, y1, x2, y2);
100     n_pixels2 = *nb_pixels;
101     err2 = generate_part_part(xp, yp, nb_pixels, radius, hole_radius, x2, y2, x3, y3);
102     n_pixels3 = *nb_pixels;
103     err3 = generate_part_part(xp, yp, nb_pixels, radius, hole_radius, x3, y3, x4, y4);
104     n_pixels4 = *nb_pixels;
105     err4 = generate_part_part(xp, yp, nb_pixels, radius, hole_radius, x4, y4, x1, y1);
106
107   } while(err1 || err2 || err3 || err4);
108 }
109
110 Shape::Shape() {
111   nb_pixels = 0;
112   x_pixels = 0;
113   y_pixels = 0;
114 }
115
116 Shape::~Shape() {
117   delete[] x_pixels;
118   delete[] y_pixels;
119 }
120
121 void Shape::randomize(scalar_t radius, scalar_t hole_radius) {
122   delete[] x_pixels;
123   delete[] y_pixels;
124   nb_pixels = 0;
125   scalar_t tmp_x_pixels[nb_max_pixels], tmp_y_pixels[nb_max_pixels];
126   generate_part(tmp_x_pixels, tmp_y_pixels, &nb_pixels, radius, hole_radius);
127   x_pixels = new scalar_t[nb_pixels];
128   y_pixels = new scalar_t[nb_pixels];
129   for(int p = 0; p < nb_pixels; p++) {
130     x_pixels[p] = tmp_x_pixels[p];
131     y_pixels[p] = tmp_y_pixels[p];
132   }
133
134   rotate(random_uniform_0_1() * M_PI * 2);
135
136   // { // ******************************* START ***************************
137 // #warning Test code added on 2009 Sep 09 18:15:25
138     // for(int p = 0; p < nb_pixels; p++) {
139       // cout << x_pixels[p] << " " << y_pixels[p] << endl;
140     // }
141   // } // ******************************** END ****************************
142
143 }
144
145 void Shape::copy(Shape *shape) {
146   delete[] x_pixels;
147   delete[] y_pixels;
148   nb_pixels = shape->nb_pixels;
149   n_pixels1 = shape->n_pixels1;
150   n_pixels2 = shape->n_pixels2;
151   n_pixels3 = shape->n_pixels3;
152   n_pixels4 = shape->n_pixels4;
153   x_pixels = new scalar_t[nb_pixels];
154   y_pixels = new scalar_t[nb_pixels];
155   for(int p = 0; p < nb_pixels; p++) {
156     x_pixels[p] = shape->x_pixels[p];
157     y_pixels[p] = shape->y_pixels[p];
158   }
159 }
160
161 void Shape::scale(scalar_t s) {
162   for(int p = 0; p < nb_pixels; p++) {
163     x_pixels[p] *= s;
164     y_pixels[p] *= s;
165   }
166 }
167
168 void Shape::rotate(scalar_t alpha) {
169   scalar_t ux = cos(alpha), uy = -sin(alpha);
170   scalar_t vx = sin(alpha), vy = cos(alpha);
171   scalar_t x, y;
172   for(int p = 0; p < nb_pixels; p++) {
173     x = x_pixels[p] * ux + y_pixels[p] * uy;
174     y = x_pixels[p] * vx + y_pixels[p] * vy;
175     x_pixels[p] = x;
176     y_pixels[p] = y;
177   }
178 }
179
180 void Shape::symmetrize(scalar_t axis_x, scalar_t axis_y) {
181   scalar_t sql = sq(axis_x) + sq(axis_y);
182   scalar_t u, v;
183   for(int p = 0; p < nb_pixels; p++) {
184     u =   x_pixels[p] * axis_y - y_pixels[p] * axis_x;
185     v =   x_pixels[p] * axis_x + y_pixels[p] * axis_y;
186     u = - u;
187     x_pixels[p] = (  u * axis_y + v * axis_x) / sql;
188     y_pixels[p] = (- u * axis_x + v * axis_y) / sql;
189   }
190 }
191
192
193 int Shape::overwrites(Vignette *vignette, scalar_t xc, scalar_t yc, int n1, int n2) {
194   int x1 = int(x_pixels[n1 % nb_pixels] + xc);
195   int y1 = int(y_pixels[n1 % nb_pixels] + yc);
196   int x2 = int(x_pixels[n2 % nb_pixels] + xc);
197   int y2 = int(y_pixels[n2 % nb_pixels] + yc);
198   int n3 = (n1 + n2) / 2;
199
200   if(n1 + 1 < n2 && (abs(x1 - x2) > 1 || abs(y1 - y2) > 1)) {
201     return
202       overwrites(vignette, xc, yc, n1, n3) ||
203       overwrites(vignette, xc, yc, n3, n2);
204   } else {
205
206     if(x1 >= margin && x1 < Vignette::width - margin &&
207        y1 >= margin && y1 < Vignette::height - margin) {
208
209       if(margin > 0) {
210         for(int xx = x1 - margin; xx <= x1 + margin; xx++) {
211           for(int yy = y1 - margin; yy <= y1 + margin; yy++) {
212             if(vignette->content[xx + Vignette::width * yy] != 255) {
213               return 1;
214             }
215           }
216         }
217       }
218
219       return 0;
220     } else {
221       return 1;
222     }
223   }
224 }
225
226 int Shape::overwrites(Vignette *vignette, scalar_t xc, scalar_t yc) {
227   return
228     overwrites(vignette, xc, yc, n_pixels1, n_pixels2) ||
229     overwrites(vignette, xc, yc, n_pixels2, n_pixels3) ||
230     overwrites(vignette, xc, yc, n_pixels3, n_pixels4) ||
231     overwrites(vignette, xc, yc, n_pixels4, nb_pixels);
232 }
233
234 void Shape::draw(int part_number, Vignette *vignette, scalar_t xc, scalar_t yc, int n1, int n2) {
235   int x1 = int(x_pixels[n1 % nb_pixels] + xc);
236   int y1 = int(y_pixels[n1 % nb_pixels] + yc);
237   int x2 = int(x_pixels[n2 % nb_pixels] + xc);
238   int y2 = int(y_pixels[n2 % nb_pixels] + yc);
239   int n3 = (n1 + n2) / 2;
240
241   if(n1 + 1 < n2 && (abs(x1 - x2) > 1 || abs(y1 - y2) > 1)) {
242     draw(part_number, vignette, xc, yc, n1, n3);
243     draw(part_number, vignette, xc, yc, n3, n2);
244   } else {
245     if(x1 >= margin && x1 < Vignette::width-margin &&
246        y1 >= margin && y1 < Vignette::height-margin) {
247       vignette->content[x1 + Vignette::width * y1] = 0;
248 #ifdef KEEP_PART_PRESENCE
249       vignette->part_presence[x1 + Vignette::width * y1] |= (1 << part_number);
250 #endif
251     } else {
252       abort();
253     }
254   }
255 }
256
257 void Shape::draw(int part_number, Vignette *vignette, scalar_t xc, scalar_t yc) {
258   draw(part_number, vignette, xc, yc, n_pixels1, n_pixels2);
259   draw(part_number, vignette, xc, yc, n_pixels2, n_pixels3);
260   draw(part_number, vignette, xc, yc, n_pixels3, n_pixels4);
261   draw(part_number, vignette, xc, yc, n_pixels4, nb_pixels);
262 }