src/vamos/body/Rigid_Body.cc

Go to the documentation of this file.
00001 //  Rigid_Body.cc - a rigid body.
00002 //
00003 //  Copyright (C) 2001--2004 Sam Varner
00004 //
00005 //  This file is part of Vamos Automotive Simulator.
00006 //
00007 //  This program is free software; you can redistribute it and/or modify
00008 //  it under the terms of the GNU General Public License as published by
00009 //  the Free Software Foundation; either version 2 of the License, or
00010 //  (at your option) any later version.
00011 //
00012 //  This program is distributed in the hope that it will be useful,
00013 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //  GNU General Public License for more details.
00016 //
00017 //  You should have received a copy of the GNU General Public License
00018 //  along with this program; if not, write to the Free Software
00019 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 
00021 #include <vamos/body/Rigid_Body.h>
00022 #include <vamos/body/Aerodynamic_Device.h>
00023 #include <vamos/body/Contact_Point.h>
00024 
00025 #include <cassert>
00026 
00027 using Vamos_Geometry::Three_Vector;
00028 using Vamos_Geometry::Three_Matrix;
00029 
00030 //* Struct Contact_Parameters
00031 
00032 //** Constructor
00033 
00034 Vamos_Body::
00035 Contact_Parameters::Contact_Parameters () 
00036   : m_distance (0.0)
00037 {
00038 }
00039 
00040 //* Class Body
00041 
00042 //** Constructors
00043 
00044 // Specify the position and orientation of the body.
00045 Vamos_Body::
00046 Rigid_Body::Rigid_Body (const Three_Vector& pos, const Three_Matrix& orient) 
00047   : Frame (pos, orient),
00048     m_initial_position (pos),
00049     m_delta_time (0.0),
00050     m_mass (0.0)
00051 {
00052         valid = false;
00053 }
00054 
00055 // Specify the position, the orientation is the same as the parent.
00056 Vamos_Body::
00057 Rigid_Body::Rigid_Body (const Three_Vector& pos) 
00058   : Frame (pos),
00059     m_initial_position (pos),
00060     m_delta_time (0.0),
00061     m_mass (0.0)
00062 {
00063         valid = false;
00064 }
00065 
00066 // Specify the position, the orientation is the same as the parent.
00067 Vamos_Body::
00068 Rigid_Body::Rigid_Body () 
00069   : Frame (),
00070     m_delta_time (0.0),
00071     m_mass (0.0)
00072 {
00073         valid = false;
00074 }
00075 
00076 
00077 //** Destuctor
00078 Vamos_Body::Rigid_Body::
00079 ~Rigid_Body ()
00080 {
00081   // The body is responsible for deleting the partiles even though
00082   // they were constructed elsewhere
00083   for (std::vector <Particle*>::iterator it = m_particles.begin ();
00084        it != m_particles.end ();
00085        it++)
00086     {
00087         //delete *it;
00088     }
00089 }
00090 
00091 // Return the position of the center of mass of the body with respect
00092 // to the world.
00093 Three_Vector Vamos_Body::
00094 Rigid_Body::cm_position ()
00095 {
00096   return transform_out (m_body_cm, m_body_cm);
00097 }
00098 
00099 // Return the contact position of the INDEXth particle of
00100 // `m_particles' with respect to the world.
00101 Three_Vector Vamos_Body::
00102 Rigid_Body::contact_position (Particle* contact_point)
00103 {
00104   return transform_out (contact_point->contact_position (), m_body_cm);
00105 }
00106 
00107 Three_Vector Vamos_Body::
00108 Rigid_Body::last_contact_position (Particle* contact_point)
00109 {
00110         Three_Vector temp_position;
00111         Three_Matrix temp_orientation;
00112         
00113         temp_position = m_position;
00114         temp_orientation = m_orientation;
00115         
00116         m_position = m_last_position;
00117         m_orientation = m_last_orientation;
00118         
00119   Three_Vector out;
00120         
00121         out = transform_out (contact_point->contact_position (), m_last_body_cm);
00122         
00123         m_position = temp_position;
00124         m_orientation = temp_orientation;
00125         
00126         return out;
00127 }
00128 
00129 //set current state to last state
00130 void Vamos_Body::
00131 Rigid_Body::roll_back()
00132 {
00133         m_position = m_last_position;
00134         m_orientation = m_last_orientation;
00135         m_body_cm = m_last_body_cm;
00136         m_cm_velocity = m_last_cm_velocity;
00137         m_ang_velocity = m_last_ang_velocity;
00138 }
00139 
00140 void Vamos_Body::
00141 Rigid_Body::kill_vel()
00142 {
00143         m_velocity = m_velocity * 0; 
00144         m_ang_velocity = m_ang_velocity * 0;
00145         
00146         std::vector <Particle*>::const_iterator it = m_particles.begin ();
00147 
00148         for (it++; it != m_particles.end (); it++)
00149     {
00150                 (*it)->set_ang_velocity(m_ang_velocity);
00151                 (*it)->set_velocity(m_velocity);
00152         }
00153 }
00154 
00155 // Return the smallest contact position z-value of the particles.
00156 double Vamos_Body::
00157 Rigid_Body::lowest_contact_position () const
00158 {
00159   std::vector <Particle*>::const_iterator it = m_particles.begin ();
00160   double pos = transform_out ((*it)->contact_position ()) [2];
00161   double lowest = pos;
00162 
00163   for (it++; it != m_particles.end (); it++)
00164     {
00165       pos = transform_out ((*it)->contact_position ()) [2];
00166       if (pos < lowest)
00167         {
00168           lowest = pos;
00169         }
00170     }
00171 
00172   return lowest;
00173 }
00174 
00175 // Calculate the center of mass, the ineritia tensor, and its inverse.
00176 void Vamos_Body::
00177 Rigid_Body::update_center_of_mass ()
00178 {
00179         if (m_contact_parameters.m_distance > 0.0)
00180     {
00181         }
00182         else
00183                 m_last_body_cm = m_body_cm;
00184         
00185   // Find the center of mass in the body frame.
00186   m_body_cm = Three_Vector (0.0, 0.0, 0.0);
00187   m_mass = 0.0;
00188   for (std::vector <Particle*>::const_iterator it = m_particles.begin ();
00189        it != m_particles.end ();
00190        it++)
00191     {
00192       m_mass += (*it)->mass ();
00193       // The particle reports its position in the body frame.
00194       m_body_cm += (*it)->mass_position () * (*it)->mass ();
00195     }
00196   m_body_cm /= m_mass;
00197 
00198   // Initialize the inertia tensor.
00199   m_inertia.zero ();
00200   // Inertia tensor for rotations about the center of mass.
00201   for (std::vector <Particle*>::const_iterator it = m_particles.begin ();
00202        it != m_particles.end ();
00203        it++)
00204     {  
00205       m_inertia.add ((*it)->mass (),
00206                      (*it)->mass_position () - m_body_cm);
00207     }
00208   m_inertia.update ();
00209 }
00210 
00211 void Vamos_Body::
00212 Rigid_Body::find_forces ()
00213 {
00214   for (std::vector <Particle*>::const_iterator it = m_particles.begin ();
00215        it != m_particles.end ();
00216        it++)
00217     {
00218       (*it)->find_forces ();
00219     }
00220 }
00221 
00222 void Vamos_Body::
00223 Rigid_Body::propagate_contact()
00224 {
00225         // Process single-collision contact.
00226         if (m_contact_parameters.m_distance > 0.0)
00227     {
00228                 Particle* point = m_contact_parameters.mp_contact_point;
00229                 Three_Vector position = rotate_out (point->contact_position () 
00230                                                                                   - m_body_cm);
00231                 Three_Vector velocity = m_cm_velocity + rotate_out (m_ang_velocity).
00232                 cross (rotate_out (point->position () - m_body_cm));
00233                 Three_Vector ang_vel = 
00234                 m_ang_velocity.project (m_contact_parameters.m_normal);
00235                 point->contact (position,
00236                                           m_inertia, 
00237                                           rotate_in (velocity),
00238                                           m_contact_parameters.m_distance, 
00239                                           rotate_in (m_contact_parameters.m_normal), 
00240                                           rotate_in (ang_vel), 
00241                                           m_contact_parameters.m_material);
00242                 
00243                 translate ((m_contact_parameters.m_distance + 0.00) 
00244                                  * m_contact_parameters.m_normal);
00245                 
00246                 m_contact_parameters.m_distance = 0.0;
00247     }
00248 }
00249 
00250 void Vamos_Body::
00251 Rigid_Body::single_point_contact(Vamos_Geometry::Three_Vector worldposition,
00252                 double distance,
00253                 Vamos_Geometry::Three_Vector normal,
00254                 Vamos_Geometry::Material_Handle material, double time)
00255 {
00256         if (distance > 0.0)
00257     {
00258                 Three_Vector contactposition = transform_in(worldposition);
00259                 Three_Vector position = rotate_out (contactposition - m_body_cm);
00260                 Three_Vector velocity = m_cm_velocity + rotate_out (m_ang_velocity).
00261                         cross (position);
00262                 Three_Vector ang_vel = 
00263                         m_ang_velocity.project (normal);
00264                                 
00265                 Vamos_Geometry::Three_Vector v_perp = rotate_in (velocity.project (normal));
00266 
00267                 
00268                 
00269                 // Find the effective mass.
00270                 double meff = m_inertia.inertia (position, normal);
00271                 Three_Vector impulse = -(1.0 + (material->restitution_factor ())) * meff * v_perp;
00272                 
00273                 Vamos_Geometry::Three_Vector v_par = rotate_in (velocity) - v_perp;
00274                 impulse -= v_par.unit () * material->friction_factor () * impulse.abs ();
00275                 
00276                 /*double impmax = 1;
00277                 for (int i = 0; i < 3; i++)
00278                 {
00279                         if (impulse[i] > impmax)
00280                                 impulse[i] = impmax;
00281                         if (impulse[i] < -impmax)
00282                                 impulse[i] = -impmax;
00283                 }*/
00284                 
00285                 /*double impscale = 0.1;
00286                 for (int i = 0; i < 3; i++)
00287                         impulse[i] *= impscale;*/
00288                 
00289                 /*double maxvimpulse = 0;
00290                 if (impulse[1] > maxvimpulse)
00291                         impulse[1] = maxvimpulse;
00292                 if (impulse[1] < -maxvimpulse)
00293                         impulse[1] = -maxvimpulse;*/
00294                 
00295                 //cout << impulse[0] << "," << impulse[1] << "," << impulse[2] << endl;
00296                 
00297                 
00298                 
00299                 
00300                 translate ((distance + 0.00) 
00301                                  * normal);
00302 
00303 
00304 
00305                 // Find the force that the particle exerts on the rest of the system.
00306                 // The particle reports its force in the Body frame.
00307                 Three_Vector total_force;
00308                 Three_Vector total_torque;
00309                 
00310                 Three_Vector body_force = impulse / time;
00311                 total_force += body_force;
00312                 
00313                 // Find the force and torque that the particle exerts on the Body.
00314                 // Find the vector from the cm to the particle in the world frame.
00315                 //Three_Vector torque_dist = m_body_cm - (*it)->torque_position ();
00316                 //Three_Vector torque = (*it)->torque ();
00317                 //double I = (m_inertia * torque.unit ()).abs ();
00318                 //torque *= I / (I + m_mass * torque_dist.dot (torque_dist));
00319                 Three_Vector force_dist = m_body_cm - contactposition;
00320                 Three_Vector zero(0,0,0);
00321                 total_torque += zero - force_dist.cross (body_force);
00322                 
00323                 // Transform the forces to the parent's coordinates so we can find
00324                 // out how the Body moves w.r.t its parent.
00325                 total_force = rotate_out (total_force) + m_gravity * m_mass;
00326                 
00327                 Three_Vector delta_omega = time * total_torque * m_inertia.inverse ();
00328                 Three_Vector delta_theta = (m_ang_velocity + delta_omega) * time;
00329                 //m_last_ang_velocity = m_ang_velocity;
00330                 m_ang_velocity += delta_omega;
00331                 
00332                 Three_Vector delta_v = time * total_force / m_mass;
00333                 Three_Vector delta_r = (m_cm_velocity + delta_v) * time;
00334                 //m_last_cm_velocity = m_cm_velocity;
00335                 m_cm_velocity += delta_v;
00336                 
00337                 // Because the body's origin is not necessarily coincident with the
00338                 // center of mass, the body's translation has a component that
00339                 // depends on the orientation.  Place the Body by translating to the
00340                 // cm, rotating and then translating back.
00341                 //m_last_position = m_position;
00342                 translate (m_body_cm);
00343                 
00344                 // rotate() acts in the body frame.
00345                 //m_last_orientation = m_orientation;
00346                 rotate (delta_theta);
00347                 translate (delta_r - m_body_cm);
00348                 
00349                 // Determine the velocity of the origin.
00350                 //m_last_velocity = m_velocity;
00351                 m_velocity = (m_position - m_last_position) / time;
00352     }
00353 }
00354 
00355 // Advance the body in time by TIME.
00356 void Vamos_Body::
00357 Rigid_Body::propagate (double time)
00358 {
00359         valid = true;
00360         
00361         bool contact = false;
00362         
00363   // Re-calculate the inertia tensor and center of mass.
00364   update_center_of_mass ();
00365 
00366   //VENZON:  the stuff in propagate_contact used to be here
00367         /*if (m_contact_parameters.m_distance > 0.0)
00368     {
00369                 contact = true;
00370         }*/
00371         //propagate_contact();
00372 
00373   // Propagate the particles
00374   for (std::vector <Particle*>::iterator it = m_particles.begin ();
00375        it != m_particles.end ();
00376        it++)
00377     {
00378       (*it)->propagate (time);
00379     }
00380  
00381   // Move the body and the particles in response to forces applied to
00382   // them and their momenta, while keeping their relative positions
00383   // fixed.
00384   m_delta_time = time;
00385   Three_Vector total_force;
00386   Three_Vector total_torque;
00387 
00388   for (std::vector <Particle*>::const_iterator it = m_particles.begin ();
00389        it != m_particles.end ();
00390        it++)
00391     {
00392       // Find the force that the particle exerts on the rest of the system.
00393       // The particle reports its force in the Body frame.
00394       Three_Vector body_force = (*it)->force () + (*it)->impulse () / time;
00395                 //Three_Vector body_force = (*it)->force ();
00396       total_force += body_force;
00397 
00398       // Find the force and torque that the particle exerts on the Body.
00399       // Find the vector from the cm to the particle in the world frame.
00400       Three_Vector torque_dist = m_body_cm - (*it)->torque_position ();
00401       Three_Vector torque = (*it)->torque ();
00402       double I = (m_inertia * torque.unit ()).abs ();
00403       torque *= I / (I + m_mass * torque_dist.dot (torque_dist));
00404       Three_Vector force_dist = m_body_cm - (*it)->force_position ();
00405       total_torque += torque - force_dist.cross (body_force);
00406     }
00407 
00408   // Transform the forces to the parent's coordinates so we can find
00409   // out how the Body moves w.r.t its parent.
00410   total_force = rotate_out (total_force) + m_gravity * m_mass;
00411 
00412   Three_Vector delta_omega = time * total_torque * m_inertia.inverse ();
00413   Three_Vector delta_theta = (m_ang_velocity + delta_omega) * time;
00414   if (!contact) 
00415           m_last_ang_velocity = m_ang_velocity;
00416   m_ang_velocity += delta_omega;
00417 
00418   Three_Vector delta_v = time * total_force / m_mass;
00419   Three_Vector delta_r = (m_cm_velocity + delta_v) * time;
00420   if (!contact) 
00421           m_last_cm_velocity = m_cm_velocity;
00422   m_cm_velocity += delta_v;
00423 
00424   // Because the body's origin is not necessarily coincident with the
00425   // center of mass, the body's translation has a component that
00426   // depends on the orientation.  Place the Body by translating to the
00427   // cm, rotating and then translating back.
00428   if (!contact)
00429           m_last_position = m_position;
00430   translate (m_body_cm);
00431 
00432   // rotate() acts in the body frame.
00433   if (!contact)
00434           m_last_orientation = m_orientation;
00435   rotate (delta_theta);
00436   translate (delta_r - m_body_cm);
00437 
00438   // Determine the velocity of the origin.
00439   if (!contact) 
00440           m_last_velocity = m_velocity;
00441   m_velocity = (m_position - m_last_position) / time;
00442 }
00443 
00444 // Undo the last propagation.
00445 void Vamos_Body::
00446 Rigid_Body::rewind ()
00447 {
00448   m_position = m_last_position;
00449   m_velocity = m_last_velocity;
00450   m_cm_velocity = m_last_cm_velocity;
00451 
00452   m_orientation = m_last_orientation;
00453   m_ang_velocity = m_last_ang_velocity;
00454 }
00455 
00456 // Finish the timestep.
00457 void Vamos_Body::
00458 Rigid_Body::end_timestep ()
00459 {
00460   for (std::vector <Particle*>::iterator it = m_particles.begin ();
00461        it != m_particles.end ();
00462        it++)
00463     {
00464       (*it)->end_timestep ();
00465     }
00466 }
00467 
00468 // Return the velocity of the particle in the parent frame.
00469 Three_Vector Vamos_Body::
00470 Rigid_Body::velocity (Particle* particle)
00471 {
00472   Three_Vector r_vec = particle->position ();
00473   return m_cm_velocity + rotate_out (m_ang_velocity).
00474     cross (rotate_out (r_vec - m_body_cm));
00475 }
00476 
00477 // Handle a collision.
00478 void Vamos_Body::
00479 Rigid_Body::contact (Particle* contact_point, 
00480                double distance,
00481                const Three_Vector& normal,
00482                const Vamos_Geometry::Material_Handle material)
00483 {
00484   if (contact_point->single_contact ())
00485     {
00486       if (distance > m_contact_parameters.m_distance)
00487         {
00488           m_contact_parameters.mp_contact_point = contact_point;
00489           m_contact_parameters.m_distance = distance;
00490           m_contact_parameters.m_normal = normal;
00491           m_contact_parameters.m_material = material;
00492         }
00493     }
00494   else
00495     {
00496       Three_Vector position = 
00497         rotate_out (contact_point->contact_position () - m_body_cm);
00498       Three_Vector ang_vel = m_ang_velocity.project (normal);
00499       Three_Vector velocity = m_cm_velocity + rotate_out (m_ang_velocity).
00500         cross (rotate_out (contact_point->position () - m_body_cm));
00501       contact_point->contact (position,
00502                               m_inertia,
00503                               rotate_in (velocity),
00504                               distance,
00505                               rotate_in (normal),
00506                               rotate_in (ang_vel),
00507                               material);
00508     }
00509 }
00510 
00511 // Transform the wind into the body frame and send it to the INDEXth
00512 // particle which must be an Aerodynamic_Device.
00513 void Vamos_Body::
00514 Rigid_Body::wind (Particle* aero_device, 
00515                   const Three_Vector& wind_vector, 
00516                   double density)
00517 {
00518   aero_device->wind (rotate_in (wind_vector), density);
00519 }
00520 
00521 // Return the body to its initial state at its initial position.
00522 void Vamos_Body::
00523 Rigid_Body::reset ()
00524 {
00525   m_position = m_initial_position;
00526   m_orientation.identity ();
00527 
00528   private_reset ();
00529 }
00530 
00531 // Return the body to its initial state at a particular position and
00532 // orientation.
00533 void Vamos_Body::
00534 Rigid_Body::reset (const Three_Vector& position, 
00535                    const Three_Matrix& orientation)
00536 {
00537   m_position = position;
00538   m_orientation = orientation;
00539 
00540   private_reset ();
00541 }
00542 
00543 // Common code for the two reset () methods.
00544 void Vamos_Body::
00545 Rigid_Body::private_reset ()
00546 {
00547   m_velocity.zero ();
00548   m_cm_velocity.zero ();
00549   m_ang_velocity.zero ();
00550 
00551   for (std::vector <Particle*>::iterator it = m_particles.begin ();
00552        it != m_particles.end ();
00553        it++)
00554     {
00555       (*it)->reset ();
00556     }
00557 }

Generated on Thu Oct 19 04:05:55 2006 by  doxygen 1.4.6