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

physics/ODESolidSystem.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)1996 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: ODESolidSystem.cpp 1031 2004-02-11 20:46:36Z jungd $
00019   $Revision: 1.18 $
00020   $Date: 2004-02-11 15:46:36 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022   
00023 ****************************************************************************/
00024 
00025 #include <physics/CollisionState>
00026 
00027 #include <physics/ODESolidSystem>
00028 #include <physics/ODECollisionCuller>
00029 #include <physics/ODECollisionDetector>
00030 #include <physics/SolidCollisionResponseHandler>
00031 #include <physics/NullCollisionResponseHandler>
00032 #include <physics/ODECollidableGroup>
00033 #include <physics/ODESolid>
00034 #include <physics/ODESolidConnectedCollidableBody>
00035 
00036 #include <physics/ODEConstraintGroup>
00037 #include <physics/ODEFixedConstraint>
00038 #include <physics/ODEContactConstraint>
00039 #include <physics/ODEBallJoint>
00040 #include <physics/ODEHingeJoint>
00041 #include <physics/ODEDoubleHingeJoint>
00042 #include <physics/ODESliderJoint>
00043 #include <physics/ODEUniversalJoint>
00044 
00045 #include <physics/ODEMotor>
00046 
00047 using physics::ODESolidSystem;
00048 
00049 
00050 using physics::Collider;
00051 using physics::CollisionCuller;
00052 using physics::CollisionDetector;
00053 using physics::ODECollisionDetector;
00054 using physics::Collidable;
00055 using physics::CollidableGroup;
00056 using physics::ODECollidableGroup;
00057 using physics::ODECollisionCuller;
00058 using physics::Solid;
00059 using physics::ODESolid;
00060 using physics::ODESolidConnectedCollidableBody;
00061 using physics::ConstraintGroup;
00062 using physics::ODEConstraintGroup;
00063 using physics::CollisionResponseHandler;
00064 using physics::SolidCollisionResponseHandler;
00065 
00066 using physics::FixedConstraint;
00067 using physics::ContactConstraint;
00068 using physics::BallJoint;
00069 using physics::HingeJoint;
00070 using physics::DoubleHingeJoint;
00071 using physics::SliderJoint;
00072 using physics::UniversalJoint;
00073 using physics::Motor;
00074 
00075 using physics::ODEFixedConstraint;
00076 using physics::ODEBallJoint;
00077 using physics::ODEHingeJoint;
00078 using physics::ODEDoubleHingeJoint;
00079 using physics::ODESliderJoint;
00080 using physics::ODEUniversalJoint;
00081 using physics::ODEMotor;
00082 
00083 
00084 
00085 ODESolidSystem::ODESolidSystem()
00086   : active(true), preSimulateCalled(false)
00087 {
00088   worldID = dWorldCreate();
00089   
00090   collisionCuller = ref<CollisionCuller>(NewObj ODECollisionCuller());
00091   collisionDetector = ref<CollisionDetector>(NewObj ODECollisionDetector());
00092   collisionHandler = ref<CollisionResponseHandler>(NewObj SolidCollisionResponseHandler(ref<SolidSystem>(this), collisionDetector)); //!!!cyclic ref!
00093   
00094   collisionCuller->addPotentialCollisionListener(collisionDetector);
00095   collisionDetector->addPotentialCollisionListener(ref<ODESolidSystem>(this));
00096 
00097 }
00098 
00099 ODESolidSystem::ODESolidSystem(const ODESolidSystem& ss)
00100   : SolidSystem(ss), active(ss.active), preSimulateCalled(false)
00101 {
00102   Unimplemented;
00103 }
00104 
00105 
00106 ODESolidSystem::~ODESolidSystem()
00107 {
00108   // release the ConstraintGroups first
00109   //  (so that the Constraints may be destroyed before the world)
00110   ConstraintGroups::iterator g = constraintGroups.begin();
00111   ConstraintGroups::iterator end = constraintGroups.end();
00112   while (g != end) {
00113     (*g)->clear();
00114     ++g;
00115   }
00116   constraintGroups.clear();
00117 
00118   setGround(ref<Solid>(0),Point3());
00119 
00120   solids.clear();
00121 
00122   collisionCuller = ref<CollisionCuller>(0);
00123   collisionDetector = ref<CollisionDetector>(0);
00124   collisionHandler = ref<CollisionResponseHandler>(0);
00125 
00126   dWorldDestroy(worldID);
00127 }
00128 
00129 
00130 
00131 
00132 // factories
00133 
00134 ref<Solid> ODESolidSystem::createSolid(ref<const Shape> shape, ref<const Material> material)  
00135 {
00136   return ref<Solid>(NewNamedObj("ODESolid") ODESolid(shape, material));
00137 }
00138 
00139 
00140 ref<ConstraintGroup> ODESolidSystem::createConstraintGroup()
00141 {
00142   return ref<ConstraintGroup>(NewNamedObj("ODEConstraintGroup") ODEConstraintGroup(worldID));
00143 }
00144 
00145 
00146 ref<BallJoint> ODESolidSystem::createBallJoint()
00147 {
00148   return ref<BallJoint>(NewNamedObj("ODEBallJoint") ODEBallJoint());
00149 }
00150 
00151 ref<HingeJoint> ODESolidSystem::createHingeJoint()
00152 {
00153   return ref<HingeJoint>(NewNamedObj("ODEHingeJoint") ODEHingeJoint());
00154 }
00155 
00156 ref<DoubleHingeJoint> ODESolidSystem::createDoubleHingeJoint()
00157 {
00158   return ref<DoubleHingeJoint>(NewNamedObj("ODEDoubleHingeJoint") ODEDoubleHingeJoint());
00159 }
00160 
00161 ref<SliderJoint> ODESolidSystem::createSliderJoint()
00162 {
00163   return ref<SliderJoint>(NewNamedObj("ODESliderJoint") ODESliderJoint());
00164 }
00165 
00166 ref<UniversalJoint> ODESolidSystem::createUniversalJoint()
00167 {
00168   return ref<UniversalJoint>(NewNamedObj("ODEUniversalJoint") ODEUniversalJoint());
00169 }
00170 
00171 
00172 ref<FixedConstraint> ODESolidSystem::createFixedConstraint()
00173 {
00174   return ref<FixedConstraint>(NewNamedObj("ODEFixedConstraint") ODEFixedConstraint());
00175 }
00176 
00177 ref<ContactConstraint> ODESolidSystem::createContactConstraint()
00178 {
00179   return ref<ContactConstraint>(NewNamedObj("ODEContactConstraint") ODEContactConstraint());
00180 }
00181 
00182 
00183 ref<Motor> ODESolidSystem::createMotor()
00184 {
00185   return ref<ODEMotor>(NewNamedObj("ODEMotor") ODEMotor());
00186 }
00187 
00188 
00189 void ODESolidSystem::setGround(ref<Solid> ground, const Point3& position)
00190 {
00191   if (this->ground) {
00192     dJointDestroy(groundJoint);
00193     ref<Solid> cground = this->ground;
00194     this->ground = ref<Solid>(0);
00195     removeSolid(cground);
00196   }
00197 
00198   if (ground) {
00199     addSolid(ground);
00200     this->ground = ground;
00201     ground->setPosition(position);
00202     groundJoint = dJointCreateFixed(worldID,0);
00203     ref<ODESolid> osolid = narrow_ref<ODESolid>(ground);
00204     dJointAttach(groundJoint, osolid->bodyID, 0);
00205     dJointSetFixed(groundJoint);
00206   }
00207   
00208 }
00209 
00210 
00211 ref<Solid> ODESolidSystem::getGround() const
00212 {
00213   return ground;
00214 }
00215 
00216 
00217 void ODESolidSystem::setGravity(const Vector3& v)
00218 {
00219   dWorldSetGravity(worldID, v.x, v.y, v.z);
00220 }
00221 
00222 
00223 void ODESolidSystem::addSolid(ref<Solid> solid)
00224 {
00225  if ((!solid) || (solid && (solid == ground)))
00226    throw std::invalid_argument(Exception("solid must be non-null (and cannot be the ground Solid)"));
00227 
00228   ref<ODESolid> osolid = narrow_ref<ODESolid>(solid);
00229   osolid->create(worldID);
00230   solids.push_back(solid);
00231 
00232   updateVisual();
00233 }
00234 
00235 
00236 void ODESolidSystem::removeSolid(ref<const Solid> solid)
00237 {
00238  if ((!solid) || (solid && (solid == ground)))
00239    throw std::invalid_argument(Exception("solid must be non-null (and cannot be the ground Solid)"));
00240 
00241   ref<const ODESolid> osolid = narrow_ref<const ODESolid>(solid);
00242   if (osolid->worldID != worldID)
00243     throw std::invalid_argument(Exception("Solid doesn't belong to this SolidSystem"));
00244   osolid->destroy();
00245   solids.remove(solid);
00246 
00247   updateVisual();
00248 }
00249 
00250 
00251 
00252 void ODESolidSystem::addConstraintGroup(ref<ConstraintGroup> group)
00253 {
00254   ref<ODEConstraintGroup> ogroup = narrow_ref<ODEConstraintGroup>(group);
00255   if (ogroup->getWorldID() != worldID)
00256     throw std::invalid_argument(Exception("ConstraintGroup doesn't belong to this SolidSystem"));
00257   constraintGroups.push_back(ogroup);
00258 }
00259 
00260 
00261 void ODESolidSystem::removeConstraintGroup(ref<const ConstraintGroup> group)
00262 {
00263   ref<const ODEConstraintGroup> ogroup = narrow_ref<const ODEConstraintGroup>(group);
00264   if (ogroup->getWorldID() != worldID)
00265     throw std::invalid_argument(Exception("ConstraintGroup doesn't belong to this SolidSystem"));
00266 
00267   constraintGroups.ConstraintGroups::remove(ogroup);
00268 }
00269 
00270 
00271 void ODESolidSystem::setCollisionCuller(ref<CollisionCuller> collisionCuller)
00272 {
00273   // first disconnect the current culler from the detector
00274   this->collisionCuller->removePotentialCollisionListener(collisionDetector);
00275   
00276   // now connect up the new one  
00277   this->collisionCuller = collisionCuller;
00278   collisionCuller->addPotentialCollisionListener(collisionDetector);
00279 }
00280 
00281 
00282 ref<CollisionCuller> ODESolidSystem::getCollisionCuller() const
00283 {
00284   return collisionCuller;
00285 }
00286 
00287 
00288 void ODESolidSystem::setCollisionDetector(ref<CollisionDetector> collisionDetector)
00289 {
00290   // first disconnect the current detector from the culler & us
00291   collisionCuller->removePotentialCollisionListener(this->collisionDetector);
00292   this->collisionDetector->removePotentialCollisionListener(ref<ODESolidSystem>(this));
00293 
00294   // now connect up the new one  
00295   this->collisionDetector = collisionDetector;
00296   collisionCuller->addPotentialCollisionListener(collisionDetector);
00297   collisionDetector->addPotentialCollisionListener(ref<ODESolidSystem>(this));
00298 }
00299 
00300 
00301 ref<CollisionDetector> ODESolidSystem::getCollisionDetector() const
00302 {
00303   return collisionDetector;
00304 }
00305 
00306 
00307 void ODESolidSystem::setCollisionResponseHandler(ref<CollisionResponseHandler> collisionResponseHandler)
00308 {
00309   collisionHandler = collisionResponseHandler;
00310 }
00311 
00312 ref<CollisionResponseHandler> ODESolidSystem::getCollisionResponseHandler() const
00313 {
00314   return collisionHandler;
00315 }
00316 
00317 
00318 
00319 void ODESolidSystem::setParameter(const String& name, Real value)
00320 {
00321   if (name == String("ERP"))
00322     dWorldSetERP(worldID, value);
00323   else if (name == String("CFM"))
00324     dWorldSetCFM(worldID, value);
00325   else
00326     SolidSystem::setParameter(name, value);
00327 }
00328 
00329 
00330 // PotentialCollisionListener
00331 
00332 void ODESolidSystem::reset()
00333 {
00334   collisionHandler->reset();
00335 }
00336 
00337 void ODESolidSystem::potentialCollision(ref<const Collidable> collidable1, ref<const Collidable> collidable2)
00338 {
00339   if (collisionListenMode == HandleCollisions) { // pass collisions on to handler
00340     collisionHandler->potentialCollision(collidable1, collidable2);
00341   }
00342   else { // just initialy checking for interpenetrations
00343     
00344     if (!collidable1->isInterpenetrationNormal() && !collidable2->isInterpenetrationNormal()) 
00345       initiallyPenetratingPairs.push_back( std::make_pair<ref<const Collidable>, ref<const Collidable> >(collidable1, collidable2) );
00346   }
00347 }
00348 
00349 
00350 void ODESolidSystem::preSimulate()
00351 {
00352   // check that the current configurations for Solids is a valid one
00353   //  before simulating (i.e. check there are no penetrations)
00354   initialPenetrations = false;
00355   collisionListenMode = RecordInterpenetrations;
00356   initiallyPenetratingPairs.clear();
00357   
00358   if (collisionCuller != 0) {
00359     collisionCuller->collisionEnable(true);
00360     if (collidable == 0)
00361       collidable = createCollidable();
00362     collisionCuller->reset();
00363     collisionCuller->collide(collidable);
00364   }
00365 
00366   if (initialPenetrations) {
00367     Consoleln("The initial configuration of some Solids is one of inter-penetration (see log) - system inactivated.");
00368     active=false;
00369     collisionCuller->collisionEnable(false);
00370   }
00371   
00372   // permanently disable collisions between all initially penetrating pairs
00373   PenetratingPairs::const_iterator ppair = initiallyPenetratingPairs.begin();
00374   PenetratingPairs::const_iterator end = initiallyPenetratingPairs.end();
00375   while (ppair != end) {
00376     const CollidablePair& pair(*ppair);
00377     collisionCuller->collisionEnable(false, pair.first, pair.second);
00378     
00379     // log that we're disabling collisions
00380     String name1("unnamed"), name2("unnamed");
00381     if ( instanceof(*pair.first, const ODESolidConnectedCollidableBody))
00382       name1 = narrow_ref<const ODESolidConnectedCollidableBody>(pair.first)->getName();
00383     if ( instanceof(*pair.second, const ODESolidConnectedCollidableBody))
00384       name2 = narrow_ref<const ODESolidConnectedCollidableBody>(pair.second)->getName();
00385     
00386     Logln("Warning: Disabling collisions between CollidableBodies '" << name1 << "' and '" << name2 << "' as they are initiallly penetrating.");
00387     
00388     ++ppair;
00389   }
00390   
00391   
00392   initiallyPenetratingPairs.clear();
00393   collisionListenMode = HandleCollisions;
00394   
00395   preSimulateCalled = true;
00396 }
00397 
00398 
00399 void ODESolidSystem::simulateForSimTime(const base::Time& dt)
00400 {
00401   Assertm(preSimulateCalled,"preSimulate() called before simulateForSimTime()");
00402 
00403   // Do Collision detection
00404   if (collisionCuller != 0) {
00405 
00406     if (collidable != 0) {
00407       collisionCuller->reset();
00408       collisionCuller->collide(collidable);
00409     }
00410   }
00411 
00412   if (active && (dt>0)) 
00413     dWorldStep(worldID, dt.seconds());
00414   
00415   if (node != 0) { // is there a Visual?
00416     // update Visual
00417     Solids::iterator s = solids.begin();
00418     Solids::iterator end = solids.end();
00419     while (s != end) {
00420       ref<ODESolid> solid = narrow_ref<ODESolid>(*s);
00421       solid->updateVisual();
00422 
00423       ++s;
00424     }
00425   }
00426 }
00427 
00428 
00429 
00430 
00431 
00432 osg::Node* ODESolidSystem::createOSGVisual(Visual::Attributes visualAttributes) const
00433 {
00434   if ((node!=0) && (attributes==visualAttributes))
00435     return &(*node);
00436 
00437   node = new osg::Group();
00438   node->setName("ODESolidSystem");
00439 
00440   attributes = visualAttributes;
00441 
00442   updateVisual();
00443 
00444   return &(*node);
00445 }
00446 
00447 
00448 void ODESolidSystem::updateVisual() const
00449 {
00450   if (node==0) return; // no Visual to update
00451 
00452  // remove all Solids from the top-level group and re-add them (to account for
00453  //  additions and removals)
00454  while (node->getNumChildren() > 0)
00455    node->removeChild(node->getChild(0));
00456 
00457   // add solids 
00458   Solids::const_iterator_const s = solids.const_begin();
00459   Solids::const_iterator_const end = solids.const_end();
00460   while (s != end) {
00461     ref<const Solid> solid = *s;
00462     if (solid->visualTypeSupported(Visual::OSGVisual))
00463       node->addChild(solid->createOSGVisual(attributes));
00464     ++s;
00465   }
00466 //!!! and collider visuals etc.
00467   // add collision detector visual (if any)
00468   if (collisionDetector)
00469     if (collisionDetector->visualTypeSupported(Visual::OSGVisual))
00470       node->addChild(collisionDetector->createOSGVisual(attributes));
00471  
00472 }
00473 
00474 
00475 ref<Collidable> ODESolidSystem::createCollidable(CollidableFlags flags) 
00476 {
00477   // just create CollidableBodys for all the Solids and put them in 
00478   //  a single group
00479   ref<ODECollidableGroup> group(NewObj ODECollidableGroup());
00480 
00481   Solids::const_iterator s = solids.begin();
00482   Solids::const_iterator end = solids.end();
00483   while (s != end) {
00484     ref<Solid> solid = *s;
00485     group->addCollidable( solid->createCollidable(flags) ); 
00486     ++s;
00487   }
00488 
00489   return group;
00490 }
00491 

Generated on Thu Jul 29 15:56:27 2004 for OpenSim by doxygen 1.3.6