#ifdef HAVE_CONFIG_H # include #endif #include "world.hh" #include "body.hh" #include "view.hh" #include World::World() : _static_friction(0.2), _dynamic_friction(0.2), _angular_friction(0.3), _angular_friction_2(1) { } void World::set_static_friction(double d) { _static_friction = d; } void World::set_dynamic_friction(double d) { _dynamic_friction = d; } void World::set_angular_friction(double d) { if (d < 0) d = 0; _angular_friction = d; } void World::add(Body *b) { _bodies.push_back(b); b->embody(this); if (b->movable()) _moving_bodies.push_back(b); if (b->z_plane() > 0) _collidable_bodies.push_back(b); } void World::remove(Body *b) { for (int i = 0; i < _moving_bodies.size(); i++) if (_moving_bodies[i] == b) { _moving_bodies[i] = _moving_bodies.back(); _moving_bodies.pop_back(); break; } for (int i = 0; i < _collidable_bodies.size(); i++) if (_collidable_bodies[i] == b) { _collidable_bodies[i] = _collidable_bodies.back(); _collidable_bodies.pop_back(); break; } for (int i = 0; i < _bodies.size(); i++) if (_bodies[i] == b) { _bodies[i] = _bodies.back(); _bodies.pop_back(); break; } } extern "C" { static int body_qsorter(const void *thunk1, const void *thunk2) { const Body **b1 = (const Body **)thunk1; const Body **b2 = (const Body **)thunk2; return (*b1)->move_phase() - (*b2)->move_phase(); } } void World::reset() { for (int i = 0; i < _bodies.size(); i++) _bodies[i]->reset(); if (_bodies.size()) qsort(&_bodies[0], _bodies.size(), sizeof(Body *), body_qsorter); } void World::trail_snapshot() { for (int i = 0; i < _bodies.size(); i++) _bodies[i]->trail_snapshot(); } void World::random_place(bool do_movable, bool do_stationary, View *view) { Point ll = view->lower_left(); Point ur = view->upper_right(); Point delta = ur - ll; for (int i = 0; i < _bodies.size(); i++) if (_bodies[i]->movable() ? do_movable : do_stationary) { Point p = ll; p.x += ((double)rand() / RAND_MAX) * delta.x; p.y += ((double)rand() / RAND_MAX) * delta.y; double rotation = ((double)rand() / RAND_MAX) * 2*M_PI; _bodies[i]->place(p, rotation); } reset(); } void World::draw(View *v) const { v->clear(); for (int i = 0; i < _bodies.size(); i++) _bodies[i]->draw(v); v->expose(); } #define MOVE_TIME_QUANTUM 0.1 void World::move() const { for (int i = 0; i < _bodies.size(); i++) _bodies[i]->move(MOVE_TIME_QUANTUM); } void World::check_collisions() const { int cs = _collidable_bodies.size(); if (cs) { Body * const *cb = _collidable_bodies.begin(); for (int i = 0; i < cs - 1; i++) for (int j = i + 1; j < cs; j++) if (cb[i]->might_collide(cb[j])) cb[i]->collide(cb[j]); } }