World of Rigid Bodies (WoRB)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Collision.h
Go to the documentation of this file.
00001 #ifndef _WORB_COLLISION_H_INCLUDED
00002 #define _WORB_COLLISION_H_INCLUDED
00003 
00004 /**
00005  *  @file      Collision.h
00006  *  @brief     Definitions for the Collision class which implements the collision
00007  *             response for a single collision.
00008  *  @author    Mikica Kocic
00009  *  @version   0.18
00010  *  @date      2012-05-02
00011  *  @copyright GNU Public License.
00012  */
00013 
00014 #include "RigidBody.h"
00015 
00016 namespace WoRB {
00017 
00018     /** Encalpsulates a collision event between two bodies; contains contact details.
00019      */
00020     class Collision
00021     {
00022         friend class CollisionResolver;
00023 
00024     public:
00025         /////////////////////////////////////////////////////////////////////////////////
00026         /** @name Collision state variables                                            */
00027                                                                                    /*@{*/
00028         /** Holds the first rigid body that is involved in the collision. 
00029          */
00030         RigidBody* Body_A;
00031 
00032         /** Holds the second rigid body that is involved in the collision.
00033          * It is null in case of the collision with a scenery.
00034          */
00035         RigidBody* Body_B;
00036 
00037         /** Holds the position of the contact in world frame of reference.
00038          */
00039         Quaternion Position;
00040 
00041         /** Holds the direction of the contact in world frame of reference.
00042          */
00043         Quaternion Normal;
00044 
00045         /** Holds the penetration depth at the point of contact.
00046          */
00047         double Penetration;
00048 
00049         /** Holds the position projections coefficient for this collision.
00050          */
00051         double Restitution;
00052 
00053         /** Holds the friction coefficient for this collision.
00054          */
00055         double Friction;
00056 
00057         /** Returns true if the collision is with scenery.
00058          */
00059         bool WithScenery () const
00060         {
00061             return ! Body_B;
00062         }
00063 
00064     private:
00065                                                                                    /*@}*/
00066         /////////////////////////////////////////////////////////////////////////////////
00067         /** @name Collision response methods                                           */
00068                                                                                    /*@{*/
00069         /** Updates the derived quantities from the state data.
00070          * @note Should be called before the collision response algorithm executes.
00071          */
00072         void UpdateDerivedQuantities( double h /*!< Time-step */ )
00073         {
00074             if ( ! Body_A ) // Reverse the contact and swap the bodies
00075             {
00076                 Normal = -Normal; // Reverse the contact normal
00077 
00078                 RigidBody* temp = Body_A; // Swap bodies
00079                 Body_A = Body_B; 
00080                 Body_B = temp;
00081             }
00082 
00083             // Calculate an set of axis at the point of contact.
00084             //
00085             FindOrthonormalBasisAtContactPoint ();
00086 
00087             // Find the relative position and velocity relative to each body
00088             //
00089             RelativePosition[0] = Position - Body_A->Position;
00090             Velocity = GetRelativeVelocity( Body_A, RelativePosition[0], h );
00091 
00092             if ( Body_B ) 
00093             {
00094                 RelativePosition[1] = Position - Body_B->Position;
00095                 Velocity -= GetRelativeVelocity( Body_B, RelativePosition[1], h );
00096             }
00097 
00098             // Calculate the desired change in velocity for the collision resolution
00099             //
00100             BouncingVelocity = GetBouncingVelocity( h );
00101         }
00102 
00103         /** Applies the linear & angular impulses needed to resolve the collision.
00104          */
00105         void ImpulseTransfer( 
00106             Quaternion V_jolt[2], //!< Returned applied velocity jolt
00107             Quaternion W_jolt[2]  //!< Returned applied angular velocity jolt
00108         );
00109 
00110         /** Applies the linear position jolt needed to resolve the collision.
00111          */
00112         void PositionProjection( 
00113             Quaternion X_jolt[2], //!< Returned applied position jolt
00114             Quaternion Q_jolt[2], //!< Returned applied orientation jolt
00115             double relaxation     //!< Position projections relaxation coefficient
00116         );
00117 
00118     private:
00119                                                                                    /*@}*/
00120         /////////////////////////////////////////////////////////////////////////////////
00121         /** @name Derived quantities                                                   */
00122                                                                                    /*@{*/
00123         /** Contains a transformation matrix from body to world frame of reference.
00124          */
00125         QTensor ToWorld;
00126 
00127         /** Holds the relative velocity v_A - v_B between bodies at the point of contact.
00128          */
00129         Quaternion Velocity;
00130 
00131         /** Holds the required change in velocity for this contact to be resolved.
00132          * The basic expression is `-( 1 + COR ) * Velocity.x`
00133          */
00134         double BouncingVelocity;
00135 
00136         /** Holds the position of the contact point in world frame, relative to the
00137          * center of each body.
00138          */
00139         Quaternion RelativePosition[2];
00140                                                                                    /*@}*/
00141         /////////////////////////////////////////////////////////////////////////////////
00142         /** @name Methods that calculates derived quantities                           */
00143                                                                                    /*@{*/
00144         /** Calculates the impulse needed to resolve the collision without friction.
00145          */
00146         Quaternion GetImpulse ();
00147 
00148         /** Calculates the impulse needed to resolve the collision in general case.
00149          */
00150         Quaternion GetImpulse_IncludeFriction ();
00151 
00152         /** Activates (only) inactive bodies in a collision. 
00153          * Collisions with the scenery (in case where body B is null) never 
00154          * cause a body to be activated.
00155          */
00156         void ActivateInactiveBodies ()
00157         {
00158             if ( Body_B && ( Body_A->IsActive ^ Body_B->IsActive ) )
00159             {
00160                 if ( Body_A->IsActive ) {
00161                     Body_B->Activate ();
00162                 }
00163                 else {
00164                     Body_A->Activate ();
00165                 }
00166             }
00167         }
00168 
00169         /** Calculates an orthonormal basis for the contact point.
00170          */
00171         void FindOrthonormalBasisAtContactPoint ()
00172         {
00173             Quaternion tangent_Y, tangent_Z;
00174 
00175             if ( fabs( Normal.x ) > fabs( Normal.y ) ) // Z-axis is nearer to the Y axis
00176             {
00177                 double length = 1.0 / sqrt( Normal.z * Normal.z + Normal.x * Normal.x );
00178 
00179                 // The new X-axis is at right angles to the world Y-axis
00180                 tangent_Y.x =  Normal.z * length;
00181                 tangent_Y.y =  0;
00182                 tangent_Y.z = -Normal.x * length;
00183 
00184                 // The new Y-axis is at right angles to the new X- and Z- axes
00185                 tangent_Z.x =  Normal.y * tangent_Y.x;
00186                 tangent_Z.y =  Normal.z * tangent_Y.x - Normal.x * tangent_Y.z;
00187                 tangent_Z.z = -Normal.y * tangent_Y.x;
00188                 tangent_Z.Normalize ();
00189             }
00190             else // Z-axis is nearer to the X axis
00191             {
00192                 double length = 1.0 / sqrt( Normal.z * Normal.z + Normal.y * Normal.y );
00193 
00194                 // The new X-axis is at right angles to the world X-axis
00195                 tangent_Y.x =  0;
00196                 tangent_Y.y = -Normal.z * length;
00197                 tangent_Y.z =  Normal.y * length;
00198 
00199                 // The new Y-axis is at right angles to the new X- and Z- axes
00200                 tangent_Z.x =  Normal.y * tangent_Y.z - Normal.z * tangent_Y.y;
00201                 tangent_Z.y = -Normal.x * tangent_Y.z;
00202                 tangent_Z.z =  Normal.x * tangent_Y.y;
00203                 tangent_Z.Normalize ();
00204             }
00205 
00206             /* Orthonormal basis is a 3x3 matrix, where each vector is a column. 
00207              * The X-direction is generated from the contact normal, and the Y and Z
00208              * directions are set so they are at right angles to it.
00209              */
00210             ToWorld.SetColumnVectors( Normal, tangent_Y, tangent_Z );
00211         }
00212 
00213         /** Gets the relative velocity for the point of contact on the given body.
00214          */
00215         Quaternion GetRelativeVelocity(
00216             RigidBody* body,                    //!< The pointer to the rigid body
00217             const Quaternion& relativePosition, //!< Relative position to the contact
00218             double h                            //!< The last time-step
00219             )
00220         {
00221             // Calculate the velocity of the contact point in contact coordinates
00222             //
00223             Quaternion V_world = body->Velocity 
00224                                + body->AngularVelocity.Cross( relativePosition );
00225 
00226             Quaternion V = ToWorld.TransformInverse( V_world );
00227 
00228             // Calculate the ammount of velocity that is due to forces without reactions,
00229             // ignoring any component of acceleration in the contact normal direction 
00230             // (where only tangential/planar components are considered)
00231             //
00232             Quaternion dV_world = body->InverseMass * body->Force * h;
00233 
00234             Quaternion dV = ToWorld.TransformInverse( dV_world );
00235 
00236             dV.x = 0; // consider only tangential components
00237 
00238             // Add the tangential velocities (they will removed during the impulse
00239             // transfer, if there's enough friction).
00240             //
00241             return V + dV;
00242         }
00243 
00244         /** Calculates the bouncing velocity required to resolve the collision.
00245          * The bouncing velocity is `-( 1 + COR ) * NormalVelocity.x`.
00246          */
00247         double GetBouncingVelocity( double h /*!< Time-step */ )
00248         {
00249             // Calculate the normal component of the velocity induced by the force 
00250             // accumulated in the last time step.
00251             //
00252             double dV_fromForce_x = 0;
00253             if ( Body_A->IsActive )
00254             {
00255                 Quaternion last_dV = Body_A->InverseMass * Body_A->Force * h;
00256                 dV_fromForce_x += last_dV.Dot( Normal );
00257             }
00258             if ( Body_B && Body_B->IsActive )
00259             {
00260                 Quaternion last_dV = Body_B->InverseMass * Body_B->Force * h;
00261                 dV_fromForce_x -= last_dV.Dot( Normal );
00262             }
00263 
00264             // Limit the restitution in case when the velocity is very low.
00265             //
00266             double COR = fabs( Velocity.x - dV_fromForce_x ) < 0.25 ? 0.0 : Restitution;
00267 
00268             // The result is the bouncing-velocity, reduced for the velocity that was
00269             // induced by the force exerted in the last time-step.
00270             //
00271             return - ( 1 + COR ) * Velocity.x + COR * dV_fromForce_x;
00272         }
00273                                                                                    /*@}*/
00274         /////////////////////////////////////////////////////////////////////////////////
00275         /** @name Miscellaneous methods                                                */
00276                                                                                    /*@{*/
00277         /** Displays the collision state variables on standard output.
00278          */
00279         private: void Dump( unsigned id, double currentTime ) const;
00280                                                                                    /*@}*/
00281         /////////////////////////////////////////////////////////////////////////////////
00282     };
00283 } // namespace WoRB
00284 
00285 #endif // _WORB_COLLISION_H_INCLUDED