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

subspace.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 "rigidobject.h"
00024 #include "subspace.h"
00025 #include "world.h"
00026 
00027 using namespace sheep;
00028 
00029 //#define DEBUG_INFO
00030 /*
00031 void Subspace::Step(Real start_time, Real end_time) {
00032     assert(end_time - start_time > EPSILON);
00033 
00034     m_cd.RefreshTransformations();
00035 
00036     while(true) {
00037         if(end_time - start_time <= EPSILON)
00038             break;
00039 
00040         Real step_end = compute_step_end(start_time, end_time);
00041 
00042         assert(step_end <= end_time);
00043         assert(step_end - start_time > EPSILON);
00044 
00045 #ifdef DEBUG_INFO
00046         *m_debug << "Step by " << step_end - start_time << br;
00047 #endif  // DEBUG_INFO
00048 
00049         step_bodies(start_time, step_end - start_time);
00050 
00051         start_time = step_end;
00052 
00053         for(rigidobject_list::iterator i = m_objects.begin(); i != m_objects.end(); i++) {
00054             RigidBody *body = (*i)->GetBody();
00055 
00056             body->ZeroForce();
00057             body->ZeroTorque();
00058             body->ApplyForce(Vector3(0,-9.8,0));        //!\todo This is a quick hack
00059         }
00060 
00061         m_jm.ApplyContraints();
00062         m_jm.ApplyCorrections();
00063 
00064         ContactList contacts;
00065 
00066         compute_contacts(&contacts);
00067 
00068         for(ContactList::iterator i = contacts.begin(); i != contacts.end(); i++) {
00069 #ifdef DEBUG_INFO
00070 //          print_contact(*i);
00071 #endif  // DEBUG_INFO
00072 
00073             m_ch.Insert(*i);
00074         }
00075 
00076 #ifdef DEBUG_INFO
00077         *m_debug << "Resting contacts so far: "
00078             << m_ch.GetRestingContactTracker()->GetRestingContacts().size() << br;
00079 #endif  // DEBUG_INFO
00080 
00081         m_ch.ResolveAll();
00082     }
00083 }
00084 */
00085 void Subspace::Step(Real start_time, Real end_time) {
00086     const Real EPSILON = 1e-6;
00087 
00088     //!\todo Is this really necessary?
00089     assert(end_time - start_time > EPSILON);
00090 
00091     m_cd.RefreshTransformations();
00092 
00093     while(end_time - start_time > EPSILON) {
00094         find_contacts();
00095 
00096 #ifdef DEBUG_INFO
00097         *m_debug << "Resting contacts so far: "
00098             << m_ch.GetRestingContactTracker()->GetRestingContacts().size() << br;
00099 #endif  // DEBUG_INFO
00100 
00101         for(rigidobject_list::iterator i = m_objects.begin(); i != m_objects.end(); i++) {
00102             RigidBody *body = (*i)->GetBody();
00103 
00104             body->ZeroForce();
00105             body->ZeroTorque();
00106 
00107             //!\todo This is a quick hack.
00108 
00109             // Gravity.
00110             body->ApplyForce(Vector3(0, -9.8, 0));
00111 
00112             // Damping.
00113             body->ApplyForce(-0.2 * body->GetLinearVelocity());
00114             body->ApplyTorque(-0.2 * body->GetAngularVelocity());
00115         }
00116 
00117         //!\todo I guess joints and resting contacts should be resolved
00118         //! together at the same time, which is obviously not the case at
00119         //! the moment. I believe that making resting contacts unilateral
00120         //! constraints (thus a particular type of joint) will help to
00121         //! achieve simultaneous resolution of resting contacts and joints.
00122 
00123         m_jm.ApplyContraints();
00124         m_ch.ResolveAll();
00125 
00126         Real step_end = compute_step_end(start_time, end_time);
00127 
00128         assert(step_end <= end_time);
00129         assert(step_end - start_time > EPSILON);
00130 
00131 #ifdef DEBUG_INFO
00132         *m_debug << "Step by " << step_end - start_time << br;
00133 #endif  // DEBUG_INFO
00134 
00135         step_bodies(start_time, step_end - start_time);
00136 
00137         start_time = step_end;
00138     }
00139 }
00140 
00141 void Subspace::save_state(state_snapshot *s) {
00142     assert(s);
00143 
00144     s->m_states = new RigidBody::StateVector[m_objects.size()];
00145 
00146     RigidBody::StateVector *p = s->m_states;
00147 
00148     for(rigidobject_list::iterator i = m_objects.begin(); i != m_objects.end(); i++) {
00149         *p++ = (*i)->GetBody()->GetState();
00150     }
00151 }
00152 
00153 void Subspace::restore_state(const state_snapshot &s) {
00154     RigidBody::StateVector *p = s.m_states;
00155 
00156     for(rigidobject_list::iterator i = m_objects.begin(); i != m_objects.end(); i++) {
00157         (*i)->GetBody()->SetState(*p++);
00158     }
00159 
00160     m_cd.RefreshTransformations();
00161 }
00162 
00163 void Subspace::find_contacts() {
00164 #ifdef DEBUG_INFO
00165     *m_debug << "Let's now compute contacts:" << br;
00166 #endif  // DEBUG_INFO
00167 
00168     ContactList contacts;
00169 
00170     m_cd.FindContacts(&contacts);
00171 
00172     for(ContactList::iterator i = contacts.begin(); i != contacts.end(); i++) {
00173         Contact &c = *i;
00174 
00175         if((c.m_fa.m_type == Feature::Type::FACE && c.m_fb.m_type == Feature::Type::VERTEX) ||
00176            (c.m_fa.m_type == Feature::Type::EDGE && c.m_fb.m_type == Feature::Type::VERTEX)) {
00177             std::swap(c.m_a, c.m_b);
00178             std::swap(c.m_fa, c.m_fb);
00179         }
00180 
00181         c.Update();
00182 
00183         if(c.GetType() == Contact::Type::SEPARATING_CONTACT) {
00184 #ifdef DEBUG_INFO
00185             *m_debug << "It is a separating contact. Skipping it." << br;
00186 #endif  // DEBUG_INFO
00187             continue;
00188         }
00189 
00190         if(c.GetType() == Contact::Type::RESTING_CONTACT) {
00191             const ContactVector &rc = m_ch.GetRCTracker().GetRestingContacts();
00192             bool known_rc = false;
00193 
00194             for(ContactVector::const_iterator i = rc.begin(); i != rc.end(); i++) {
00195                 if(c == *i) {
00196                     known_rc = true;
00197                     break;
00198                 }
00199             }
00200 
00201             if(known_rc) {
00202 #ifdef DEBUG_INFO
00203                 *m_debug << "It is an already known resting contact. Skipping it." << br;
00204 #endif  // DEBUG_INFO
00205                 continue;
00206             }
00207         }
00208 
00209 #ifdef DEBUG_INFO
00210         *m_debug << "Adding the following contact to the contact list:" << br;
00211         print_contact(c);
00212 #endif  // DEBUG_INFO
00213 
00214         m_ch.Insert(c);
00215     }
00216 }
00217 
00218 Real Subspace::compute_step_end(Real start_time, Real end_time) {
00219     //!\todo Much work can be done here to speed things up, like
00220     //! time-of-intersection prediction, and so on...
00221 
00222     const Real EPSILON = 1e-6;
00223 
00224     assert(end_time - start_time > EPSILON);
00225     assert(m_cd.AreObjectsDisjoint());
00226 
00227     state_snapshot orig_state;
00228     save_state(&orig_state);
00229 
00230     Real step_end = start_time;
00231     Real step = end_time - start_time;
00232 
00233     while(true) {
00234         assert(end_time - step_end >= 0);
00235 
00236         if(end_time - step_end < EPSILON) {
00237 #ifdef DEBUG_INFO
00238             *m_debug << "Maximum step reached." << br;
00239 #endif  // DEBUG_INFO
00240             break;
00241         }
00242 
00243         assert(m_cd.AreObjectsDisjoint());
00244 
00245         state_snapshot last_state;
00246         save_state(&last_state);
00247 
00248         assert(step > EPSILON);
00249 
00250         step_bodies(step_end, step);
00251 
00252         if(!m_cd.AreObjectsDisjoint()) {
00253             restore_state(last_state);
00254 
00255             step /= 2;
00256 
00257             if(step <= EPSILON) {
00258 #ifdef DEBUG_INFO
00259                 *m_debug << "Giving up time bisection." << br;
00260                 *m_debug << "Hint: one or several objects may be moving too fast." << br;
00261 #endif  // DEBUG_INFO
00262                 break;
00263             }
00264         } else {
00265             step_end += step;
00266 
00267             if(!m_cd.AreObjectHullsDisjoint()) {
00268 #ifdef DEBUG_INFO
00269                 *m_debug << "Interference detected." << br;
00270 #endif  // DEBUG_INFO
00271                 break;
00272             }
00273         }
00274     }
00275 
00276     restore_state(orig_state);
00277 
00278     assert(m_cd.AreObjectsDisjoint());
00279 
00280     assert(step_end <= end_time);
00281     assert(step_end - start_time > EPSILON);
00282 
00283     return step_end;
00284 }
00285 
00286 void Subspace::step_bodies(Real time, Real step) {
00287     const Real EPSILON = 1e-6;
00288 
00289     //!\todo Is this really necessary?
00290     assert(step > EPSILON);
00291 
00292     for(rigidobject_list::iterator i = m_objects.begin(); i != m_objects.end(); i++) {
00293         RigidBody *body = (*i)->GetBody();
00294 
00295         if(body->IsFrozen())
00296             continue;
00297 
00298         body->EvolveOneStep(m_solver, time, step);
00299     }
00300 
00301     m_cd.RefreshTransformations();
00302 }

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