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. //
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. //
12 // Written and (C) by François Fleuret //
13 // Contact <francois.fleuret@epfl.ch> for comments & bug reports //
14 ////////////////////////////////////////////////////////////////////////////////
16 // $Id: universe.cc,v 1.88 2007-06-16 13:51:54 fleuret Exp $
20 Universe::Universe(int nb_max_polygons,
21 scalar_t xmax, scalar_t ymax) : _xmax(xmax), _ymax(ymax),
22 _nb_max_polygons(nb_max_polygons), _nb_polygons(0) {
23 _polygons = new Polygon *[_nb_max_polygons];
24 for(int n = 0; n < _nb_max_polygons; n++) _polygons[n] = 0;
27 Universe::~Universe() {
28 for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) delete _polygons[n];
32 void Universe::initialize(Polygon *p) {
33 p->initialize(_nb_max_polygons);
36 void Universe::clear() {
37 for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) delete _polygons[n];
41 void Universe::add_polygon(Polygon *p) {
42 if(_nb_polygons < _nb_max_polygons) {
43 if(!p->_initialized) {
44 cerr << "You can not add a non-initialized polygon." << endl;
47 _polygons[_nb_polygons++] = p;
49 cerr << "To many polygons!" << endl;
54 bool Universe::collide(Polygon *p) {
55 for(int n = 0; n < _nb_polygons; n++)
56 if(_polygons[n] && _polygons[n]->collide(p)) return true;
61 void Universe::compute_pseudo_collisions(int nb_axis, int *nb_colliding_axis) {
62 Couple couples[_nb_polygons * 2];
64 memset((void *) nb_colliding_axis, 0, _nb_polygons * _nb_polygons * sizeof(int));
66 for(int a = 0; a < nb_axis; a++) {
67 scalar_t alpha = M_PI * scalar_t(a) / scalar_t(nb_axis);
68 scalar_t vx = cos(alpha), vy = sin(alpha);
70 for(int n = 0; n < _nb_polygons; n++) {
71 scalar_t *x = _polygons[n]->_x, *y = _polygons[n]->_y;
72 scalar_t min = x[0] * vx + y[0] * vy, max = min;
74 for(int v = 1; v < _polygons[n]->_nb_vertices; v++) {
75 scalar_t s = x[v] * vx + y[v] * vy;
80 couples[2 * n + 0].value = min;
81 couples[2 * n + 0].index = n;
82 couples[2 * n + 1].value = max;
83 couples[2 * n + 1].index = n;
86 qsort((void *) couples, 2 * _nb_polygons, sizeof(Couple), compare_couple);
89 memset((void *) in, 0, _nb_polygons * sizeof(int));
90 for(int k = 0; k < 2 * _nb_polygons; k++) {
91 int i = couples[k].index;
96 for(int j = 0; j < i; j++)
97 if(j != i && in[j]) nb_colliding_axis[j + i * _nb_polygons]++;
98 for(int j = i+1; j < _nb_polygons; j++)
99 if(j != i && in[j]) nb_colliding_axis[i + j * _nb_polygons]++;
105 for(int i = 0; i < _nb_polygons; i++) {
106 for(int j = 0; j < i; j++) {
107 if(nb_colliding_axis[j + i * _nb_polygons] > nb_colliding_axis[i + i * _nb_polygons])
108 nb_colliding_axis[i + i * _nb_polygons] = nb_colliding_axis[j + i * _nb_polygons];
109 nb_colliding_axis[i + j * _nb_polygons] = nb_colliding_axis[j + i * _nb_polygons];
114 bool Universe::update(scalar_t dt) {
116 apply_collision_forces(dt);
117 for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) {
118 _polygons[n]->apply_border_forces(dt, _xmax, _ymax);
119 result |= _polygons[n]->update(dt);
124 Polygon *Universe::pick_polygon(scalar_t x, scalar_t y) {
125 for(int n = 0; n < _nb_polygons; n++)
126 if(_polygons[n] && _polygons[n]->contain(x, y)) return _polygons[n];
130 void Universe::print_fig(ostream &os) {
131 os << "#FIG 3.2" << endl;
132 os << "Portrait" << endl;
133 os << "Center" << endl;
134 os << "Metric" << endl;
136 os << "100.00" << endl;
137 os << "Single" << endl;
139 os << "1200 2" << endl;
140 for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) _polygons[n]->print_fig(os);
143 void Universe::draw(SimpleWindow *window) {
144 for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) _polygons[n]->draw(window);
145 for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) _polygons[n]->draw_contours(window);
148 void Universe::apply_collision_forces(scalar_t dt) {
149 const int nb_axis = 2;
150 int nb_collision[_nb_polygons * _nb_polygons];
152 compute_pseudo_collisions(nb_axis, nb_collision);
154 for(int n = 0; n < _nb_polygons; n++) if(_polygons[n])
155 for(int m = 0; m < _nb_polygons; m++)
156 if(m != n && _polygons[m] && nb_collision[n + _nb_polygons * m] == nb_axis)
157 _polygons[n]->apply_collision_forces(dt, m, _polygons[m]);