Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

rctracker.cpp

Go to the documentation of this file.
00001 /*
00002     Sheep - A Rigid Body Dynamics Engine
00003     Copyright (C) 2001-2004 Francois Beaune
00004     Contact: http://toxicengine.sourceforge.net/
00005 
00006     This file is part of Sheep.
00007 
00008     Sheep is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     Sheep is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with Sheep; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00023 #include "engine/geometry/icollisiondetector.h"     // sheep::HUCK_THICKNESS
00024 #include "engine/simulation/rigidobject.h"
00025 #include "rctracker.h"
00026 #include "rigidbody.h"
00027 
00028 #include <cmath>        // for fabs()
00029 #include <limits>
00030 
00031 using namespace sheep;
00032 
00033 const Real HULL_THICKNESS = 0.05 / 2.0;     // duplicated because of lazyness
00034 
00035 Matrix RCTracker::compute_A_matrix() {
00036     Matrix A(m_resting_contacts.size(), m_resting_contacts.size());
00037 
00038     for(int i=0; i<m_resting_contacts.size(); i++)      // rows
00039         for(int j=0; j<m_resting_contacts.size(); j++) {    // columns
00040             Contact ci = m_resting_contacts[i];
00041             Contact cj = m_resting_contacts[j];
00042 
00043             RigidBody *a = ci.m_a->GetBody();
00044             RigidBody *b = ci.m_b->GetBody();
00045 
00046             // If the bodies involved in the ith and jth contacts
00047             // are distinct, then a[i,j] is zero.
00048             if((ci.m_a!=cj.m_a)&&(ci.m_b!=cj.m_b)&&
00049                 (ci.m_a!=cj.m_b)&&(ci.m_b!=cj.m_a)) {
00050                 A(i,j) = 0;
00051                 continue;
00052             }
00053 
00054             Vector3 ria = ci.m_a->GetBody()->TransformVectorToWorld(ci.m_pa);
00055             Vector3 rib = ci.m_b->GetBody()->TransformVectorToWorld(ci.m_pb);
00056             Vector3 rja = cj.m_a->GetBody()->TransformVectorToWorld(cj.m_pa);
00057             Vector3 rjb = cj.m_b->GetBody()->TransformVectorToWorld(cj.m_pb);
00058 
00059             // Compute force and torque the jth contact exerts on body A.
00060 
00061             Vector3 force_on_a = 0, torque_on_a = 0;
00062 
00063             if(cj.m_a==ci.m_a) {
00064                 force_on_a = cj.m_n;
00065                 torque_on_a = rja ^ cj.m_n;
00066             }
00067             else if(cj.m_b==ci.m_a) {
00068                 force_on_a = - cj.m_n;
00069                 torque_on_a = rja ^ cj.m_n;
00070             }
00071 
00072             // Compute force and torque the jth contact exerts on body B.
00073 
00074             Vector3 force_on_b = 0, torque_on_b = 0;
00075 
00076             if(cj.m_a==ci.m_b) {
00077                 force_on_b = cj.m_n;
00078                 torque_on_b = rjb ^ cj.m_n;
00079             }
00080             else if(cj.m_b==ci.m_b) {
00081                 force_on_b = - cj.m_n;
00082                 torque_on_b = rjb ^ cj.m_n;
00083             }
00084 
00085             // Now compute how the jth contact force affects the linear
00086             // and angular accelerations of the contact point on each body.
00087 
00088             Vector3 a_part = a->IsFrozen() ? 0 : force_on_a / a->GetMass() +
00089                 ((a->GetWorldInertiaTensor().Inverse() * torque_on_a) ^ ria);
00090             
00091             Vector3 b_part = b->IsFrozen() ? 0 : force_on_b / b->GetMass() +
00092                 ((b->GetWorldInertiaTensor().Inverse() * torque_on_b) ^ rib);
00093 
00094             A(i,j) = ci.m_n * (a_part - b_part);
00095         }
00096 
00097     return A;
00098 }
00099 
00100 Vector RCTracker::compute_b_vector() {
00101     Vector bv(m_resting_contacts.size());
00102 
00103     for(int i=0; i<m_resting_contacts.size(); i++) {
00104         Contact c = m_resting_contacts[i];
00105 
00106         RigidBody *a = c.m_a->GetBody();
00107         RigidBody *b = c.m_b->GetBody();
00108 
00109         Vector3 ra = a->TransformVectorToWorld(c.m_pa);
00110         Vector3 rb = b->TransformVectorToWorld(c.m_pb);
00111 
00112         // Compute the part of padotdot(t0) due to the external
00113         // force and torque, and similarly for pbdotdot(t0).
00114 
00115         Vector3 a_ext_part = a->IsFrozen() ? 0 : a->GetTotalForce() / a->GetMass() +
00116             ((a->GetWorldInertiaTensor().Inverse() * a->GetTotalTorque()) ^ ra);
00117 
00118         Vector3 b_ext_part = b->IsFrozen() ? 0 : b->GetTotalForce() / b->GetMass() +
00119             ((b->GetWorldInertiaTensor().Inverse() * b->GetTotalTorque()) ^ rb);
00120 
00121         // Compute the part of padotdot(t0) due to velocity, and
00122         // similarly for pbdotdot(t0).
00123 
00124         Vector3 a_vel_part = 0, b_vel_part = 0;
00125 
00126         if(!a->IsFrozen()) {
00127             Vector3 a_L = a->GetWorldInertiaTensor() * a->GetAngularVelocity();
00128             a_vel_part = (a->GetAngularVelocity() ^ (a->GetAngularVelocity() ^ ra)) +
00129                 ((a->GetWorldInertiaTensor().Inverse() * (a_L ^ a->GetAngularVelocity())) ^ ra);
00130         }
00131 
00132         if(!b->IsFrozen()) {
00133             Vector3 b_L = b->GetWorldInertiaTensor() * b->GetAngularVelocity();
00134             b_vel_part = (b->GetAngularVelocity() ^ (b->GetAngularVelocity() ^ rb)) +
00135                 ((b->GetWorldInertiaTensor().Inverse() * (b_L ^ b->GetAngularVelocity())) ^ rb);
00136         }
00137 
00138         // Combine the above results, and dot with the contact normal.
00139 
00140         Real k1 = c.m_n * ((a_ext_part + a_vel_part) - (b_ext_part + b_vel_part));
00141         Real k2 = 2 * c.GetNormalDerivative() * (c.m_va - c.m_vb);
00142 
00143         bv[i] = k1 + k2;
00144     }
00145 
00146     return bv;
00147 }
00148 
00149 Vector RCTracker::fdirection(const Matrix &A, int d) {
00150     Vector delta_f(m_resting_contacts.size(), 0);
00151 
00152     delta_f[d] = 1;
00153 
00154     if(C.size()<1)
00155         return delta_f;
00156 
00157     int i, j, k;
00158 
00159     // Compute A11.
00160 
00161     Matrix A11(C.size(), C.size());
00162 
00163     k = 0;      // linear index in A11 (which is row-major)
00164 
00165     for(i=0; i<m_resting_contacts.size(); i++) {    // rows
00166         if(!C.Contains(i))
00167             continue;       // skip this row
00168 
00169         for(j=0; j<m_resting_contacts.size(); j++) {    // columns
00170             if(C.Contains(j))
00171                 A11[k++] = A(i,j);
00172         }
00173     }
00174 
00175     assert(k==C.size()*C.size());
00176 
00177     // Compute v1.
00178 
00179     Vector v1(C.size());
00180 
00181     k = 0;      // index in v1
00182 
00183     for(i=0; i<m_resting_contacts.size(); i++) {
00184         if(C.Contains(i))
00185             v1[k++] = A(i,d);
00186     }
00187 
00188     assert(k==C.size());
00189 
00190 //  *debug << "A11:" << A11 << std::endl;
00191 
00192     Vector x = - A11.Inverse() * v1;
00193 
00194     // Transfer x into delta_f.
00195 
00196     k = 0;      // index in x
00197 
00198     for(i=0; i<m_resting_contacts.size(); i++) {
00199         if(C.Contains(i))
00200             delta_f[i] = x[k++];
00201     }
00202 
00203     return delta_f;
00204 }
00205 
00206 // Output to s and j.
00207 void RCTracker::maxstep(const Vector &a,
00208                         const Vector &f,
00209                         const Vector &delta_a,
00210                         const Vector &delta_f,
00211                         int d, Real *s, int *j) {
00212     *s = std::numeric_limits<Real>::max();      // fake infinity
00213     *j = -1;
00214 
00215     if(delta_a[d]>0) {
00216         //!\todo Resolve properly the case where delta_a[d] is very small (1e-16).
00217         //! Solution: do not add a resting contact if it does not accelerate toward
00218         //! its neighbor more than EPSILON (along the contact normal).
00219 
00220 //      assert(fabs(delta_a[d])>EPSILON);
00221 
00222         *s = - a[d] / delta_a[d];
00223         *j = d;
00224     }
00225 
00226     index_set::iterator i;
00227 
00228     for(i=C.begin(); i!=C.end(); i++)
00229         if(delta_f[*i]<0) {
00230             assert(fnz(delta_f[*i]));
00231 
00232             Real s1 = -f[*i] / delta_f[*i];
00233 
00234             if(s1 < *s) {
00235                 *s = s1;
00236                 *j = *i;
00237             }
00238         }
00239 
00240     for(i=NC.begin(); i!=NC.end(); i++)
00241         if(delta_a[*i]<0) {
00242             assert(fnz(delta_a[*i]));
00243 
00244             Real s1 = -a[*i] / delta_a[*i];
00245 
00246             if(s1 < *s) {
00247                 *s = s1;
00248                 *j = *i;
00249             }
00250         }
00251 }
00252 
00253 void RCTracker::drive_to_zero(const Matrix &A, Vector &f, Vector &a, int d) {
00254 L1:
00255 //  *debug << "At that point, we have C = {";
00256 
00257 //  index_set::const_iterator i;
00258 
00259 //  for(i=C.begin(); i!=C.end(); i++)
00260 //      *debug << ' ' << *i;
00261 
00262 //  *debug << " } and NC = {";
00263 
00264 //  for(i=NC.begin(); i!=NC.end(); i++)
00265 //      *debug << ' ' << *i;
00266 
00267 //  *debug << " }." << br << std::endl;
00268 
00269     Vector delta_f = fdirection(A, d);
00270     Vector delta_a = A * delta_f;
00271 
00272     Real s;
00273     int j;
00274 
00275     maxstep(a, f, delta_a, delta_f, d, &s, &j);     // output to s and j
00276 
00277     assert(j!=-1);      // make sure that max_step < infinity
00278 
00279     f += s * delta_f;
00280     a += s * delta_a;
00281 
00282     if(C.Contains(j)) {
00283 //      *debug << "Moving " << j << " from C to NC." << br << std::endl;
00284         C.remove(j);
00285         NC.push_back(j);
00286         goto L1;
00287     }
00288     else if(NC.Contains(j)) {
00289 //      *debug << "Moving " << j << " from NC to C." << br << std::endl;
00290         NC.remove(j);
00291         C.push_back(j);
00292         goto L1;
00293     }
00294     else {      // j must be d, implying a[d] = 0
00295 //      *debug << "Pushing " << j << " to C." << br << std::endl;
00296         C.push_back(j);
00297     }
00298 }
00299 
00300 Vector RCTracker::compute_forces(const Matrix &A, const Vector &b) {
00301     Vector f(m_resting_contacts.size(), 0);
00302 
00303     Vector a = b;
00304 
00305     C.clear();
00306     NC.clear();
00307 
00308 //  *debug << "<p>Starting with C = {";
00309 
00310 //  index_set::const_iterator i;
00311 
00312 //  for(i=C.begin(); i!=C.end(); i++)
00313 //      *debug << ' ' << *i;
00314 
00315 //  *debug << " } and NC = {";
00316 
00317 //  for(i=NC.begin(); i!=NC.end(); i++)
00318 //      *debug << ' ' << *i;
00319 
00320 //  *debug << " }." << br << std::endl;
00321 
00322     int d = 0;
00323 
00324     const Real EPSILON = 1e-6;
00325 
00326     while(d<a.GetDimension()) {
00327         if(a[d] < -EPSILON) {
00328 //          Real temp = a[d];
00329             drive_to_zero(A, f, a, d);
00330 //          *debug << "Drove a[" << d << "] from " << temp << " to " << a[d] << "." << br << std::endl;
00331             d = 0;
00332         }
00333         else d++;
00334     }
00335 
00336 //  *debug << "Ending with C = {";
00337 
00338 //  for(i=C.begin(); i!=C.end(); i++)
00339 //      *debug << ' ' << *i;
00340 
00341 //  *debug << " } and NC = {";
00342 
00343 //  for(i=NC.begin(); i!=NC.end(); i++)
00344 //      *debug << ' ' << *i;
00345 
00346 //  *debug << " }.</p>" << std::endl;
00347 
00348     return f;
00349 }
00350 
00351 bool RCTracker::is_inactivated_rc::operator()(Contact &c) const {
00352     c.Update();
00353 
00354 //  *debug << "is_inactivated_rc: " << c.m_inactivated << ", " << (c.m_pa - c.m_pb).Norm() << br;
00355 
00356 //  if(c.m_inactivated) {
00357 //      std::cerr << "- " << c.m_fa << "-" << c.m_fb << std::endl;
00358 //  }
00359 
00360     return c.m_inactivated /*|| (c.m_pa - c.m_pb).Norm() > HULL_THICKNESS -- warning: HULL_THICKNESS definition changed! */;
00361 }
00362 
00363 void RCTracker::remove_inactivated_rc() {
00364     m_resting_contacts.erase(
00365         std::remove_if(m_resting_contacts.begin(), m_resting_contacts.end(), is_inactivated_rc()),
00366         m_resting_contacts.end());
00367 }
00368 
00369 void RCTracker::ResolveAll() {
00370     // Remove inactivated resting contacts.
00371     remove_inactivated_rc();
00372 
00373     if(m_resting_contacts.size()==0)
00374         return;
00375 
00376     // Compute and apply contact forces that keep the contact
00377     // points from accelerating toward each other.
00378 
00379     Vector f = compute_forces(compute_A_matrix(), compute_b_vector());
00380 
00381 //  *debug << "Acceleration before:" << compute_b_vector();
00382 
00383     Vector v(m_resting_contacts.size());
00384     int i;
00385 
00386     for(i=0; i<m_resting_contacts.size(); i++) {
00387         Contact c = m_resting_contacts[i];
00388         c.Update();
00389         v[i] = c.m_n * (c.m_va - c.m_vb);
00390     }
00391 
00392 //  *debug << "Normal velocity before: " << v;
00393 
00394     // Apply the contact forces to resting bodies.
00395     for(i=0; i<m_resting_contacts.size(); i++) {
00396 //      *debug << "Handling resting contact #" << i << ":" << br;
00397 
00398         Contact c = m_resting_contacts[i];
00399 
00400         RigidBody *a = c.m_a->GetBody();
00401         RigidBody *b = c.m_b->GetBody();
00402 
00403 //      *debug << "  Applying force +/-" << f[i] * c.m_n;
00404 
00405         a->ApplyForce(f[i] * c.m_n, c.m_pa);
00406         b->ApplyForce(-f[i] * c.m_n, c.m_pb);
00407     }
00408 
00409 //  *debug << "Acceleration after:" << compute_b_vector();
00410 
00411     for(i=0; i<m_resting_contacts.size(); i++) {
00412         Contact c = m_resting_contacts[i];
00413         c.Update();
00414         c.CancelNormalVelocity();
00415         v[i] = c.m_n * (c.m_va - c.m_vb);
00416     }
00417 
00418 //  *debug << "Normal velocity after: " << v;
00419 }

Generated on Tue May 11 01:31:51 2004 for toxic by doxygen 1.3.6