92b7a1b702558bc806c3efa719daee6f1dd22626
[universe.git] / universe.cc
1
2 // Written and (C) by Francois Fleuret
3 // Contact <francois.fleuret@idiap.ch> for comments & bug reports
4
5 #include <string.h>
6
7 #include "universe.h"
8
9 Universe::Universe(int nb_max_polygons,
10                    scalar_t width, scalar_t height) : _width(width), _height(height),
11                                                    _nb_max_polygons(nb_max_polygons), _nb_polygons(0) {
12   _polygons = new Polygon *[_nb_max_polygons];
13   for(int n = 0; n < _nb_max_polygons; n++) _polygons[n] = 0;
14 }
15
16 Universe::~Universe() {
17   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) delete _polygons[n];
18   delete[] _polygons;
19 }
20
21 void Universe::initialize(Polygon *p) {
22   p->initialize(_nb_max_polygons);
23 }
24
25 void Universe::clear() {
26   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) delete _polygons[n];
27   _nb_polygons = 0;
28 }
29
30 void Universe::add_polygon(Polygon *p) {
31   if(_nb_polygons < _nb_max_polygons) {
32     if(!p->_initialized) {
33       cerr << "You can not add a non-initialized polygon." << endl;
34       abort();
35     }
36     _polygons[_nb_polygons++] = p;
37   } else {
38     cerr << "Too many polygons!" << endl;
39     exit(1);
40   }
41 }
42
43 bool Universe::collide(Polygon *p) {
44   for(int n = 0; n < _nb_polygons; n++)
45     if(_polygons[n] && _polygons[n]->collide(p)) return true;
46
47   return false;
48 }
49
50 void Universe::compute_pseudo_collisions(int nb_axis, int *nb_colliding_axis) {
51   Couple couples[_nb_polygons * 2];
52   int in[_nb_polygons];
53   memset((void *) nb_colliding_axis, 0, _nb_polygons * _nb_polygons * sizeof(int));
54
55   for(int a = 0; a < nb_axis; a++) {
56     scalar_t alpha = M_PI * scalar_t(a) / scalar_t(nb_axis);
57     scalar_t vx = cos(alpha), vy = sin(alpha);
58
59     for(int n = 0; n < _nb_polygons; n++) {
60       scalar_t *x = _polygons[n]->_x, *y = _polygons[n]->_y;
61       scalar_t min = x[0] * vx + y[0] * vy, max = min;
62
63       for(int v = 1; v < _polygons[n]->_nb_vertices; v++) {
64         scalar_t s = x[v] * vx + y[v] * vy;
65         if(s > max) max = s;
66         if(s < min) min = s;
67       }
68
69       couples[2 * n + 0].value = min;
70       couples[2 * n + 0].index = n;
71       couples[2 * n + 1].value = max;
72       couples[2 * n + 1].index = n;
73     }
74
75     qsort((void *) couples, 2 * _nb_polygons, sizeof(Couple), compare_couple);
76
77     int nb_in = 0;
78     memset((void *) in, 0, _nb_polygons * sizeof(int));
79     for(int k = 0; k < 2 * _nb_polygons; k++) {
80       int i = couples[k].index;
81       in[i] = !in[i];
82       if(in[i]) {
83         nb_in++;
84         if(nb_in > 1) {
85           for(int j = 0; j < i; j++)
86             if(j != i && in[j]) nb_colliding_axis[j + i * _nb_polygons]++;
87           for(int j = i+1; j < _nb_polygons; j++)
88             if(j != i && in[j]) nb_colliding_axis[i + j * _nb_polygons]++;
89         }
90       } else nb_in--;
91     }
92   }
93
94   for(int i = 0; i < _nb_polygons; i++) {
95     for(int j = 0; j < i; j++) {
96       if(nb_colliding_axis[j + i * _nb_polygons] > nb_colliding_axis[i + i * _nb_polygons])
97         nb_colliding_axis[i + i * _nb_polygons] = nb_colliding_axis[j + i * _nb_polygons];
98       nb_colliding_axis[i + j * _nb_polygons] = nb_colliding_axis[j + i * _nb_polygons];
99     }
100   }
101 }
102
103 bool Universe::update(scalar_t dt) {
104   bool result = false;
105   apply_collision_forces(dt);
106   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) {
107     _polygons[n]->apply_border_forces(dt, _width, _height);
108     result |= _polygons[n]->update(dt);
109   }
110   return result;
111 }
112
113 Polygon *Universe::pick_polygon(scalar_t x, scalar_t y) {
114   for(int n = 0; n < _nb_polygons; n++)
115     if(_polygons[n] && _polygons[n]->contain(x, y)) return _polygons[n];
116   return 0;
117 }
118
119 void Universe::print_xfig(XFigTracer *tracer) {
120   for(int n = 0; n < _nb_polygons; n++) {
121     if(_polygons[n]) {
122       _polygons[n]->color_xfig(tracer);
123     }
124   }
125   for(int n = 0; n < _nb_polygons; n++) {
126     if(_polygons[n]) {
127       _polygons[n]->print_xfig(tracer);
128     }
129   }
130 }
131
132 #ifdef X11_SUPPORT
133 void Universe::draw(SimpleWindow *window) {
134   for(int n = 0; n < _nb_polygons; n++) {
135     if(_polygons[n]) {
136       _polygons[n]->draw(window);
137     }
138   }
139
140   for(int n = 0; n < _nb_polygons; n++) {
141     if(_polygons[n]) {
142       _polygons[n]->draw_contours(window);
143     }
144   }
145 }
146 #endif
147
148 #ifdef CAIRO_SUPPORT
149 void Universe::draw(cairo_t *context_resource) {
150   for(int n = 0; n < _nb_polygons; n++) {
151     if(_polygons[n]) {
152       _polygons[n]->draw(context_resource);
153     }
154   }
155
156   for(int n = 0; n < _nb_polygons; n++) {
157     if(_polygons[n]) {
158       _polygons[n]->draw_contours(context_resource);
159     }
160   }
161 }
162 #endif
163
164 void Universe::apply_collision_forces(scalar_t dt) {
165   const int nb_axis = 2;
166   int nb_collision[_nb_polygons * _nb_polygons];
167
168   compute_pseudo_collisions(nb_axis, nb_collision);
169
170   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n])
171     for(int m = 0; m < _nb_polygons; m++)
172       if(m != n && _polygons[m] && nb_collision[n + _nb_polygons * m] == nb_axis)
173         _polygons[n]->apply_collision_forces(dt, m, _polygons[m]);
174 }