Update.
[universe.git] / polygon.cc
1
2 // Written and (C) by Francois Fleuret
3 // Contact <francois.fleuret@idiap.ch> for comments & bug reports
4
5 #include <cmath>
6 #include "polygon.h"
7
8 static const scalar_t dl = 20.0;
9 static const scalar_t repulsion_constant = 0.2;
10 static const scalar_t dissipation = 0.5;
11
12 Polygon::Polygon(scalar_t mass,
13                  scalar_t red, scalar_t green, scalar_t blue,
14                  scalar_t *x, scalar_t *y,
15                  int nv) : _mass(mass),
16                            _moment_of_inertia(0), _radius(0),
17                            _relative_x(new scalar_t[nv]), _relative_y(new scalar_t[nv]),
18                            _total_nb_dots(0),
19                            _nb_dots(new int[nv]),
20                            _effecting_edge(0),
21                            _length(new scalar_t[nv]),
22                            _triangles(new Triangle[nv-2]),
23                            _initialized(false), _nailed(false),
24                            _nb_vertices(nv),
25                            _x(new scalar_t[nv]), _y(new scalar_t[nv]),
26                            _red(red), _green(green), _blue(blue) {
27   _last_center_x = 0;
28   _last_center_y = 0;
29   _last_theta = 0;
30
31   if(x) for(int i = 0; i < nv; i++) _relative_x[i] = x[i];
32   if(y) for(int i = 0; i < nv; i++) _relative_y[i] = y[i];
33 }
34
35 Polygon::~Polygon() {
36   delete[] _relative_x;
37   delete[] _relative_y;
38   delete[] _x;
39   delete[] _y;
40   delete[] _nb_dots;
41   delete[] _length;
42   delete[] _triangles;
43   delete[] _effecting_edge;
44 }
45
46 Polygon *Polygon::clone() {
47   return new Polygon(_mass, _red, _green, _blue, _relative_x, _relative_y, _nb_vertices);
48 }
49
50 void Polygon::color_xfig(XFigTracer *tracer) {
51   tracer->add_color(int(255 * _red), int(255 * _green), int(255 * _blue));
52 }
53
54 void Polygon::print_xfig(XFigTracer *tracer) {
55   tracer->draw_polygon(int(255 * _red), int(255 * _green), int(255 * _blue),
56                        _nb_vertices, _x, _y);
57 }
58
59 #ifdef X11_SUPPORT
60 void Polygon::draw(SimpleWindow *window) {
61   window->color(_red, _green, _blue);
62   int x[_nb_vertices], y[_nb_vertices];
63   for(int n = 0; n < _nb_vertices; n++) {
64     x[n] = int(_x[n]);
65     y[n] = int(_y[n]);
66   }
67   window->fill_polygon(_nb_vertices, x, y);
68 }
69
70 void Polygon::draw_contours(SimpleWindow *window) {
71   int x[_nb_vertices], y[_nb_vertices];
72   for(int n = 0; n < _nb_vertices; n++) {
73     x[n] = int(_x[n]);
74     y[n] = int(_y[n]);
75   }
76   window->color(0.0, 0.0, 0.0);
77   // window->color(1.0, 1.0, 1.0);
78   for(int n = 0; n < _nb_vertices; n++) {
79     window->draw_line(x[n], y[n], x[(n+1)%_nb_vertices], y[(n+1)%_nb_vertices]);
80   }
81 }
82 #endif
83
84 #ifdef CAIRO_SUPPORT
85 void Polygon::draw(cairo_t* context_resource) {
86   cairo_set_line_width(context_resource, 1.0);
87   cairo_set_source_rgb (context_resource, _red, _green, _blue);
88   cairo_move_to(context_resource, _x[0], _y[0]);
89   for(int n = 0; n < _nb_vertices; n++) {
90     cairo_line_to(context_resource, _x[n], _y[n]);
91   }
92   cairo_close_path(context_resource);
93   cairo_stroke_preserve(context_resource);
94   cairo_fill(context_resource);
95 }
96
97 void Polygon::draw_contours(cairo_t* context_resource) {
98   cairo_set_line_width(context_resource, 1.0);
99   cairo_set_source_rgb (context_resource, 0.0, 0.0, 0.0);
100   // cairo_set_source_rgb (context_resource, 1.0, 1.0, 1.0);
101   cairo_move_to(context_resource, _x[0], _y[0]);
102   for(int n = 0; n < _nb_vertices; n++) {
103     cairo_line_to(context_resource, _x[n], _y[n]);
104   }
105   cairo_close_path(context_resource);
106   cairo_stroke(context_resource);
107 }
108 #endif
109
110 void Polygon::set_vertex(int k, scalar_t x, scalar_t y) {
111   _relative_x[k] = x;
112   _relative_y[k] = y;
113 }
114
115 void Polygon::set_position(scalar_t center_x, scalar_t center_y, scalar_t theta) {
116   _center_x = center_x;
117   _center_y = center_y;
118   _theta = theta;
119 }
120
121 void Polygon::set_speed(scalar_t dcenter_x, scalar_t dcenter_y, scalar_t dtheta) {
122   _dcenter_x = dcenter_x;
123   _dcenter_y = dcenter_y;
124   _dtheta = dtheta;
125 }
126
127 bool Polygon::contain(scalar_t x, scalar_t y) {
128   for(int t = 0; t < _nb_vertices-2; t++) {
129     scalar_t xa = _x[_triangles[t].a], ya = _y[_triangles[t].a];
130     scalar_t xb = _x[_triangles[t].b], yb = _y[_triangles[t].b];
131     scalar_t xc = _x[_triangles[t].c], yc = _y[_triangles[t].c];
132     if(prod_vect(x - xa, y - ya, xb - xa, yb - ya) <= 0 &&
133        prod_vect(x - xb, y - yb, xc - xb, yc - yb) <= 0 &&
134        prod_vect(x - xc, y - yc, xa - xc, ya - yc) <= 0) return true;
135   }
136   return false;
137 }
138
139 void Polygon::triangularize(int &nt, int nb, int *index) {
140   if(nb == 3) {
141
142     if(nt >= _nb_vertices-2) {
143       cerr << "Error type #1 in triangularization." << endl;
144       exit(1);
145     }
146
147     _triangles[nt].a = index[0];
148     _triangles[nt].b = index[1];
149     _triangles[nt].c = index[2];
150     nt++;
151
152   } else {
153     int best_m = -1, best_n = -1;
154     scalar_t best_split = -1, det, s = -1, t = -1;
155
156     for(int n = 0; n < nb; n++) for(int m = 0; m < n; m++) if(n > m+1 && m+nb > n+1) {
157       bool no_intersection = true;
158       for(int k = 0; no_intersection & (k < nb); k++)
159         if(k != n && k != m && (k+1)%nb != n && (k+1)%nb != m) {
160           intersection(_relative_x[index[n]], _relative_y[index[n]],
161                        _relative_x[index[m]], _relative_y[index[m]],
162                        _relative_x[index[k]], _relative_y[index[k]],
163                        _relative_x[index[(k+1)%nb]], _relative_y[index[(k+1)%nb]], det, s, t);
164           no_intersection = det == 0 || s < 0 || s > 1 || t < 0 || t > 1;
165         }
166
167       if(no_intersection) {
168         scalar_t a1 = 0, a2 = 0;
169         for(int k = 0; k < nb; k++) if(k >= m && k < n)
170           a1 += prod_vect(_relative_x[index[k]] - _relative_x[index[m]],
171                           _relative_y[index[k]] - _relative_y[index[m]],
172                           _relative_x[index[k+1]] - _relative_x[index[m]],
173                           _relative_y[index[k+1]] - _relative_y[index[m]]);
174         else
175           a2 += prod_vect(_relative_x[index[k]] - _relative_x[index[m]],
176                           _relative_y[index[k]] - _relative_y[index[m]],
177                           _relative_x[index[(k+1)%nb]] - _relative_x[index[m]],
178                           _relative_y[index[(k+1)%nb]] - _relative_y[index[m]]);
179
180         if((a1 * a2 > 0 && best_split < 0) || (abs(a1 - a2) < best_split)) {
181           best_n = n; best_m = m;
182           best_split = abs(a1 - a2);
183         }
184       }
185     }
186
187     if(best_n >= 0 && best_m >= 0) {
188       int index_neg[nb], index_pos[nb];
189       int neg = 0, pos = 0;
190       for(int k = 0; k < nb; k++) {
191         if(k >= best_m && k <= best_n) index_pos[pos++] = index[k];
192         if(k <= best_m || k >= best_n) index_neg[neg++] = index[k];
193       }
194       if(pos < 3 || neg < 3) {
195         cerr << "Error type #2 in triangularization." << endl;
196         exit(1);
197       }
198       triangularize(nt, pos, index_pos);
199       triangularize(nt, neg, index_neg);
200     } else {
201       cerr << "Error type #3 in triangularization." << endl;
202       exit(1);
203     }
204   }
205 }
206
207 void Polygon::initialize(int nb_polygons) {
208   scalar_t a;
209
210   _nb_polygons = nb_polygons;
211
212   a = _relative_x[_nb_vertices - 1] * _relative_y[0] - _relative_x[0] * _relative_y[_nb_vertices - 1];
213   for(int n = 0; n < _nb_vertices - 1; n++)
214     a += _relative_x[n] * _relative_y[n+1] - _relative_x[n+1] * _relative_y[n];
215   a *= 0.5;
216
217   // Reorder the vertices
218
219   if(a < 0) {
220     a = -a;
221     scalar_t x, y;
222     for(int n = 0; n < _nb_vertices / 2; n++) {
223       x = _relative_x[n];
224       y = _relative_y[n];
225       _relative_x[n] = _relative_x[_nb_vertices - 1 - n];
226       _relative_y[n] = _relative_y[_nb_vertices - 1 - n];
227       _relative_x[_nb_vertices - 1 - n] = x;
228       _relative_y[_nb_vertices - 1 - n] = y;
229     }
230   }
231
232   // Compute the center of mass and moment of inertia
233
234   scalar_t sx, sy, w;
235   w = 0;
236   sx = 0;
237   sy = 0;
238   for(int n = 0; n < _nb_vertices; n++) {
239     int np = (n+1)%_nb_vertices;
240     w =_relative_x[n] * _relative_y[np] - _relative_x[np] * _relative_y[n];
241     sx += (_relative_x[n] + _relative_x[np]) * w;
242     sy += (_relative_y[n] + _relative_y[np]) * w;
243   }
244   sx /= 6 * a;
245   sy /= 6 * a;
246
247   _radius = 0;
248   for(int n = 0; n < _nb_vertices; n++) {
249     _relative_x[n] -= sx;
250     _relative_y[n] -= sy;
251     scalar_t r = sqrt(sq(_relative_x[n]) + sq(_relative_y[n]));
252     if(r > _radius) _radius = r;
253   }
254
255   scalar_t num = 0, den = 0;
256   for(int n = 0; n < _nb_vertices; n++) {
257     int np = (n+1)%_nb_vertices;
258     den += abs(prod_vect(_relative_x[np], _relative_y[np], _relative_x[n], _relative_y[n]));
259     num += abs(prod_vect(_relative_x[np], _relative_y[np], _relative_x[n], _relative_y[n])) *
260       (_relative_x[np] * _relative_x[np] + _relative_y[np] * _relative_y[np] +
261        _relative_x[np] * _relative_x[n] + _relative_y[np] * _relative_y[n] +
262        _relative_x[n] * _relative_x[n] + _relative_y[n] * _relative_y[n]);
263   }
264
265   _moment_of_inertia = num / (6 * den);
266
267   scalar_t vx = cos(_theta), vy = sin(_theta);
268
269   for(int n = 0; n < _nb_vertices; n++) {
270     _x[n] = _center_x + _relative_x[n] * vx + _relative_y[n] * vy;
271     _y[n] = _center_y - _relative_x[n] * vy + _relative_y[n] * vx;
272   }
273
274   scalar_t length;
275   _total_nb_dots = 0;
276   for(int n = 0; n < _nb_vertices; n++) {
277     length = sqrt(sq(_relative_x[n] - _relative_x[(n+1)%_nb_vertices]) +
278                   sq(_relative_y[n] - _relative_y[(n+1)%_nb_vertices]));
279     _length[n] = length;
280     _nb_dots[n] = int(length / dl + 1);
281     _total_nb_dots += _nb_dots[n];
282   }
283
284   delete[] _effecting_edge;
285   _effecting_edge = new int[_nb_polygons * _total_nb_dots];
286   for(int p = 0; p < _nb_polygons * _total_nb_dots; p++) _effecting_edge[p] = -1;
287
288   int nt = 0;
289   int index[_nb_vertices];
290   for(int n = 0; n < _nb_vertices; n++) index[n] = n;
291   triangularize(nt, _nb_vertices, index);
292
293   _initialized = true;
294 }
295
296 bool Polygon::update(scalar_t dt) {
297   if(!_nailed) {
298     _center_x += _dcenter_x * dt;
299     _center_y += _dcenter_y * dt;
300     _theta += _dtheta * dt;
301   }
302
303   scalar_t d = exp(log(dissipation) * dt);
304   _dcenter_x *= d;
305   _dcenter_y *= d;
306   _dtheta *= d;
307
308   scalar_t vx = cos(_theta), vy = sin(_theta);
309
310   for(int n = 0; n < _nb_vertices; n++) {
311     _x[n] = _center_x + _relative_x[n] * vx + _relative_y[n] * vy;
312     _y[n] = _center_y - _relative_x[n] * vy + _relative_y[n] * vx;
313   }
314
315   if(abs(_center_x - _last_center_x) +
316      abs(_center_y - _last_center_y) +
317      abs(_theta - _last_theta) * _radius > 0.1) {
318     _last_center_x = _center_x;
319     _last_center_y = _center_y;
320     _last_theta = _theta;
321     return true;
322   } else return false;
323 }
324
325 scalar_t Polygon::relative_x(scalar_t ax, scalar_t ay) {
326   return (ax - _center_x) * cos(_theta) - (ay - _center_y) * sin(_theta);
327 }
328
329 scalar_t Polygon::relative_y(scalar_t ax, scalar_t ay) {
330   return (ax - _center_x) * sin(_theta) + (ay - _center_y) * cos(_theta);
331 }
332
333 scalar_t Polygon::absolute_x(scalar_t rx, scalar_t ry) {
334   return _center_x + rx * cos(_theta) + ry * sin(_theta);
335 }
336
337 scalar_t Polygon::absolute_y(scalar_t rx, scalar_t ry) {
338   return _center_y - rx * sin(_theta) + ry * cos(_theta);
339 }
340
341 void Polygon::apply_force(scalar_t dt, scalar_t x, scalar_t y, scalar_t fx, scalar_t fy) {
342   _dcenter_x += fx / _mass * dt;
343   _dcenter_y += fy / _mass * dt;
344   _dtheta -= prod_vect(x - _center_x, y - _center_y, fx, fy) / (_mass * _moment_of_inertia) * dt;
345 }
346
347 void Polygon::apply_border_forces(scalar_t dt, scalar_t xmax, scalar_t ymax) {
348   for(int v = 0; v < _nb_vertices; v++) {
349     int vp = (v+1)%_nb_vertices;
350     for(int d = 0; d < _nb_dots[v]; d++) {
351       scalar_t s = scalar_t(d * dl)/_length[v];
352       scalar_t x = _x[v] * (1 - s) + _x[vp] * s;
353       scalar_t y = _y[v] * (1 - s) + _y[vp] * s;
354       scalar_t vx = 0, vy = 0;
355       if(x < 0) vx = x;
356       else if(x > xmax) vx = x - xmax;
357       if(y < 0) vy = y;
358       else if(y > ymax) vy = y - ymax;
359       apply_force(dt, x, y, - dl * vx * repulsion_constant, - dl * vy * repulsion_constant);
360     }
361   }
362 }
363
364 void Polygon::apply_collision_forces(scalar_t dt, int n_polygon, Polygon *p) {
365   scalar_t closest_x[_total_nb_dots], closest_y[_total_nb_dots];
366   bool inside[_total_nb_dots];
367   scalar_t distance[_total_nb_dots];
368   int _new_effecting_edge[_total_nb_dots];
369
370   int first_dot = 0;
371
372   for(int v = 0; v < _nb_vertices; v++) {
373     int vp = (v+1)%_nb_vertices;
374     scalar_t x = _x[v], y = _y[v], xp = _x[vp], yp = _y[vp];
375
376     for(int d = 0; d < _nb_dots[v]; d++) {
377       inside[d] = false;
378       distance[d] = FLT_MAX;
379     }
380
381     // First, we tag the dots located inside the polygon p
382
383     for(int t = 0; t < p->_nb_vertices-2; t++) {
384       scalar_t min = 0, max = 1;
385       scalar_t xa = p->_x[p->_triangles[t].a], ya = p->_y[p->_triangles[t].a];
386       scalar_t xb = p->_x[p->_triangles[t].b], yb = p->_y[p->_triangles[t].b];
387       scalar_t xc = p->_x[p->_triangles[t].c], yc = p->_y[p->_triangles[t].c];
388       scalar_t den, num;
389
390       const scalar_t eps = 1e-6;
391
392       den = prod_vect(xp - x, yp - y, xb - xa, yb - ya);
393       num = prod_vect(xa - x, ya - y, xb - xa, yb - ya);
394       if(den > eps) {
395         if(num / den < max) max = num / den;
396       } else if(den < -eps) {
397         if(num / den > min) min = num / den;
398       } else {
399         if(num < 0) { min = 1; max = 0; }
400       }
401
402       den = prod_vect(xp - x, yp - y, xc - xb, yc - yb);
403       num = prod_vect(xb - x, yb - y, xc - xb, yc - yb);
404       if(den > eps) {
405         if(num / den < max) max = num / den;
406       } else if(den < -eps) {
407         if(num / den > min) min = num / den;
408       } else {
409         if(num < 0) { min = 1; max = 0; }
410       }
411
412       den = prod_vect(xp - x, yp - y, xa - xc, ya - yc);
413       num = prod_vect(xc - x, yc - y, xa - xc, ya - yc);
414       if(den > eps) {
415         if(num / den < max) max = num / den;
416       } else if(den < -eps) {
417         if(num / den > min) min = num / den;
418       } else {
419         if(num < 0) { min = 1; max = 0; }
420       }
421
422       for(int d = 0; d < _nb_dots[v]; d++) {
423         scalar_t s = scalar_t(d * dl)/_length[v];
424         if(s >= min && s <= max) inside[d] = true;
425       }
426     }
427
428     // Then, we compute for each dot what is the closest point on
429     // the boundary of p
430
431     for(int m = 0; m < p->_nb_vertices; m++) {
432       int mp = (m+1)%p->_nb_vertices;
433       scalar_t xa = p->_x[m], ya = p->_y[m];
434       scalar_t xb = p->_x[mp], yb = p->_y[mp];
435       scalar_t gamma0 = ((x - xa) * (xb - xa) + (y - ya) * (yb - ya)) / sq(p->_length[m]);
436       scalar_t gamma1 = ((xp - x) * (xb - xa) + (yp - y) * (yb - ya)) / sq(p->_length[m]);
437       scalar_t delta0 = (prod_vect(xb - xa, yb - ya, x - xa, y - ya)) / p->_length[m];
438       scalar_t delta1 = (prod_vect(xb - xa, yb - ya, xp - x, yp - y)) / p->_length[m];
439
440       for(int d = 0; d < _nb_dots[v]; d++) if(inside[d]) {
441         int r = _effecting_edge[(first_dot + d) * _nb_polygons + n_polygon];
442
443         // If there is already a spring, we look only at the
444         // vertices next to the current one
445
446         if(r < 0 || m == r || m == (r+1)%p->_nb_vertices || (m+1)%p->_nb_vertices == r) {
447
448           scalar_t s = scalar_t(d * dl)/_length[v];
449           scalar_t delta = abs(s * delta1 + delta0);
450           if(delta < distance[d]) {
451             scalar_t gamma = s * gamma1 + gamma0;
452             if(gamma < 0) {
453               scalar_t l = sqrt(sq(x * (1 - s) + xp * s - xa) + sq(y * (1 - s) + yp * s - ya));
454               if(l < distance[d]) {
455                 distance[d] = l;
456                 closest_x[d] = xa;
457                 closest_y[d] = ya;
458                 _new_effecting_edge[first_dot + d] = m;
459               }
460             } else if(gamma > 1) {
461               scalar_t l = sqrt(sq(x * (1 - s) + xp * s - xb) + sq(y * (1 - s) + yp * s - yb));
462               if(l < distance[d]) {
463                 distance[d] = l;
464                 closest_x[d] = xb;
465                 closest_y[d] = yb;
466                 _new_effecting_edge[first_dot + d] = m;
467               }
468             } else {
469               distance[d] = delta;
470               closest_x[d] = xa * (1 - gamma) + xb * gamma;
471               closest_y[d] = ya * (1 - gamma) + yb * gamma;
472               _new_effecting_edge[first_dot + d] = m;
473             }
474           }
475         }
476       } else _new_effecting_edge[first_dot + d] = -1;
477     }
478
479     // Apply forces
480
481     for(int d = 0; d < _nb_dots[v]; d++) if(inside[d]) {
482       scalar_t s = scalar_t(d * dl)/_length[v];
483       scalar_t x = _x[v] * (1 - s) + _x[vp] * s;
484       scalar_t y = _y[v] * (1 - s) + _y[vp] * s;
485       scalar_t vx = x - closest_x[d];
486       scalar_t vy = y - closest_y[d];
487
488       p->apply_force(dt,
489                      closest_x[d], closest_y[d],
490                      dl * vx  * repulsion_constant, dl * vy * repulsion_constant);
491
492       apply_force(dt,
493                   x, y,
494                   - dl * vx * repulsion_constant, - dl * vy * repulsion_constant);
495     }
496
497     first_dot += _nb_dots[v];
498   }
499
500   for(int d = 0; d < _total_nb_dots; d++)
501     _effecting_edge[d * _nb_polygons + n_polygon] = _new_effecting_edge[d];
502
503 }
504
505 bool Polygon::collide(Polygon *p) {
506   for(int n = 0; n < _nb_vertices; n++) {
507     int np = (n+1)%_nb_vertices;
508     for(int m = 0; m < p->_nb_vertices; m++) {
509       int mp = (m+1)%p->_nb_vertices;
510       scalar_t det, s = -1, t = -1;
511       intersection(_x[n], _y[n], _x[np], _y[np],
512                    p->_x[m], p->_y[m], p->_x[mp], p->_y[mp], det, s, t);
513       if(det != 0 && s>= 0 && s <= 1&& t >= 0 && t <= 1) return true;
514     }
515   }
516
517   for(int n = 0; n < _nb_vertices; n++) if(p->contain(_x[n], _y[n])) return true;
518   for(int n = 0; n < p->_nb_vertices; n++) if(contain(p->_x[n], p->_y[n])) return true;
519
520   return false;
521 }