45494610c764b844020ea7b022135a88aa9f6d7f
[universe.git] / universe.cc
1
2 ////////////////////////////////////////////////////////////////////////////////
3 // This program is free software; you can redistribute it and/or              //
4 // modify it under the terms of the GNU General Public License                //
5 // version 2 as published by the Free Software Foundation.                    //
6 //                                                                            //
7 // This program is distributed in the hope that it will be useful, but        //
8 // WITHOUT ANY WARRANTY; without even the implied warranty of                 //
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          //
10 // General Public License for more details.                                   //
11 //                                                                            //
12 // Written and (C) by François Fleuret                                        //
13 // Contact <francois.fleuret@epfl.ch> for comments & bug reports              //
14 ////////////////////////////////////////////////////////////////////////////////
15
16 #include "universe.h"
17
18 Universe::Universe(int nb_max_polygons,
19                    scalar_t xmax, scalar_t ymax) : _xmax(xmax), _ymax(ymax),
20                                                    _nb_max_polygons(nb_max_polygons), _nb_polygons(0) {
21   _polygons = new Polygon *[_nb_max_polygons];
22   for(int n = 0; n < _nb_max_polygons; n++) _polygons[n] = 0;
23 }
24
25 Universe::~Universe() {
26   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) delete _polygons[n];
27   delete[] _polygons;
28 }
29
30 void Universe::initialize(Polygon *p) {
31   p->initialize(_nb_max_polygons);
32 }
33
34 void Universe::clear() {
35   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) delete _polygons[n];
36   _nb_polygons = 0;
37 }
38
39 void Universe::add_polygon(Polygon *p) {
40   if(_nb_polygons < _nb_max_polygons) {
41     if(!p->_initialized) {
42       cerr << "You can not add a non-initialized polygon." << endl;
43       abort();
44     }
45     _polygons[_nb_polygons++] = p;
46   } else {
47     cerr << "To many polygons!" << endl;
48     exit(1);
49   }
50 }
51
52 bool Universe::collide(Polygon *p) {
53   for(int n = 0; n < _nb_polygons; n++)
54     if(_polygons[n] && _polygons[n]->collide(p)) return true;
55
56   return false;
57 }
58
59 void Universe::compute_pseudo_collisions(int nb_axis, int *nb_colliding_axis) {
60   Couple couples[_nb_polygons * 2];
61   int in[_nb_polygons];
62   memset((void *) nb_colliding_axis, 0, _nb_polygons * _nb_polygons * sizeof(int));
63
64   for(int a = 0; a < nb_axis; a++) {
65     scalar_t alpha = M_PI * scalar_t(a) / scalar_t(nb_axis);
66     scalar_t vx = cos(alpha), vy = sin(alpha);
67
68     for(int n = 0; n < _nb_polygons; n++) {
69       scalar_t *x = _polygons[n]->_x, *y = _polygons[n]->_y;
70       scalar_t min = x[0] * vx + y[0] * vy, max = min;
71
72       for(int v = 1; v < _polygons[n]->_nb_vertices; v++) {
73         scalar_t s = x[v] * vx + y[v] * vy;
74         if(s > max) max = s;
75         if(s < min) min = s;
76       }
77
78       couples[2 * n + 0].value = min;
79       couples[2 * n + 0].index = n;
80       couples[2 * n + 1].value = max;
81       couples[2 * n + 1].index = n;
82     }
83
84     qsort((void *) couples, 2 * _nb_polygons, sizeof(Couple), compare_couple);
85
86     int nb_in = 0;
87     memset((void *) in, 0, _nb_polygons * sizeof(int));
88     for(int k = 0; k < 2 * _nb_polygons; k++) {
89       int i = couples[k].index;
90       in[i] = !in[i];
91       if(in[i]) {
92         nb_in++;
93         if(nb_in > 1) {
94           for(int j = 0; j < i; j++)
95             if(j != i && in[j]) nb_colliding_axis[j + i * _nb_polygons]++;
96           for(int j = i+1; j < _nb_polygons; j++)
97             if(j != i && in[j]) nb_colliding_axis[i + j * _nb_polygons]++;
98         }
99       } else nb_in--;
100     }
101   }
102
103   for(int i = 0; i < _nb_polygons; i++) {
104     for(int j = 0; j < i; j++) {
105       if(nb_colliding_axis[j + i * _nb_polygons] > nb_colliding_axis[i + i * _nb_polygons])
106         nb_colliding_axis[i + i * _nb_polygons] = nb_colliding_axis[j + i * _nb_polygons];
107       nb_colliding_axis[i + j * _nb_polygons] = nb_colliding_axis[j + i * _nb_polygons];
108     }
109   }
110 }
111
112 bool Universe::update(scalar_t dt) {
113   bool result = false;
114   apply_collision_forces(dt);
115   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) {
116     _polygons[n]->apply_border_forces(dt, _xmax, _ymax);
117     result |= _polygons[n]->update(dt);
118   }
119   return result;
120 }
121
122 Polygon *Universe::pick_polygon(scalar_t x, scalar_t y) {
123   for(int n = 0; n < _nb_polygons; n++)
124     if(_polygons[n] && _polygons[n]->contain(x, y)) return _polygons[n];
125   return 0;
126 }
127
128 void Universe::print_fig(ostream &os) {
129   os << "#FIG 3.2" << endl;
130   os << "Portrait" << endl;
131   os << "Center" << endl;
132   os << "Metric" << endl;
133   os << "A4      " << endl;
134   os << "100.00" << endl;
135   os << "Single" << endl;
136   os << "-2" << endl;
137   os << "1200 2" << endl;
138   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) _polygons[n]->print_fig(os);
139 }
140
141 void Universe::draw(SimpleWindow *window) {
142   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) _polygons[n]->draw(window);
143   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) _polygons[n]->draw_contours(window);
144 }
145
146 void Universe::apply_collision_forces(scalar_t dt) {
147   const int nb_axis = 2;
148   int nb_collision[_nb_polygons * _nb_polygons];
149
150   compute_pseudo_collisions(nb_axis, nb_collision);
151
152   for(int n = 0; n < _nb_polygons; n++) if(_polygons[n])
153     for(int m = 0; m < _nb_polygons; m++)
154       if(m != n && _polygons[m] && nb_collision[n + _nb_polygons * m] == nb_axis)
155         _polygons[n]->apply_collision_forces(dt, m, _polygons[m]);
156 }