World of Rigid Bodies (WoRB)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
RigidBody.h
Go to the documentation of this file.
00001 #ifndef _WORB_RIGID_BODY_H_INCLUDED
00002 #define _WORB_RIGID_BODY_H_INCLUDED
00003 
00004 /**
00005  *  @file      RigidBody.h
00006  *  @brief     Definitions for the RigidBody class.
00007  *  @author    Mikica B Kocic
00008  *  @version   0.4
00009  *  @date      2012-05-01
00010  *  @copyright GNU Public License.
00011  */
00012 
00013 #include "Quaternion.h"
00014 #include "QTensor.h"
00015 
00016 namespace WoRB {
00017 
00018     /** Encapsulates a rigid body. 
00019      *
00020      * Rigid body is the basic simulation object in the World of Bodies (WoRB).
00021      *
00022      * Properties:
00023      *  - inverse mass, and
00024      *  - inverse moment of inertia
00025      *
00026      * State variables: 
00027      *  - position, 
00028      *  - orientation, 
00029      *  - linear momentum, and 
00030      *  - angular momentum
00031      *
00032      * Derived quantities:
00033      *  - linear and angular velocity, kinetic energy, etc.
00034      *
00035      */
00036     class RigidBody
00037     {
00038     public:
00039         /////////////////////////////////////////////////////////////////////////////////
00040         /** @name Properties and state variables of the rigid body                     */
00041                                                                                    /*@{*/
00042         /** Holds the inverse of the mass of the rigid body. 
00043          */
00044         double InverseMass;
00045 
00046         /** Holds the inverse of the body's moment of inertia tensor in body-fixed frame.
00047          */
00048         QTensor InverseInertiaBody;
00049 
00050         /** Holds the linear position of the rigid body in world space.
00051          */
00052         Quaternion Position;
00053 
00054         /** Holds the angular orientation of the rigid body in world space.
00055          */
00056         Quaternion Orientation;
00057 
00058         /** Holds the linear momentum of the rigid body in world space.
00059          */
00060         Quaternion LinearMomentum;
00061 
00062         /** Holds the angular momentum of the rigid body in world space.
00063          */
00064         Quaternion AngularMomentum;
00065                                                                                    /*@}*/
00066         /////////////////////////////////////////////////////////////////////////////////
00067         /** @name Derived quantities                                                   */
00068 
00069         /** Holds a combined translation/rotation matrix for converting from body-fixed 
00070          * local coordinates into world coordinates.
00071          *
00072          * Columns of ToWorld transofmr matrix are base unit vectors (axes) of
00073          * the rigid body as seen in the world frame of reference.
00074          */
00075         QTensor ToWorld;
00076 
00077         /** Holds the inverse inertia tensor of the body in world space.
00078          */
00079         QTensor InverseInertiaWorld;
00080 
00081         /** Holds the linear velocity of the rigid body in world space.
00082          */
00083         Quaternion Velocity;
00084 
00085         /** Holds the angular velocity of the rigid body in world space.
00086          */
00087         Quaternion AngularVelocity;
00088         
00089         /** Holds the total angular momentum of the rigid body in world space.
00090          */
00091         Quaternion TotalAngularMomentum;
00092 
00093         /** Holds the total kinetic energy of the rigid body.
00094          */
00095         double KineticEnergy;
00096 
00097         /** Holds the total potential energy of the rigid body.
00098          */
00099         double PotentialEnergy;
00100                                                                                    /*@{*/
00101         /** Holds the amount of weighted mean kinetic energy of the body. 
00102          */
00103         double AverageKineticEnergy;
00104 
00105         /** Holds the kinetic energy level under which a body will considered stationary.
00106          */
00107         double KineticEnergyThreshold;
00108 
00109         /** Indicates whether to impose kinetic energy damping.
00110          */
00111         bool KineticEnergyDamping;
00112                                                                                    /*@}*/
00113         /////////////////////////////////////////////////////////////////////////////////
00114         /** @name Total force and torque accumulators
00115          *
00116          * These variables store the current total force, torque and acceleration of the 
00117          * rigid body; these quantities are accummulated inbetween time-steps.
00118          */                                                                        /*@{*/
00119 
00120         /** Holds the accumulated force to be applied at the next integration step.
00121          */
00122         Quaternion Force;
00123 
00124         /** Holds the accumulated torque to be applied at the next integration step.
00125          */
00126         Quaternion Torque;
00127                                                                                    /*@}*/
00128     public:
00129         /////////////////////////////////////////////////////////////////////////////////
00130         /** @name Constructors and destructors                                         */
00131                                                                                    /*@{*/
00132         RigidBody ()
00133             : InverseMass( 0 )
00134             , ToWorld( QTensor::Identity )
00135             , KineticEnergy( 0 )
00136             , PotentialEnergy( 0 )
00137             , AverageKineticEnergy( 0 )
00138             , KineticEnergyThreshold( 0 )
00139             , KineticEnergyDamping( false )
00140             , IsActive( false )
00141             , CanBeDeactivated( false )
00142         {
00143         }
00144                                                                                    /*@}*/
00145         /////////////////////////////////////////////////////////////////////////////////
00146         /** @name Integration and simulation methods
00147          *
00148          * These methods are used to simulate the rigid body's motion over time.
00149          */                                                                        /*@{*/
00150 
00151         /** Integrates the rigid body forward in time for the given time-step length.
00152          */
00153         void SolveODE( double h )
00154         {
00155             if ( ! IsActive ) {
00156                 return;
00157             }
00158 
00159             // Solve the linear momentum
00160             //
00161             LinearMomentum += Force * h;
00162 
00163             // Solve the angular momentum in world space (included gyroscopic effect)
00164             //
00165             AngularMomentum += Torque * h;
00166 
00167             // If enabled, remove kinetic energy added through the numerical 
00168             // instability in the Semi-implicit Euler integrator.
00169             //
00170             if ( KineticEnergyDamping ) {
00171                 DampMomentum( h );
00172             }
00173 
00174             // Derive the linear and the angular velocity
00175             //
00176             Velocity = InverseMass * LinearMomentum;
00177             AngularVelocity = InverseInertiaWorld * AngularMomentum;
00178 
00179             // Calculate the orientation time derivative in world space
00180             //
00181             Quaternion OrientationDot = 0.5 * AngularVelocity * Orientation;
00182 
00183             // Solve the linear position
00184             //
00185             Position += Velocity * h;
00186 
00187             // Solve the orientation (angular position)
00188             //
00189             Orientation += OrientationDot * h;
00190 
00191             // Normalize orientation to versor and calculate derived quantities
00192             //
00193             CalculateDerivedQuantities ();
00194 
00195             // Deactivate body, if allowed, when it becomes stationary.
00196             //
00197             if ( CanBeDeactivated )
00198             {
00199                 // Calculate exponential average of the kinetic energy
00200                 //
00201                 double alpha = pow( 0.5, h ); // alpha = 1 / 2^h
00202                 AverageKineticEnergy = alpha * AverageKineticEnergy 
00203                                      + ( 1 - alpha ) * KineticEnergy;
00204 
00205                 if ( AverageKineticEnergy < KineticEnergyThreshold ) {
00206                     Deactivate ();
00207                 }
00208                 else if ( AverageKineticEnergy > 10 * KineticEnergyThreshold ) {
00209                     AverageKineticEnergy = 10 * KineticEnergyThreshold;
00210                 }
00211             }
00212         }
00213 
00214         /** Normalizes orientation and calculates derived quantities 
00215          * from the state variables.
00216          *
00217          * @param fromMomenta  If true, derive quantites from linear and angular momenta; 
00218          *                     otherwise, derive quantities from velocities.
00219          *
00220          */
00221         void CalculateDerivedQuantities( bool fromMomenta = true )
00222         {
00223             // Normalize the orientation to versor
00224             //
00225             Orientation.Normalize ();
00226 
00227             // Setup the transform matrix for the body from orientation and position.
00228             //
00229             ToWorld.SetFromOrientationAndPosition( Orientation, Position );
00230 
00231             // Setup the moment of inertia tensor in world frame of reference.
00232             //
00233             InverseInertiaWorld = ToWorld( InverseInertiaBody );
00234 
00235             if ( fromMomenta )
00236             {
00237                 // Calculate the linear and angular velocity from respecitve momenta
00238                 //
00239                 Velocity = InverseMass * LinearMomentum;
00240                 AngularVelocity = InverseInertiaWorld * AngularMomentum;
00241             }
00242             else
00243             {
00244                 // Calculate the linear and angular momentum from repsective velocities
00245                 //
00246                 LinearMomentum  = Mass()  * Velocity;
00247                 AngularMomentum = InverseInertiaWorld.Inverse () * AngularVelocity;
00248             }
00249 
00250             // Calculate the total angular momentum
00251             //
00252             TotalAngularMomentum = Position.Cross( LinearMomentum ) + AngularMomentum;
00253 
00254             // Derive the total kinetic energy
00255             //
00256             KineticEnergy = 0.5 * Velocity        .Dot( LinearMomentum  )
00257                           + 0.5 * AngularVelocity .Dot( AngularMomentum );
00258         }
00259 
00260         /** Damp linear and angular momentum.
00261          */
00262         void DampMomentum( double timeStep )
00263         {
00264             const double linearDamping  = 0;
00265             const double angularDamping = 0.998;
00266 
00267             if ( linearDamping > 0 ) {
00268                 LinearMomentum *= pow( linearDamping, timeStep );
00269             }
00270             if ( angularDamping > 0 ) {
00271                 AngularMomentum *= pow( angularDamping, timeStep );
00272             }
00273         }
00274                                                                                    /*@}*/
00275         /////////////////////////////////////////////////////////////////////////////////
00276         /** @name Property getters and setters                                         */
00277                                                                                    /*@{*/
00278         /** Sets the mass of the rigid body.
00279          */
00280         void SetupMass( double mass )
00281         {
00282             InverseMass = mass == 0 ? 1e+30 
00283                         : mass >= 1e+30 ? 0.0 : 1.0 / mass;
00284 
00285             KineticEnergyThreshold = 0.3 * mass;
00286         }
00287 
00288         /** Gets the mass of the rigid body.
00289          */
00290         double Mass () const
00291         {
00292             return InverseMass == 0 ? 1e+30 
00293                  : InverseMass >= 1e+30 ? 0.0 : 1.0 / InverseMass;
00294         }
00295 
00296         /** Returns true if the mass of the body is not-infinite.
00297          */
00298         bool IsFiniteMass () const
00299         {
00300             return InverseMass > 0.0;
00301         }
00302 
00303         /** Initializs the position, orientation, velocity and angular velocity
00304          * of the rigid body and updates other derived quantities.
00305          */
00306         void Set_XQVW
00307         (
00308             const Quaternion& X,  //!< The initial position
00309             const Quaternion& Q,  //!< The initial orientation
00310             const Quaternion& V,  //!< The initial velocity
00311             const Quaternion& W   //!< The initial angular velocity in world space
00312             )
00313         {
00314             Position        = X;
00315             Orientation     = Q;
00316             Velocity        = V;
00317             AngularVelocity = W;
00318 
00319             CalculateDerivedQuantities( /*fromMomenta*/ false );
00320         }
00321 
00322         /** Sets the intertia tensor for the rigid body.
00323          */
00324         void SetMomentOfInertia( const QTensor& I_body )
00325         {
00326             InverseInertiaBody.SetInverseOf( I_body );
00327         }
00328                                                                                    /*@}*/
00329         /////////////////////////////////////////////////////////////////////////////////
00330         /** @name Flags controlling ODE solver activity for the body                   */
00331                                                                                    /*@{*/
00332         /** A body can be inactivated to avoid it being updated SolveODE 
00333          * or affected  by collisions with the scenery.
00334          */
00335         bool IsActive;
00336 
00337         /** Controls whether body is allowed to be inactivated.
00338          */
00339         bool CanBeDeactivated;
00340 
00341         /** Allows body to move, i.e. enables its ODE to be solved.
00342          */
00343         void Activate ()
00344         {
00345             if ( ! IsActive ) 
00346             {
00347                 IsActive = true;
00348                 // Body must have some kinetic energy to avoid immediate deactivation
00349                 AverageKineticEnergy = 2 * 0.3 * Mass(); 
00350             }
00351         }
00352 
00353         /** Disallows body to move i.e. disables its ODE to be solved.
00354          * For deativated body, its velocities are also set to 0.
00355          */
00356         void Deactivate ()
00357         {
00358             IsActive             = false;
00359             LinearMomentum       = 0.0;
00360             AngularMomentum      = 0.0;
00361             TotalAngularMomentum = 0.0;
00362             Velocity             = 0;
00363             AngularVelocity      = 0;
00364             KineticEnergy        = 0;
00365             Force                = 0.0;
00366             Torque               = 0.0;
00367         }
00368 
00369         /** Sets whether the body is ever allowed to be deactivated.
00370          */
00371         void SetCanBeDeactivated( bool flag = true )
00372         {
00373             CanBeDeactivated = flag;
00374 
00375             if ( ! CanBeDeactivated && ! IsActive ) {
00376                 Activate ();
00377             }
00378         }
00379                                                                                    /*@}*/
00380         /////////////////////////////////////////////////////////////////////////////////
00381         /** @name Setters for the force, torque and acceleration
00382          *
00383          * These functions set up forces and torques to apply to the rigid body.
00384          */                                                                        /*@{*/
00385 
00386         /** Clears the forces and torques in the accumulators. 
00387          */
00388         void ClearAccumulators ()
00389         {
00390             Force  = 0;
00391             Torque = 0;
00392             PotentialEnergy = 0;
00393         }
00394 
00395         /** Adds the given external force to center of mass of the rigid body.
00396          * An external force acts on the whole body equally and does not activate 
00397          * inactive bodies.
00398          */
00399         void AddExternalForce( const Quaternion& force, double potentialEnergy = 0 )
00400         {
00401             Force += force;
00402             PotentialEnergy += potentialEnergy;
00403         }
00404 
00405         /** Adds the given internal force to center of mass of the rigid body.
00406          */
00407         void AddForce( const Quaternion& force, double potentialEnergy = 0 )
00408         {
00409             Force += force;
00410             PotentialEnergy += potentialEnergy;
00411             IsActive = true;
00412         }
00413 
00414         /** Adds the given internal force to the given point on the rigid body.
00415          */
00416         void AddForceAtPoint( const Quaternion& worldPoint, 
00417             const Quaternion& force, double potentialEnergy = 0 )
00418         {
00419             Force += force;
00420             Torque += ( worldPoint - Position ).Cross( force );
00421             PotentialEnergy += potentialEnergy;
00422             IsActive = true;
00423         }
00424 
00425         /** Adds the given internal force to the given point on the rigid body.
00426          */
00427         void AddForceAtBodyPoint( const Quaternion& bodyPoint,
00428             const Quaternion& force, double potentialEnergy = 0  )
00429         {
00430             AddForceAtPoint( ToWorld( bodyPoint ), force, potentialEnergy );
00431         }
00432 
00433         /** Adds the given internal torque to the rigid body.
00434          */
00435         void AddTorque( const Quaternion& torque )
00436         {
00437             Torque += torque;
00438             IsActive = true;
00439         }
00440 
00441         /////////////////////////////////////////////////////////////////////////////////
00442     };
00443 
00444 } // WoRB
00445 
00446 #endif // _WORB_RIGID_BODY_H_INCLUDED