4 flatland is a simple 2d physical simulator
6 Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/
7 Written by Francois Fleuret <francois.fleuret@idiap.ch>
9 This file is part of flatland
11 flatland is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License version 3 as
13 published by the Free Software Foundation.
15 flatland is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with flatland. If not, see <http://www.gnu.org/licenses/>.
29 Universe::Universe(int nb_max_polygons,
30 scalar_t width, scalar_t height) : _width(width),
32 _nb_max_polygons(nb_max_polygons),
34 _polygons = new Polygon *[_nb_max_polygons];
35 for(int n = 0; n < _nb_max_polygons; n++) _polygons[n] = 0;
38 Universe::~Universe() {
43 void Universe::initialize_polygon(Polygon *p) {
44 p->initialize(_nb_max_polygons);
47 void Universe::clear() {
48 for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) delete _polygons[n];
52 void Universe::add_polygon(Polygon *p) {
53 if(_nb_polygons < _nb_max_polygons) {
54 if(!p->_initialized) {
55 cerr << "You can not add a non-initialized polygon." << endl;
58 _polygons[_nb_polygons++] = p;
60 cerr << "Too many polygons!" << endl;
65 bool Universe::collide_with_borders(Polygon *p, scalar_t padding) {
66 return p->collide_with_borders(padding, padding,_width - padding, _height - padding);
70 bool Universe::collide(Polygon *p) {
71 for(int n = 0; n < _nb_polygons; n++)
72 if(_polygons[n] && _polygons[n]->collide(p)) return true;
77 void Universe::compute_pseudo_collisions(int nb_axis, int *nb_colliding_axis) {
78 Couple couples[_nb_polygons * 2];
80 memset((void *) nb_colliding_axis, 0, _nb_polygons * _nb_polygons * sizeof(int));
82 for(int a = 0; a < nb_axis; a++) {
83 scalar_t alpha = M_PI * scalar_t(a) / scalar_t(nb_axis);
84 scalar_t vx = cos(alpha), vy = sin(alpha);
86 for(int n = 0; n < _nb_polygons; n++) {
87 scalar_t *x = _polygons[n]->_x, *y = _polygons[n]->_y;
88 scalar_t min = x[0] * vx + y[0] * vy, max = min;
90 for(int v = 1; v < _polygons[n]->_nb_vertices; v++) {
91 scalar_t s = x[v] * vx + y[v] * vy;
96 couples[2 * n + 0].value = min;
97 couples[2 * n + 0].index = n;
98 couples[2 * n + 1].value = max;
99 couples[2 * n + 1].index = n;
102 qsort((void *) couples, 2 * _nb_polygons, sizeof(Couple), compare_couple);
105 memset((void *) in, 0, _nb_polygons * sizeof(int));
106 for(int k = 0; k < 2 * _nb_polygons; k++) {
107 int i = couples[k].index;
112 for(int j = 0; j < i; j++)
113 if(j != i && in[j]) nb_colliding_axis[j + i * _nb_polygons]++;
114 for(int j = i+1; j < _nb_polygons; j++)
115 if(j != i && in[j]) nb_colliding_axis[i + j * _nb_polygons]++;
121 for(int i = 0; i < _nb_polygons; i++) {
122 for(int j = 0; j < i; j++) {
123 if(nb_colliding_axis[j + i * _nb_polygons] > nb_colliding_axis[i + i * _nb_polygons])
124 nb_colliding_axis[i + i * _nb_polygons] = nb_colliding_axis[j + i * _nb_polygons];
125 nb_colliding_axis[i + j * _nb_polygons] = nb_colliding_axis[j + i * _nb_polygons];
130 bool Universe::update(scalar_t dt, scalar_t padding) {
132 apply_collision_forces(dt);
133 for(int n = 0; n < _nb_polygons; n++) if(_polygons[n]) {
134 _polygons[n]->apply_border_forces(dt,
136 _width - padding, _height - padding);
137 result |= _polygons[n]->update(dt);
142 Polygon *Universe::pick_polygon(scalar_t x, scalar_t y) {
143 for(int n = 0; n < _nb_polygons; n++)
144 if(_polygons[n] && _polygons[n]->contain(x, y)) return _polygons[n];
148 void Universe::draw(Canvas *canvas) {
149 for(int n = 0; n < _nb_polygons; n++) {
151 _polygons[n]->draw(canvas);
155 for(int n = 0; n < _nb_polygons; n++) {
157 _polygons[n]->draw_contours(canvas);
162 void Universe::apply_gravity(scalar_t dt, scalar_t fx, scalar_t fy) {
163 for(int n = 0; n < _nb_polygons; n++)
165 _polygons[n]->apply_force(dt,
166 _polygons[n]->_center_x, _polygons[n]->_center_y,
170 void Universe::apply_collision_forces(scalar_t dt) {
171 const int nb_axis = 2;
172 int nb_collision[_nb_polygons * _nb_polygons];
174 compute_pseudo_collisions(nb_axis, nb_collision);
176 for(int n = 0; n < _nb_polygons; n++) if(_polygons[n])
177 for(int m = 0; m < _nb_polygons; m++)
178 if(m != n && _polygons[m] && nb_collision[n + _nb_polygons * m] == nb_axis)
179 _polygons[n]->apply_collision_forces(dt, m, _polygons[m]);