983eb96a744d2d6f102ecd8d23f93801272727e2
[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 "universe.h"
6
7 Universe::Universe(int nb_max_polygons,
8                    scalar_t xmax, scalar_t ymax) : _xmax(xmax), _ymax(ymax),
9                                                    _nb_max_polygons(nb_max_polygons), _nb_polygons(0) {
10   _polygons = new Polygon *[_nb_max_polygons];
11   for(int n = 0; n < _nb_max_polygons; n++) _polygons[n] = 0;
12 }
13
14 Universe::~Universe() {
15   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) delete _polygons[n];
16   delete[] _polygons;
17 }
18
19 void Universe::initialize(Polygon *p) {
20   p->initialize(_nb_max_polygons);
21 }
22
23 void Universe::clear() {
24   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) delete _polygons[n];
25   _nb_polygons = 0;
26 }
27
28 void Universe::add_polygon(Polygon *p) {
29   if(_nb_polygons < _nb_max_polygons) {
30     if(!p->_initialized) {
31       cerr << "You can not add a non-initialized polygon." << endl;
32       abort();
33     }
34     _polygons[_nb_polygons++] = p;
35   } else {
36     cerr << "To many polygons!" << endl;
37     exit(1);
38   }
39 }
40
41 bool Universe::collide(Polygon *p) {
42   for(int n = 0; n < _nb_polygons; n++)
43     if(_polygons[n] && _polygons[n]->collide(p)) return true;
44
45   return false;
46 }
47
48 void Universe::compute_pseudo_collisions(int nb_axis, int *nb_colliding_axis) {
49   Couple couples[_nb_polygons * 2];
50   int in[_nb_polygons];
51   memset((void *) nb_colliding_axis, 0, _nb_polygons * _nb_polygons * sizeof(int));
52
53   for(int a = 0; a < nb_axis; a++) {
54     scalar_t alpha = M_PI * scalar_t(a) / scalar_t(nb_axis);
55     scalar_t vx = cos(alpha), vy = sin(alpha);
56
57     for(int n = 0; n < _nb_polygons; n++) {
58       scalar_t *x = _polygons[n]->_x, *y = _polygons[n]->_y;
59       scalar_t min = x[0] * vx + y[0] * vy, max = min;
60
61       for(int v = 1; v < _polygons[n]->_nb_vertices; v++) {
62         scalar_t s = x[v] * vx + y[v] * vy;
63         if(s > max) max = s;
64         if(s < min) min = s;
65       }
66
67       couples[2 * n + 0].value = min;
68       couples[2 * n + 0].index = n;
69       couples[2 * n + 1].value = max;
70       couples[2 * n + 1].index = n;
71     }
72
73     qsort((void *) couples, 2 * _nb_polygons, sizeof(Couple), compare_couple);
74
75     int nb_in = 0;
76     memset((void *) in, 0, _nb_polygons * sizeof(int));
77     for(int k = 0; k < 2 * _nb_polygons; k++) {
78       int i = couples[k].index;
79       in[i] = !in[i];
80       if(in[i]) {
81         nb_in++;
82         if(nb_in > 1) {
83           for(int j = 0; j < i; j++)
84             if(j != i && in[j]) nb_colliding_axis[j + i * _nb_polygons]++;
85           for(int j = i+1; j < _nb_polygons; j++)
86             if(j != i && in[j]) nb_colliding_axis[i + j * _nb_polygons]++;
87         }
88       } else nb_in--;
89     }
90   }
91
92   for(int i = 0; i < _nb_polygons; i++) {
93     for(int j = 0; j < i; j++) {
94       if(nb_colliding_axis[j + i * _nb_polygons] > nb_colliding_axis[i + i * _nb_polygons])
95         nb_colliding_axis[i + i * _nb_polygons] = nb_colliding_axis[j + i * _nb_polygons];
96       nb_colliding_axis[i + j * _nb_polygons] = nb_colliding_axis[j + i * _nb_polygons];
97     }
98   }
99 }
100
101 bool Universe::update(scalar_t dt) {
102   bool result = false;
103   apply_collision_forces(dt);
104   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) {
105     _polygons[n]->apply_border_forces(dt, _xmax, _ymax);
106     result |= _polygons[n]->update(dt);
107   }
108   return result;
109 }
110
111 Polygon *Universe::pick_polygon(scalar_t x, scalar_t y) {
112   for(int n = 0; n < _nb_polygons; n++)
113     if(_polygons[n] && _polygons[n]->contain(x, y)) return _polygons[n];
114   return 0;
115 }
116
117 void Universe::print_fig(ostream &os) {
118   os << "#FIG 3.2" << endl;
119   os << "Portrait" << endl;
120   os << "Center" << endl;
121   os << "Metric" << endl;
122   os << "A4      " << endl;
123   os << "100.00" << endl;
124   os << "Single" << endl;
125   os << "-2" << endl;
126   os << "1200 2" << endl;
127   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) _polygons[n]->print_fig(os);
128 }
129
130 void Universe::draw(SimpleWindow *window) {
131   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) _polygons[n]->draw(window);
132   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) _polygons[n]->draw_contours(window);
133 }
134
135 void Universe::apply_collision_forces(scalar_t dt) {
136   const int nb_axis = 2;
137   int nb_collision[_nb_polygons * _nb_polygons];
138
139   compute_pseudo_collisions(nb_axis, nb_collision);
140
141   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n])
142     for(int m = 0; m < _nb_polygons; m++)
143       if(m != n && _polygons[m] && nb_collision[n + _nb_polygons * m] == nb_axis)
144         _polygons[n]->apply_collision_forces(dt, m, _polygons[m]);
145 }