Flatland

Documentation

SourceForge.net Logo

flatland.hpp

Go to the documentation of this file.
00001 // Summary: Declares a geometry class and world class.  These are wrapper interfaces to ODE.
00002 // Copyright: 2007  Philip Rideout.  All rights reserved.
00003 // License: see source/bsd-license.txt
00004 
00005 #pragma once
00006 #include <flatland/ode/ode.h>
00007 #include <flatland/ode/source/objects.h>
00008 #include <flatland/aabb.hpp>
00009 #include <flatland/vector.hpp>
00010 #include <flatland/enums.hpp>
00011 #include <flatland/intersection.hpp>
00012 #include <cassert>
00013 #include <stack>
00014 
00015 /// Everything in the 2D collision library goes in the "Flatland" namespace.
00016 namespace Flatland
00017 {
00018     class ContactList;
00019     class Object;
00020 
00021     typedef unsigned int Mask;
00022     typedef dBodyID Body;
00023     typedef void (*Callback)(ContactList &contacts);
00024 
00025     /// Abstract 2D geometry class used for collision detection.
00026     class Geometry
00027     {
00028       public:
00029         Geometry();
00030         virtual void UpdateBounds() = 0;
00031         virtual void SetCenter(const vec2 &center);
00032         vec2 Center() const { return center; }
00033         virtual void SetAxis(const vec2 &axis);
00034         void Rotate(float theta);
00035         void Rotate(const vec2 &xform);
00036         vec2 Axis() const { return axis; }
00037         vec2 Axis(int i) const { return i ? axis.perp() : axis; }
00038         virtual void SetMass(Body body, float density) const {}
00039         virtual Shape GetShape() const = 0;
00040         const aabb &GetBounds() const { return bounds; }
00041       protected:
00042         aabb bounds;
00043         vec2 axis;
00044         vec2 center;
00045     };
00046 
00047     /// \note
00048     /// For physical properties, I don't see a need for accessor/mutator methods right now.
00049     /// In the future we can add proxies if need be.  For example, we'd turn the struct into a class,
00050     /// then we'd make friction a FrictionProxy instead of a float, then we'd add a private member
00051     /// to store the actual float for friction. FrictionProxy would use operator overloading
00052     /// to hide validation behind the scenes.  If the proxy code is tedious even using templates,
00053     /// then maybe we could add to the enums perl script to auto-generate code for us.
00054 
00055     /// Physical properties.
00056     struct ObjectProperties
00057     {
00058         float density;
00059         float friction;
00060         float bounceFactor;
00061         float bounceVelocity;
00062         Mask collisionMask;
00063         Mask frictionMask;
00064         Callback callback;
00065     };
00066 
00067     /// Abstract Flatland object to be overridden by the application.
00068     //
00069     /// Flatland::Object is an abstract class which can be dynamic or static.
00070     ///  - Dynamic objects use position/orientation information stored in an ODE body.
00071     ///  - Static objects have their own position/orientation information.  They cannot be moved by ODE.
00072     ///  - Dynamic and static objects both have geometry, friction, and bounciness.
00073     class Object
00074     {
00075       public:
00076         Object();
00077         virtual ~Object() {}
00078         virtual Geometry &GetGeometry() = 0;
00079         virtual const Geometry &GetGeometry() const = 0;
00080         virtual bool IsDynamic() const = 0;
00081         virtual Body GetBody() = 0;
00082         virtual void SetMass(float density) = 0;
00083         void Move();
00084         void Rotate(float theta);
00085         void SetCenter(const vec2 &center);
00086       public:
00087         ObjectProperties &Property() { return properties; }
00088         const ObjectProperties &Property() const { return properties; }
00089         static ObjectProperties &Default() { return defaults; }
00090         static void PushProperties() { defaultStack.push(defaults); }
00091         static void PopProperties() { defaults = defaultStack.top(); defaultStack.pop(); }
00092       private:
00093         ObjectProperties properties;
00094         static ObjectProperties defaults;
00095         static std::stack<ObjectProperties> defaultStack;
00096     };
00097 
00098     /// Dynamic object.
00099     template<class G>
00100     class Dynamic : public Object
00101     {
00102       public:
00103         Dynamic(G *geometry, Body b);
00104         virtual ~Dynamic() { dBodyDestroy(body); delete geometry; }
00105         G &GetGeometry() { return *geometry; }
00106         const G &GetGeometry() const { return *geometry; }
00107         bool IsDynamic() const { return true; }
00108         Body GetBody() { return body; }
00109         void SetMass(float density) { geometry->SetMass(body, density); }
00110       protected:
00111         G *geometry;
00112         Body body;
00113     };
00114 
00115     /// Static object (cannot be moved by the physics engine)
00116     template<class G>
00117     class Static : public Object
00118     {
00119       public:
00120         Static(G *geometry) : geometry(geometry) {}
00121         virtual ~Static() { delete geometry; }
00122         G &GetGeometry() { return *geometry; }
00123         const G &GetGeometry() const { return *geometry; }
00124         bool IsDynamic() const { return false; }
00125         Body GetBody() { return 0; }
00126         void SetMass(float) {}
00127       protected:
00128         G *geometry;
00129     };
00130 
00131     /// Encapsulates an array of contacts between two geometries.
00132     class ContactList
00133     {
00134       public:
00135         ContactList();
00136         void Reset(Object *o1, Object *o2);
00137         Object *Self() { return o1; }
00138         Object *Other() { return o2; }
00139         void ToggleNormalInversion() { invertNormals = !invertNormals; }
00140         void AddContact(const vec2 &position, const vec2 &normal, float depth);
00141         void Finalize();
00142         void CreateJoints(dWorldID world, dJointGroupID contactGroup) const;
00143         int Count() const { return count; }
00144         static const int Max = 64;
00145       private:
00146         Object *o1;
00147         Object *o2;
00148         dContact contacts[Max];
00149         int count;
00150         bool invertNormals;
00151     };
00152 
00153     /// Encapsulates an ODE world and contact group.
00154     class World
00155     {
00156       public:
00157         World();
00158         ~World();
00159         void QuickStep(float);
00160         Body BodyCreate();
00161         template<class S> void GenerateContacts(const S &space);
00162         template<class S> bool IsCorrupt(const S &space) const;
00163         int ContactCount() const { return contactCount; }
00164         void SetCFM(float);
00165         void SetAutoDisableFlag(bool);
00166         void SetERP(float);
00167         void SetContactMaxCorrectingVel(float);
00168         void SetContactSurfaceLayer(float);
00169         void SetAutoDisableLinearThreshold(float);
00170         void SetAutoDisableAngularThreshold(float);
00171         void SetGravity(const vec2&);
00172         dJointID AddMotor(Object &object);
00173         dJointID Glue(Object &object1, Object &object2);
00174         dJointID AnchorAxis(Object &object, const vec2 &axis);
00175         dJointID Anchor(Object &o1, Object &o2, const vec2 &point, float mu, float erp);
00176         dJointID Anchor(Object &o1, const vec2 &point, float mu, float erp);
00177         void DeleteJoint(dJointID joint);
00178         static void SetMotorVelocity(dJointID joint, float velocity);
00179         static float GetMotorVelocity(dJointID joint);
00180       private:
00181         int contactCount;
00182         dWorldID world;
00183         dJointGroupID contactGroup;
00184         ContactList contactList;
00185     };
00186 
00187     /// Contact generator for 2D geometry.
00188     //
00189     /// GenerateContacts is a template function that takes any object that acts
00190     /// like an STL container of pointers.
00191     /// It generates all appropriate ODE joints for simulating 2D collisions.
00192     /// The given container does not need to be an actual STL container; it only needs to have these properties:
00193     ///  - Container::const_iterator
00194     ///  - Container::begin()
00195     ///  - Container::end()
00196     /// The objects in the container must have a GetFlatlandObject() method.
00197     template<class Container>
00198     void World::GenerateContacts(const Container &space)
00199     {
00200         dJointGroupEmpty(contactGroup);
00201         contactCount = 0;
00202         typename Container::const_iterator o1;
00203         for (o1 = space.begin(); o1 != space.end(); ++o1)
00204         {
00205             Object *object1 = (*o1)->GetFlatlandObject();
00206             if (!object1)
00207                 continue;
00208 
00209             typename Container::const_iterator o2 = o1;
00210             for (++o2; o2 != space.end(); ++o2)
00211             {
00212                 Object *object2 = (*o2)->GetFlatlandObject();
00213                 if (!object2)
00214                     continue;
00215 
00216                 if (!object1->IsDynamic() && !object2->IsDynamic())
00217                     continue;
00218 
00219                 if (!(object1->Property().collisionMask & object2->Property().collisionMask))
00220                     if (!object1->Property().callback && !object2->Property().callback)
00221                         continue;
00222 
00223                 Geometry &g1 = object1->GetGeometry();
00224                 Geometry &g2 = object2->GetGeometry();
00225 
00226                 if (Intersection::Test(g1, g2))
00227                 {
00228                     contactList.Reset(object1, object2);
00229                     Intersection::Find(g1, g2, contactList);
00230                     contactList.Finalize();
00231                     if ((object1->Property().collisionMask & object2->Property().collisionMask))
00232                     {
00233                         contactList.CreateJoints(world, contactGroup);
00234                         contactCount += contactList.Count();
00235                     }
00236                 }
00237             }
00238         }
00239     }
00240 
00241     /// Corruption detection in a scene.
00242     //
00243     /// IsCorrupt is a template function that takes any object that acts
00244     /// like an STL container of pointers.
00245     /// The given container does not need to be an actual STL container; it only needs to have these properties:
00246     ///  - Container::const_iterator
00247     ///  - Container::begin()
00248     ///  - Container::end()
00249     /// The objects in the container must have a GetFlatlandObject() method.
00250     template<class Container>
00251     bool World::IsCorrupt(const Container &space) const
00252     {
00253         typename Container::const_iterator o;
00254         for (o = space.begin(); o != space.end(); ++o)
00255         {
00256             Object *object = (*o)->GetFlatlandObject();
00257             if (!object)
00258                 continue;
00259 
00260             Body body = object->GetBody();
00261             if (!body)
00262                 continue;
00263 
00264             const dReal *lvel = dBodyGetLinearVel(body);
00265             const dReal *avel = dBodyGetAngularVel(body);
00266 
00267             if (is_nan(lvel[0])) return true;
00268             if (is_nan(lvel[1])) return true;
00269             if (is_nan(avel[0])) return true;
00270             if (is_nan(avel[1])) return true;
00271         }
00272         return false;
00273     }
00274 
00275 
00276     template<class G>
00277     Dynamic<G>::Dynamic(G *g, Body b) : geometry(g), body(b)
00278     {
00279         body->geom = this;
00280 
00281         dMatrix3 R;
00282         float theta = atan2f(geometry->Axis(0).y, geometry->Axis(0).x); // TODO inefficient
00283         dRFromAxisAndAngle(R, 0, 0, 1, theta);
00284         dBodyInit(body, geometry->Center().x, geometry->Center().y, R);
00285 
00286         SetMass(Object::Default().density);
00287     }
00288 }
00289 
00290 typedef Flatland::Object *dGeomID;
00291 void dGeomMoved(dGeomID g);
00292 dGeomID dGeomGetBodyNext(dGeomID);
00293 void dGeomSetBody(dGeomID g, dBodyID b);

Generated on Sat Jan 13 17:20:21 2007 for Flatland by doxygen 1.5.1