|
World of Rigid Bodies (WoRB)
|
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