00001 00003 // 00004 // -= Particle =- 00005 // 00006 // Definition: "particle, just position no rotation, 2nd order derivatives" 00007 // 00009 // 00010 // $RCSfile: Particle.h,v $ 00011 // $Date: 2002/06/10 03:08:00 $ 00012 // $Revision: 1.9 $ 00013 // Copyright (C) 1998, 1999, 2000 Kevin Meinert, kevin@vrsource.org 00014 // 00015 // This library is free software; you can redistribute it and/or 00016 // modify it under the terms of the GNU Library General Public 00017 // License as published by the Free Software Foundation; either 00018 // version 2 of the License, or (at your option) any later version. 00019 // 00020 // This library is distributed in the hope that it will be useful, 00021 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00023 // Library General Public License for more details. 00024 // 00025 // You should have received a copy of the GNU Library General Public 00026 // License along with this library; if not, write to the Free 00027 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00028 // 00030 #ifndef PARTICLE_INCLUDED_H 00031 #define PARTICLE_INCLUDED_H 00032 00033 #include <gmtl/Vec.h> 00034 00035 #include "ani/Dynamics/Memory.h" 00036 00037 // Rigid body references: 00038 // - Thick, very detailed. 00039 // http://www.cs.cmu.edu/~baraff/sigcourse/ 00040 // - Easy to understand, most is implemented from it. 00041 // http://www.cs.unc.edu/~ehmann/RigidTutorial/ 00042 00043 00044 // ani namespace. 00045 namespace ani 00046 { 00047 //: Particle, for use in a particle system. 00048 // particle is able to do newtonian physics through application of force. 00049 // - Dynamic attributes (affected by force) include position, and velocity 00050 // - Static attributes (which are not affected by force) include mass, and color. 00051 // 00052 // Use Particle objects in conjunction with DynamicSystem, Operator, and ODEsolvers. 00053 // 00054 // Notes on "phase space" 00055 // The motion of a newtonian particle is governed by the familiar f = ma, or, as we will write it here 00056 // x'' = a = f/m. This equation differs from a canonical ODE because it involves a second time derivative, making 00057 // it a _second_order_ equation. To handle a second order ODE, we convert it to a first order one by introducing 00058 // extra variables. Here we create a variable mVelocity to represent velocity, giving us a pair of coupled first 00059 // order ODE's: v' = f/m, and x' = v. This position/velocity product space is called _phase_space_. 00060 class Particle : public ani::Memory 00061 { 00062 public: 00063 Particle() : ani::Memory(), 00064 mPosition( 0.0f, 0.0f, 0.0f ), 00065 mLinearMomentum( 0.0f, 0.0f, 0.0f ), 00066 mForceAccumulator( 0.0f, 0.0f, 0.0f ), 00067 mMass( 1.0f ), mInvMass( 1.0f ), mVolume( 1.0f, 1.0f, 1.0f ), 00068 mDragCoef(1.0f)//, mColor 00069 { 00070 } 00071 00072 Particle( const Particle& p ) 00073 { 00074 this->copy( p ); 00075 } 00076 00077 virtual ~Particle() 00078 { 00079 } 00080 00081 // operations/operators: 00082 public: 00083 00084 Particle& operator=( const Particle& p ) 00085 { 00086 this->copy( p ); 00087 return *this; 00088 } 00089 00090 // this = p 00091 // copies all attributes. 00092 inline virtual void copy( const Particle& p ) 00093 { 00094 mPosition = p.mPosition; 00095 mLinearMomentum = p.mLinearMomentum; 00096 mForceAccumulator = p.mForceAccumulator; 00097 mMass = p.mMass; 00098 mInvMass = p.mInvMass; 00099 mVolume = p.mVolume; 00100 mDragCoef = p.mDragCoef; 00101 } 00102 00103 //: computeDerivative 00104 // 00105 // The behavior of the system is described by an "Ordinary 00106 // Differential Equation" (ODE) of the form 00107 // x' = f( x, t ) 00108 // where f is a known function, x is the state of the system 00109 // and x' is the time derivitive of x. 00110 // 00111 // Here, f = computeDerivative, x' = this, and x = currentState; 00112 // This function computes change due to the force accumulator 00113 // The x' returned assumes time=1, so for example using Euler's 00114 // method to solve the next step, you will have to scale 00115 // x' by the amount of time since this func was last called. 00116 // 00117 // 00118 // this = the time derivitive of "currentState" 00119 inline virtual void computeDerivative( const Particle& currentState, const float& currentTime ) 00120 { 00121 // change in position/rotation over time (first order) 00122 // x' = v = P(t)/M 00123 mPosition = currentState.linearVelocity(); 00124 00125 // change in momentum over time (second order) 00126 // P'(t) = F(t) 00127 mLinearMomentum = currentState.mForceAccumulator; 00128 } 00129 00130 virtual void normalize() 00131 { 00132 } 00133 00134 // scale by time. 00135 // this = a * h 00136 inline virtual void multiplyPhase( const Particle& a, float h ) 00137 { 00138 mPosition = a.mPosition * h; 00139 mLinearMomentum = a.mLinearMomentum * h; 00140 } 00141 00142 // scale by time. 00143 // this *= h 00144 inline virtual void multiplyPhase( float h ) 00145 { 00146 mPosition *= h; 00147 mLinearMomentum *= h; 00148 } 00149 00150 // phase space addition operator 00151 // this = a + b 00152 inline virtual void addPhase( const Particle& a, const Particle& b ) 00153 { 00154 mPosition = a.mPosition + b.mPosition; 00155 mLinearMomentum = a.mLinearMomentum + b.mLinearMomentum; 00156 } 00157 00158 // phase space addition operator 00159 // this += a 00160 inline virtual void addPhase( const Particle& a ) // 00161 { 00162 mPosition += a.mPosition; 00163 mLinearMomentum += a.mLinearMomentum; 00164 } 00165 00166 // state setting/accumulation 00167 public: 00168 void setPosition( const gmtl::Vec3f& position) { mPosition = position; } 00169 void setVelocity( const gmtl::Vec3f& velocity ) { mLinearMomentum = velocity * mMass; } 00170 00171 //: Apply a force to the particle 00172 // Each call to applyForce adds a force vector and torque to the particle. 00173 // call update() to finally apply the accumulated forces which were added with this function. 00174 // NOTE: the force applied, should be with respect to 1.0 unit of time. 00175 void applyForce( const gmtl::Vec3f& force ) 00176 { 00177 mForceAccumulator += force; 00178 } 00179 00180 inline virtual void zeroForce() 00181 { 00182 mForceAccumulator.set( 0.0f, 0.0f, 0.0f ); 00183 } 00184 00185 //: set the mass 00186 // units are metric kilograms 00187 void setMass( const float& kilograms ) 00188 { 00189 mMass = kilograms; 00190 00191 // precompute the inverse mass 00192 mInvMass = 1.0f / kilograms; 00193 } 00194 00195 void setVolume( gmtl::Vec3f vol ) 00196 { 00197 mVolume = vol; 00198 } 00199 00200 // aliases (getters) 00201 public: 00202 // "phase space" (see note above) 00203 inline const gmtl::Vec3f& position() const { return mPosition; } 00204 00205 //: Calculate v(t) 00206 inline gmtl::Vec3f linearVelocity() const 00207 { 00208 return mLinearMomentum * mInvMass; 00209 } 00210 00211 inline gmtl::Vec3f linearMomentum() const 00212 { 00213 return mLinearMomentum; 00214 } 00215 00216 // other things needed by ODE to compute changes in the "phase space" 00217 inline const gmtl::Vec3f& accumulatedForce() const { return mForceAccumulator; } 00218 inline const float& mass() const { return mMass; } 00219 inline const gmtl::Vec3f& volume() const { return mVolume; } 00220 00221 public: 00222 //:: "phase space" (see note above) 00223 // state variables: 00224 gmtl::Vec3f mPosition; // meters - x(t) 00225 gmtl::Vec3f mLinearMomentum; // linear momentum P(t) 00226 // mLinearMomentum = mMass * mVelocity 00227 00228 // derived quantities (aux variables) 00229 //gmtl::Vec3f mVelocity; // v(t) (meters/second) 00230 00231 //:: other things needed by ODE to compute changes in the "phase space" 00232 00233 // accumulation buffers: 00234 gmtl::Vec3f mForceAccumulator; // newtons - F(t) 00235 00236 // constant (set) quantities 00237 float mMass, mInvMass; // kilograms 00238 gmtl::Vec3f mVolume; // 3D volume (a box) 00239 00240 // other attribs for the particle. 00241 float mDragCoef; // just a coef from 0 (no drag) to 1 (drag) 00242 }; 00243 00244 }; // ani namespace 00245 00246 #endif