ODESimulator.cpp

Go to the documentation of this file.
00001 /*************************************************************************
00002 *                                                                       *
00003 * Open Physics Abstraction Layer                                        *
00004 * Copyright (C) 2004-2005                                               *
00005 * Alan Fischer  alan.fischer@gmail.com                                  *
00006 * Andres Reinot  andres@reinot.com                                      *
00007 * Tyler Streeter  tylerstreeter@gmail.com                               *
00008 * All rights reserved.                                                  *
00009 * Web: opal.sourceforge.net                                             *
00010 *                                                                       *
00011 * This library is free software; you can redistribute it and/or         *
00012 * modify it under the terms of EITHER:                                  *
00013 *   (1) The GNU Lesser General Public License as published by the Free  *
00014 *       Software Foundation; either version 2.1 of the License, or (at  *
00015 *       your option) any later version. The text of the GNU Lesser      *
00016 *       General Public License is included with this library in the     *
00017 *       file license-LGPL.txt.                                          *
00018 *   (2) The BSD-style license that is included with this library in     *
00019 *       the file license-BSD.txt.                                       *
00020 *                                                                       *
00021 * This library is distributed in the hope that it will be useful,       *
00022 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
00024 * license-LGPL.txt and license-BSD.txt for more details.                *
00025 *                                                                       *
00026 *************************************************************************/
00027 
00028 // project headers
00029 #include "ODESimulator.h"
00030 #include "../ShapeData.h"
00031 
00032 using namespace std;
00033 
00034 namespace opal
00035 {
00036         OPAL_EXPORT_FUNCTION opal::Simulator* OPAL_CALL createSimulator( )
00037         {
00038                 // Check to make to ODE's reals are the same size as OPAL's reals.
00039                 if ( sizeof( real ) != sizeof( dReal ) )
00040                 {
00041                         OPAL_LOGGER( "warning" ) << "The size of data types (OPAL) real "
00042                         << "and (ODE) dReal do not match.  Make sure these "
00043                         << "libraries are built using the same floating point "
00044                         << "precision (float or double)." << std::endl;
00045                 }
00046 
00047                 opal::ODESimulator * sim = new opal::ODESimulator( );
00048                 sim->initData( opal::SimulatorData() );
00049                 return sim;
00050         }
00051 
00052         OPAL_EXPORT_FUNCTION opal::Simulator* OPAL_CALL createCustomSimulator( opal::SimulatorData & data )
00053         {
00054                 // Check to make to ODE's reals are the same size as OPAL's reals.
00055                 if ( sizeof( real ) != sizeof( dReal ) )
00056                 {
00057                         OPAL_LOGGER( "warning" ) << "The size of data types (OPAL) real "
00058                         << "and (ODE) dReal do not match.  Make sure these "
00059                         << "libraries are built using the same floating point "
00060                         << "precision (float or double)." << std::endl;
00061                 }
00062 
00063                 opal::ODESimulator * sim = new opal::ODESimulator( );
00064                 sim->initData( data );
00065                 return sim;
00066         }
00067 
00068         void ODESimulator::initData( SimulatorData data )
00069         {
00070                 Simulator::initData( data );
00071 
00072                 // Create ODE world.
00073                 mWorldID = dWorldCreate();
00074 
00075                 // Set default gravity.
00076                 setGravity( defaults::gravity );
00077 
00078                 // Create the root ODE space.
00079                 //mRootSpaceID = dSimpleSpaceCreate(0);
00080                 //dVector3 center = {0, 0, 0};
00081                 //dVector3 extents = {200, 100 200};
00082                 //mRootSpaceID = dQuadTreeSpaceCreate(0, center, extents, 5);
00083 
00084                 if ( data.useOctreeInsteadHash )
00085                 {
00086                         dVector3 center = { data.worldCenter[ 0 ],
00087                                             data.worldCenter[ 1 ],
00088                                             data.worldCenter[ 2 ] };
00089                         dVector3 extents = { data.worldSize[ 0 ],
00090                                              data.worldSize[ 1 ],
00091                                              data.worldSize[ 2 ] };
00092                         mRootSpaceID = dQuadTreeSpaceCreate( 0, center, extents, data.octreeDepth );
00093                 }
00094                 else
00095                 {
00096                         mRootSpaceID = dHashSpaceCreate( 0 );
00097                         dHashSpaceSetLevels( mRootSpaceID, data.hashMinLevel, data.hashMaxLevel );
00098                 }
00099 
00100                 mRootSpace = new ODESpace( mRootSpaceID );
00101 
00102                 // Create the ODE contact joint group.
00103                 mContactJointGroupID = dJointGroupCreate( 0 );
00104 
00105                 // Set the ODE global CFM value that will be used by all Joints
00106                 // (including contacts).  This affects normal Joint constraint
00107                 // operation and Joint limits.  The user cannot adjust CFM, but
00108                 // they can adjust ERP (a.k.a. bounciness/restitution) for materials
00109                 // (i.e. contact settings) and Joint limits.
00110                 dWorldSetCFM( mWorldID, defaults::ode::globalCFM );
00111 
00112                 // Set the ODE global ERP value.  This will only be used for Joints
00113                 // under normal conditions, not at their limits.  Also, it will not
00114                 // affect contacts at all since they use material properties to
00115                 // calculate ERP.
00116                 dWorldSetERP( mWorldID, ( real ) 0.5 * ( defaults::ode::maxERP +
00117                               defaults::ode::minERP ) );
00118 
00119                 dWorldSetContactSurfaceLayer( mWorldID, defaults::ode::surfaceLayer );
00120 
00121                 setSolverAccuracy( defaults::solverAccuracy );
00122                 mCollisionCount = 0;
00123                 // "mRaycastResult" is initialized in its own constructor.
00124                 mSensorSolid = NULL;
00125                 mRayContactGroup = defaults::shape::contactGroup;
00126         }
00127 
00128         ODESimulator::ODESimulator( )
00129         {
00130                 // empty
00131         }
00132 
00133         ODESimulator::~ODESimulator()
00134         {
00135                 // empty
00136         }
00137 
00138         void ODESimulator::setMaxCorrectingVel( real vel )
00139         {
00140                 Simulator::setMaxCorrectingVel( vel );
00141                 dWorldSetContactMaxCorrectingVel( mWorldID, vel );
00142         }
00143 
00144         Solid* ODESimulator::createSolid()
00145         {
00146                 Solid * newSolid = new ODESolid( mWorldID, mRootSpaceID );
00147                 addSolid( newSolid );
00148                 return newSolid;
00149         }
00150 
00151         Space* ODESimulator::createSpace()
00152         {
00153                 ODESpace * newSpace = new ODESpace();
00154 
00155                 // Add this new Space as a child of the Simulator's root Space.
00156                 dSpaceAdd( mRootSpaceID, ( dGeomID ) newSpace->internal_getSpaceID() );
00157 
00158                 addSpace( newSpace );
00159                 return newSpace;
00160         }
00161 
00162         Joint* ODESimulator::createJoint()
00163         {
00164                 Joint * newJoint = new ODEJoint( mWorldID );
00165                 addJoint( newJoint );
00166                 return newJoint;
00167         }
00168 
00169         void ODESimulator::destroy()
00170         {
00171                 // These temporary copies are necessary because the
00172                 // ODESimulator::~ODESimulator call (due to "delete this") will
00173                 // invalidate the data members.
00174                 dSpaceID rootSpaceID = mRootSpaceID;
00175                 dWorldID worldID = mWorldID;
00176                 dJointGroupID contactJointGroupID = mContactJointGroupID;
00177 
00178                 delete this;
00179 
00180                 // The following must occur after Simulator::~Simulator() is called;
00181                 // otherwise, Simulator::~Simulator() will try to destroy Solids after
00182                 // ODE has closed.
00183                 dSpaceDestroy( rootSpaceID );
00184                 dWorldDestroy( worldID );
00185                 dJointGroupDestroy( contactJointGroupID );
00186                 dCloseODE();
00187         }
00188 
00189         void ODESimulator::stepPhysics()
00190         {
00191                 // Apply linear and angular damping; if using the "add opposing
00192                 // forces" method, be sure to do this before calling ODE step
00193                 // function.
00194                 std::vector<Solid*>::iterator iter;
00195                 for ( iter = mSolidList.begin(); iter != mSolidList.end(); ++iter )
00196                 {
00197                         ODESolid* solid = ( ODESolid* ) ( *iter );
00198 
00199                         if ( !solid->isStatic() )
00200                         {
00201                                 if ( solid->isSleeping() )
00202                                 {
00203                                         // Reset velocities, force, & torques of objects that go
00204                                         // to sleep; ideally, this should happen in the ODE
00205                                         // source only once - when the object initially goes to
00206                                         // sleep.
00207 
00208                                         dBodyID bodyID = ( ( ODESolid* ) solid ) ->internal_getBodyID();
00209                                         dBodySetLinearVel( bodyID, 0, 0, 0 );
00210                                         dBodySetAngularVel( bodyID, 0, 0, 0 );
00211                                         dBodySetForce( bodyID, 0, 0, 0 );
00212                                         dBodySetTorque( bodyID, 0, 0, 0 );
00213                                 }
00214                                 else
00215                                 {
00216                                         // Dampen Solid motion.  3 possible methods:
00217                                         // 1) apply a force/torque in the opposite direction of
00218                                         // motion scaled by the body's velocity
00219                                         // 2) same as 1, but scale the opposing force by
00220                                         // the body's momentum (this automatically handles
00221                                         // different mass values)
00222                                         // 3) reduce the body's linear and angular velocity by
00223                                         // scaling them by 1 - damping * stepsize
00224 
00225                                         dBodyID bodyID = solid->internal_getBodyID();
00226                                         dMass mass;
00227                                         dBodyGetMass( bodyID, &mass );
00228 
00229                                         // Method 1
00230                                         //const dReal* l = dBodyGetLinearVel(bodyID);
00231                                         //dReal damping = -solid->getLinearDamping();
00232                                         //dBodyAddForce(bodyID, damping*l[0], damping*l[1], damping*l[2]);
00233                                         //const dReal* a = dBodyGetAngularVel(bodyID);
00234                                         //damping = -solid->getAngularDamping();
00235                                         //dBodyAddTorque(bodyID, damping*a[0], damping*a[1], damping*a[2]);
00236 
00237                                         // Method 2
00238                                         // Since the ODE mass.I inertia matrix is local, angular
00239                                         // velocity and torque also need to be local.
00240 
00241                                         // Linear damping
00242                                         real linearDamping = solid->getLinearDamping();
00243                                         if ( 0 != linearDamping )
00244                                         {
00245                                                 const dReal * lVelGlobal = dBodyGetLinearVel( bodyID );
00246 
00247                                                 // The damping force depends on the damping amount,
00248                                                 // mass, and velocity (i.e. damping amount and
00249                                                 // momentum).
00250                                                 dReal dampingFactor = -linearDamping * mass.mass;
00251                                                 dVector3 dampingForce = {
00252                                                                             dampingFactor * lVelGlobal[ 0 ],
00253                                                                             dampingFactor * lVelGlobal[ 1 ],
00254                                                                             dampingFactor * lVelGlobal[ 2 ] };
00255 
00256                                                 // Add a global force opposite to the global linear
00257                                                 // velocity.
00258                                                 dBodyAddForce( bodyID, dampingForce[ 0 ],
00259                                                                dampingForce[ 1 ], dampingForce[ 2 ] );
00260                                         }
00261 
00262                                         // Angular damping
00263                                         real angularDamping = solid->getAngularDamping();
00264                                         if ( 0 != angularDamping )
00265                                         {
00266                                                 const dReal * aVelGlobal = dBodyGetAngularVel( bodyID );
00267                                                 dVector3 aVelLocal;
00268                                                 dBodyVectorFromWorld( bodyID, aVelGlobal[ 0 ],
00269                                                                       aVelGlobal[ 1 ], aVelGlobal[ 2 ], aVelLocal );
00270 
00271                                                 // The damping force depends on the damping amount,
00272                                                 // mass, and velocity (i.e. damping amount and
00273                                                 // momentum).
00274                                                 //dReal dampingFactor = -angularDamping * mass.mass;
00275                                                 dReal dampingFactor = -angularDamping;
00276                                                 dVector3 aMomentum;
00277 
00278                                                 // Make adjustments for inertia tensor.
00279                                                 dMULTIPLYOP0_331( aMomentum, = , mass.I, aVelLocal );
00280                                                 dVector3 dampingTorque = {
00281                                                                              dampingFactor * aMomentum[ 0 ],
00282                                                                              dampingFactor * aMomentum[ 1 ],
00283                                                                              dampingFactor * aMomentum[ 2 ] };
00284 
00285                                                 // Add a local torque opposite to the local angular
00286                                                 // velocity.
00287                                                 dBodyAddRelTorque( bodyID, dampingTorque[ 0 ],
00288                                                                    dampingTorque[ 1 ], dampingTorque[ 2 ] );
00289                                         }
00290 
00291                                         //dMass mass;
00292                                         //dBodyGetMass(bodyID, &mass);
00293                                         //const dReal* l = dBodyGetLinearVel(bodyID);
00294                                         //dReal damping = -solid->getLinearDamping() * mass.mass;
00295                                         //dBodyAddForce(bodyID, damping*l[0], damping*l[1], damping*l[2]);
00296                                         //const dReal* aVelLocal = dBodyGetAngularVel(bodyID);
00299                                         //damping = -solid->getAngularDamping();
00300                                         //dVector3 aMomentum;
00301                                         //dMULTIPLYOP0_331(aMomentum, =, aVelLocal, mass.I);
00302                                         //dBodyAddTorque(bodyID, damping*aMomentum[0], damping*aMomentum[1],
00303                                         //  damping*aMomentum[2]);
00304 
00305                                         // Method 3
00306                                         //const dReal* l = dBodyGetLinearVel(bodyID);
00307                                         //dReal damping = (real)1.0 - solid->getLinearDamping() * mStepSize;
00308                                         //dBodySetLinearVel(bodyID, damping*l[0], damping*l[1], damping*l[2]);
00309                                         //const dReal* a = dBodyGetAngularVel(bodyID);
00310                                         //damping = (real)1.0 - solid->getAngularDamping() * mStepSize;
00311                                         //dBodySetAngularVel(bodyID, damping*a[0], damping*a[1], damping*a[2]);
00312                                 }
00313                         }
00314                 }
00315 
00316                 // Do collision detection; add contacts to the contact joint group.
00317                 dSpaceCollide( mRootSpaceID, this,
00318                                &ode_hidden::internal_collisionCallback );
00319 
00320                 // Take a simulation step.
00321                 if ( SOLVER_QUICKSTEP == mSolverType )
00322                 {
00323                         dWorldQuickStep( mWorldID, mStepSize );
00324                 }
00325                 else
00326                 {
00327                         dWorldStep( mWorldID, mStepSize );
00328                 }
00329 
00330                 // Remove all joints from the contact group.
00331                 dJointGroupEmpty( mContactJointGroupID );
00332 
00333                 // Fix angular velocities for freely-spinning bodies that have
00334                 // gained angular velocity through explicit integrator inaccuracy.
00335                 for ( iter = mSolidList.begin(); iter != mSolidList.end(); ++iter )
00336                 {
00337                         ODESolid* s = ( ODESolid* ) ( *iter );
00338                         if ( !s->isSleeping() && !s->isStatic() )
00339                         {
00340                                 s->internal_doAngularVelFix();
00341                         }
00342                 }
00343         }
00344 
00345         namespace ode_hidden
00346         {
00347                 void internal_collisionCallback( void *data, dGeomID o0, dGeomID o1 )
00348                 {
00349                         if ( dGeomIsSpace( o0 ) || dGeomIsSpace( o1 ) )
00350                         {
00351                                 // Colliding a space with either a geom or another space.
00352                                 dSpaceCollide2( o0, o1, data, &internal_collisionCallback );
00353 
00354                                 if ( dGeomIsSpace( o0 ) )
00355                                 {
00356                                         // Colliding all geoms internal to the space.
00357                                         dSpaceCollide( ( dSpaceID ) o0, data,
00358                                                        &internal_collisionCallback );
00359                                 }
00360 
00361                                 if ( dGeomIsSpace( o1 ) )
00362                                 {
00363                                         // Colliding all geoms internal to the space.
00364                                         dSpaceCollide( ( dSpaceID ) o1, data,
00365                                                        &internal_collisionCallback );
00366                                 }
00367                         }
00368                         else
00369                         {
00370                                 // Colliding two geoms.
00371 
00372                                 // The following is a set of special cases where we might
00373                                 // want to skip collision detection (but not all are
00374                                 // enforced here for various reasons):
00375                                 // 1. Two static Solids (neither geom has a body) AND
00376                                 //    neither Solid has a CollisionEventHandler AND there are
00377                                 //    not global handlers: this is enforced.
00378                                 // 2. Two Shapes that are part of the same Solid (they
00379                                 //    share a body): this is not enforced because ODE
00380                                 //    already takes care of it.
00381                                 // 3. Two sleeping Solids (note: both must have bodies to
00382                                 //    check this): this is enforced.  (ODE should handle
00383                                 //    this, but it doesn't.)
00384                                 // 4. Two Solids connected by a fixed Joint: this is
00385                                 //    enforced.
00386                                 // 5. Two Solids connected by a Joint (besides ODE
00387                                 //    contact joints, which should never generate more
00388                                 //    contacts) with contacts disabled (note: both must have
00389                                 //    bodies to check this): this is enforced.
00390                                 // 6. Solid0 is static, Solid1 is dynamic and is sleeping,
00391                                 //    static-to-sleeping contacts are ignored by the
00392                                 //    Simulator, and neither Solid has a
00393                                 //    CollisionEventHandler AND there are no global handlers:
00394                                 //    this is enforced.
00395                                 // 7. Solid1 is static, Solid0 is dynamic and is sleeping,
00396                                 //    static-to-sleeping contacts are ignored by the
00397                                 //    Simulator, and neither Solid has a
00398                                 //    CollisionEventHandler AND there are no global handlers:
00399                                 //    this is enforced.
00400                                 // 8. The two Solids' contact groups do not generate
00401                                 //    contacts when they collide AND neither Solid has a
00402                                 //    CollisionEventHandler AND there are no global handlers.
00403 
00404                                 // Get the geoms' ODE body IDs.
00405                                 dBodyID o0BodyID = dGeomGetBody( o0 );
00406                                 dBodyID o1BodyID = dGeomGetBody( o1 );
00407                                 bool solid0Static = ( 0 == o0BodyID );
00408                                 bool solid1Static = ( 0 == o1BodyID );
00409 
00410                                 // Check if both Solids are dynamic (i.e. have ODE bodies).
00411                                 bool bothHaveBodies = true;
00412                                 if ( 0 == o0BodyID || 0 == o1BodyID )
00413                                 {
00414                                         bothHaveBodies = false;
00415                                 }
00416 
00417                                 // If the two Solids are connected by a common Joint, get
00418                                 // a pointer to that Joint.
00419                                 Joint* commonJoint = NULL;
00420                                 if ( bothHaveBodies && dAreConnectedExcluding( o0BodyID,
00421                                         o1BodyID, dJointTypeContact ) )
00422                                 {
00423                                         // This will become non-NULL only if there exists an ODE
00424                                         // joint connecting the two bodies.
00425                                         commonJoint = internal_getCommonJoint( o0BodyID, o1BodyID );
00426                                 }
00427 
00428                                 // Get pointers to the geoms' GeomData structures.
00429                                 GeomData* geomData0 = ( GeomData* ) dGeomGetData( o0 );
00430                                 GeomData* geomData1 = ( ( GeomData* ) dGeomGetData( o1 ) );
00431 
00432                                 // Get pointers to the geoms' ShapeData structures.
00433                                 const ShapeData* shape0 = geomData0->shape;
00434                                 const ShapeData* shape1 = geomData1->shape;
00435 
00436                                 // Get a pointer to the ODESimulator.
00437                                 ODESimulator* sim = ( ODESimulator* ) data;
00438 
00439                                 // Check if the two Solids' contact groups generate contacts
00440                                 // when they collide.
00441                                 bool makeContacts = sim->groupsMakeContacts(
00442                                                         shape0->contactGroup, shape1->contactGroup );
00443 
00444                                 // Find out whether the Simulator has static-to-sleeping
00445                                 // contacts disabled.
00446                                 bool ignoreStaticSleepingContacts =
00447                                     !sim->areStaticSleepingContactsEnabled();
00448 
00449                                 // Get pointers to the geoms' Solids.
00450                                 Solid* solid0 = geomData0->solid;
00451                                 Solid* solid1 = geomData1->solid;
00452 
00453                                 // Get pointers to the two Solids' CollisionEventHandlers.
00454                                 // These will be NULL if the Solids don't use
00455                                 // CollisionEventHandlers.
00456                                 CollisionEventHandler* handler0 =
00457                                     solid0->getCollisionEventHandler();
00458                                 CollisionEventHandler* handler1 =
00459                                     solid1->getCollisionEventHandler();
00460 
00461                                 bool neitherHasEventHandler = !( handler0 || handler1 );
00462 
00463                                 bool hasNoGlobalHandler = sim->getNumGlobalCollisionEventHandlers() == 0;
00464 
00465                                 // Now do the actual tests to see if we should return early.
00466                                 // It is important here that we don't call dBodyIsEnabled on
00467                                 // a static body because that crashes ODE.
00468 
00469                                 bool case1 = neitherHasEventHandler && hasNoGlobalHandler
00470                                              && solid0Static && solid1Static;
00471                                 //bool case2= o0BodyID == o1BodyID;
00472                                 bool case3 = bothHaveBodies && !dBodyIsEnabled( o0BodyID )
00473                                              && !dBodyIsEnabled( o1BodyID );
00474                                 bool case4 = commonJoint &&
00475                                              commonJoint->getType() == FIXED_JOINT;
00476                                 bool case5 = commonJoint
00477                                              && !commonJoint->areContactsEnabled();
00478                                 bool case6 = solid0Static && 0 != o1BodyID
00479                                              && !dBodyIsEnabled( o1BodyID )
00480                                              && ignoreStaticSleepingContacts
00481                                              && neitherHasEventHandler && hasNoGlobalHandler;
00482                                 bool case7 = solid1Static && 0 != o0BodyID
00483                                              && !dBodyIsEnabled( o0BodyID )
00484                                              && ignoreStaticSleepingContacts
00485                                              && neitherHasEventHandler && hasNoGlobalHandler;
00486                                 bool case8 = !makeContacts && neitherHasEventHandler
00487                                              && hasNoGlobalHandler;
00488 
00489                                 if ( case1 || case3 || case4 || case5 || case6 || case7 || case8 )
00490                                         return ;
00491 
00492                                 // Now actually test for collision between the two geoms.
00493                                 // This is one of the more expensive operations.
00494                                 dWorldID theWorldID = sim->internal_getWorldID();
00495                                 dJointGroupID theJointGroupID =
00496                                     sim->internal_getJointGroupID();
00497                                 dContactGeom contactArray[ globals::maxMaxContacts ];
00498                                 int numContacts = dCollide( o0, o1, sim->getMaxContacts(),
00499                                         contactArray, sizeof( dContactGeom ) );
00500 
00501                                 // If the two objects didn't make any contacts, they weren't
00502                                 // touching, so just return.
00503                                 if ( 0 == numContacts )
00504                                 {
00505                                         return ;
00506                                 }
00507 
00508                                 // If at least one of the Solids has a CollisionEventHandler,
00509                                 // send it a CollisionEvent.
00510                                 if ( handler0 || handler1 || !hasNoGlobalHandler )
00511                                 {
00512                                         // Call the CollisionEventHandlers.  Note that we only
00513                                         // use one contact point per collision: just the first one
00514                                         // in the contact array.  The order of the Solids
00515                                         // passed to the event handlers is important: the first
00516                                         // one should be the one whose event handler is
00517                                         // getting called.
00518 
00519                                         CollisionEvent e;
00520                                         e.thisSolid = solid0;
00521                                         e.otherSolid = solid1;
00522                                         e.pos[ 0 ] = ( real ) contactArray[ 0 ].pos[ 0 ];
00523                                         e.pos[ 1 ] = ( real ) contactArray[ 0 ].pos[ 1 ];
00524                                         e.pos[ 2 ] = ( real ) contactArray[ 0 ].pos[ 2 ];
00525                                         e.normal[ 0 ] = ( real ) contactArray[ 0 ].normal[ 0 ];
00526                                         e.normal[ 1 ] = ( real ) contactArray[ 0 ].normal[ 1 ];
00527                                         e.normal[ 2 ] = ( real ) contactArray[ 0 ].normal[ 2 ];
00528                                         e.depth = ( real ) contactArray[ 0 ].depth;
00529 
00530                                         if ( handler0 )
00531                                         {
00532                                                 handler0->internal_pushCollisionEvent( e );
00533                                         }
00534 
00535                                         if ( handler1 )
00536                                         {
00537                                                 // For the other Solid's CollisionEventHandler, we need
00538                                                 // to invert the normal and swap the Solid pointers.
00539                                                 e.normal *= -1;
00540                                                 e.thisSolid = solid1;
00541                                                 e.otherSolid = solid0;
00542                                                 handler1->internal_pushCollisionEvent( e );
00543                                         }
00544 
00545                                         sim->internal_recordCollision( e );
00546                                 }
00547 
00548                                 // Old version...
00550                                 //if (solid0->getCollisionEventHandler()
00551                                 //  || solid1->getCollisionEventHandler())
00552                                 //{
00553                                 //  // Call the event handlers.  Note: we only use one
00554                                 //  // contact point per collision; just use the first one
00555                                 //  // in the contact array.  The order of the Solids
00556                                 //  // passed to the event handlers is important: the first
00557                                 //  // one should be the one whose event handler is
00558                                 //  // getting called.
00559 
00560                                 //  CollisionEvent e;
00561                                 //  e.solid0 = solid0;
00562                                 //  e.solid1 = solid1;
00563                                 //  e.pos[0] = contactArray[0].pos[0];
00564                                 //  e.pos[1] = contactArray[0].pos[1];
00565                                 //  e.pos[2] = contactArray[0].pos[2];
00566                                 //  e.normal[0] = contactArray[0].normal[0];
00567                                 //  e.normal[1] = contactArray[0].normal[1];
00568                                 //  e.normal[2] = contactArray[0].normal[2];
00569                                 //  e.depth = contactArray[0].depth;
00570 
00571                                 //  EventHandler* eventHandler =
00572                                 //      solid0->getCollisionEventHandler();
00573                                 //  if (eventHandler)
00574                                 //  {
00575                                 //      generateContacts0 =
00576                                 //          eventHandler->handleCollisionEvent(e);
00577                                 //  }
00578 
00579                                 //  e.normal *= -1; // Invert normal.
00580                                 //  e.solid0 = solid1; // Swap solid pointers.
00581                                 //  e.solid1 = solid0;
00582 
00583                                 //  eventHandler = solid1->getCollisionEventHandler();
00584                                 //  if (eventHandler)
00585                                 //  {
00586                                 //      generateContacts1 =
00587                                 //          eventHandler->handleCollisionEvent(e);
00588                                 //  }
00589                                 //}
00590 
00591                                 if ( makeContacts )
00592                                 {
00593                                         // Invalidate the "freely-spinning" parameters.
00594                                         ( ( ODESolid* ) solid0 ) ->internal_setFreelySpinning( false );
00595                                         ( ( ODESolid* ) solid1 ) ->internal_setFreelySpinning( false );
00596 
00597                                         for ( int i = 0; i < numContacts; ++i )
00598                                         {
00599                                                 const Material* m0 = &( shape0->material );
00600                                                 const Material* m1 = &( shape1->material );
00601 
00602                                                 dContact tempContact;
00603                                                 tempContact.surface.mode = dContactBounce |
00604                                                         dContactSoftERP; // | dContactSoftCFM;
00605 
00606                                                 // Average the hardness of the two materials.
00607                                                 assert( m0->hardness >= 0 && m0->hardness <= 1
00608                                                         && m1->hardness >= 0 && m1->hardness <= 1 );
00609                                                 real hardness = ( m0->hardness + m1->hardness ) *
00610                                                                 ( real ) 0.5;
00611 
00612                                                 // Convert hardness to ERP.  As hardness goes from
00613                                                 // 0.0 to 1.0, ERP goes from min to max.
00614                                                 tempContact.surface.soft_erp = hardness *
00615                                                         ( defaults::ode::maxERP - defaults::ode::minERP ) +
00616                                                         defaults::ode::minERP;
00617 
00618                                                 // Don't use contact CFM anymore.  Just let it use
00619                                                 // the global value set in the ODE world.
00620                                                 //tempContact.surface.soft_cfm =
00621                                                 //  defaults::ode::minCFM;
00622 
00623                                                 // As friction goes from 0.0 to 1.0, mu goes from 0.0
00624                                                 // to max, though it is set to dInfinity when
00625                                                 // friction == 1.0.
00626                                                 assert( m0->friction >= 0 && m0->friction <= 1
00627                                                         && m1->friction >= 0 && m1->friction <= 1 );
00628                                                 if ( 1.0 == m0->friction && 1.0 == m1->friction )
00629                                                 {
00630                                                         tempContact.surface.mu = dInfinity;
00631                                                 }
00632                                                 else
00633                                                 {
00634                                                         tempContact.surface.mu =
00635                                                             sqrt( m0->friction * m1->friction ) *
00636                                                             defaults::ode::maxFriction;
00637                                                 }
00638 
00639                                                 // Average the bounciness of the two materials.
00640                                                 assert( m0->bounciness >= 0 && m0->bounciness <= 1
00641                                                         && m1->bounciness >= 0 && m1->bounciness <= 1 );
00642                                                 real bounciness = ( m0->bounciness + m1->bounciness ) *
00643                                                         ( real ) 0.5;
00644 
00645                                                 // ODE's bounce parameter, a.k.a. restitution.
00646                                                 tempContact.surface.bounce = bounciness;
00647 
00648                                                 // ODE's bounce_vel parameter is a threshold:
00649                                                 // the relative velocity of the two objects must be
00650                                                 // greater than this for bouncing to occur at all.
00651                                                 tempContact.surface.bounce_vel =
00652                                                     defaults::bounceThreshold;
00653 
00654                                                 // Old way to calculate bounce threshold; threshold
00655                                                 // was scaled by the collision bounciness, but this
00656                                                 // makes all objects with non-zero bounciness
00657                                                 // always bounce.  This is undesirable because it
00658                                                 // takes a while for bouncing to totally diminish.
00659                                                 //tempContact.surface.bounce_vel =
00660                                                 //  defaults::ode::maxBounceVel - bounciness *
00661                                                 //  defaults::ode::maxBounceVel;
00662 
00663                                                 tempContact.geom = contactArray[ i ];
00664                                                 dJointID contactJoint = dJointCreateContact(
00665                                                         theWorldID, theJointGroupID, &tempContact );
00666 
00667                                                 // Note: the following line of code replaces the
00668                                                 // rest of this function which is commented out.
00669                                                 // TODO: test this and make sure the mass ratio
00670                                                 // issues are unimportant and that we never need
00671                                                 // "one-sided" contacts between two Solids.
00672                                                 dJointAttach( contactJoint, o0BodyID, o1BodyID );
00673 
00674                                                 //if (!bothHaveBodies)
00675                                                 //{
00676                                                 //  // at least one object is static, so just handle
00677                                                 //  // things like normal
00678                                                 //  dJointAttach(contactJoint, o0BodyID, o1BodyID);
00679                                                 //}
00680                                                 //else
00681                                                 //{
00682                                                 //  // TODO: We probably need to remove the following chunk of
00683                                                 //  // code.  The first case is obsolete since now both sides
00684                                                 //  // always get contacts, if at all.  (There isn't really a
00685                                                 //  // good reason to have one side use contacts but not the
00686                                                 //  // other; the side not wanting contacts would appear to be
00687                                                 //  // static, so just make it static in the first place.  On
00688                                                 //  // the other hand, this may end up being desirable if
00689                                                 //  // an object should be moved by some objects but not
00690                                                 //  // others, and the "others" *do* collid with the first
00691                                                 //  // object... but this situation may never come up.  The
00692                                                 //  // second case, using mass ratios to determine whether two
00693                                                 //  // objects should collide, might not be an issue.  Mass
00694                                                 //  // ratios might only be a problem when the two objects are
00695                                                 //  // constantly connected with a Joint.
00696 
00697                                                 //  // Handle one-sided contacts for two cases: 1) only one of
00698                                                 //  // the above event handlers actually wants contacts generated,
00699                                                 //  // 2) if the mass ratio is above some threshold, treat it as
00700                                                 //  // a one-sided collision solution: treat the more massive
00701                                                 //  // object as static, calculate the collision like normal
00702                                                 //  // (with the massive one being static), then also add the
00703                                                 //  // massive object's velocity to the smaller one (velocity
00704                                                 //  // calculated at the point of collision).
00705 
00706                                                 //  // calculate mass ratio (use mass1 / mass2); if
00707                                                 //  // the ratio is too high, mass1 is too large; if
00708                                                 //  // the ratio is too low, mass2 is too large
00709                                                 //  real massRatio = 0;
00710                                                 //  dMass mass0, mass1;
00711                                                 //  dBodyGetMass(o0BodyID, &mass0);
00712                                                 //  dBodyGetMass(o1BodyID, &mass1);
00713                                                 //  massRatio = mass0.mass / mass1.mass;
00714 
00715                                                 //  // here we handle all the different collision
00716                                                 //  // cases: one solid or the other or both may want
00717                                                 //  // contacts generated; also, the mass ratio may
00718                                                 //  // be outside the acceptable range
00719 
00720                                                 //  if (true == generateContacts0 && true ==
00721                                                 //      generateContacts1)
00722                                                 //  {
00723                                                 //      // both want contacts, neither wants to be
00724                                                 //      // static
00725                                                 //      if (massRatio > defaults::ode::maxMassRatio)
00726                                                 //      {
00727                                                 //          // ratio is too high - mass0 is too large,
00728                                                 //          // treat solid0 as static
00729                                                 //          dBodyEnable(o1BodyID);
00730                                                 //          dJointAttach(contactJoint, 0, o1BodyID);
00731                                                 //      }
00732                                                 //      else if (massRatio <
00733                                                 //          defaults::ode::minMassRatio)
00734                                                 //      {
00735                                                 //          // ratio is too low - mass1 is too large,
00736                                                 //          // treat solid1 as static
00737                                                 //          dBodyEnable(o0BodyID);
00738                                                 //          dJointAttach(contactJoint, o0BodyID, 0);
00739                                                 //      }
00740                                                 //      else
00741                                                 //      {
00742                                                 //          //ratio is good - no static objects
00743                                                 //          dJointAttach(contactJoint, o0BodyID,
00744                                                 //              o1BodyID);
00745                                                 //      }
00746                                                 //  }
00747                                                 //  else if (true == generateContacts0)
00748                                                 //  {
00749                                                 //      // solid0 wants contacts, solid1 wants to be
00750                                                 //      // static
00751                                                 //      if (massRatio > defaults::ode::maxMassRatio)
00752                                                 //      {
00753                                                 //          // ratio is too high - mass0 is too large,
00754                                                 //          // treat solid0 and solid1 as static
00755                                                 //          // i.e. don't generate a contact joint
00756                                                 //      }
00757                                                 //      else
00758                                                 //      {
00759                                                 //          // this block handles two cases which have
00760                                                 //          // the same result:
00761                                                 //          // 1. ratio is too low - mass1 is too
00762                                                 //          //  large, treat solid1 as static
00763                                                 //          // 2. ratio is good - treat solid1 as
00764                                                 //          //  static
00765                                                 //          dBodyEnable(o0BodyID);
00766                                                 //          dJointAttach(contactJoint, o0BodyID, 0);
00767                                                 //      }
00768                                                 //  }
00769                                                 //  else //generateContacts1 must be true
00770                                                 //  {
00771                                                 //      // solid1 wants contacts, solid0 wants to be
00772                                                 //      // static
00773                                                 //      if (massRatio < defaults::ode::minMassRatio)
00774                                                 //      {
00775                                                 //          // ratio is too low - mass1 is too large,
00776                                                 //          // treat solid0 and solid1 as static
00777                                                 //          // i.e. don't generate a contact joint
00778                                                 //      }
00779                                                 //      else
00780                                                 //      {
00781                                                 //          // this block handles two cases which have
00782                                                 //          // the same result:
00783                                                 //          // 1. ratio is too high - mass0 is too
00784                                                 //          //  large, treat solid0 as static
00785                                                 //          // 2. ratio is good - treat solid0 as
00786                                                 //          //  static
00787                                                 //          dBodyEnable(o1BodyID);
00788                                                 //          dJointAttach(contactJoint, 0, o1BodyID);
00789                                                 //      }
00790                                                 //  }
00791                                                 //}
00792                                         }
00793                                 }
00794                         }
00795                 }
00796 
00797                 Joint* internal_getCommonJoint( dBodyID body0, dBodyID body1 )
00798                 {
00799                         // First we need to find the ODE joint connecting the bodies
00800                         // (it would be ideal if ODE included this functionality...).
00801                         // We only need to check one of the bodies' ODE joints
00802                         // because it is assumed here that the two bodies are
00803                         // connected, thus they should have a common ODE joint.
00804                         int numJoints0 = dBodyGetNumJoints( body0 );
00805                         dJointID theJoint = 0;
00806 
00807                         // Loop through body0's ODE joints.
00808                         int i = 0;
00809                         for ( i = 0; i < numJoints0; ++i )
00810                         {
00811                                 dJointID currentJoint = dBodyGetJoint( body0, i );
00812                                 dBodyID jointBody0 = dJointGetBody( currentJoint, 0 );
00813                                 dBodyID jointBody1 = dJointGetBody( currentJoint, 1 );
00814 
00815                                 if ( ( jointBody0 == body0 && jointBody1 == body1 ) ||
00816                                         ( jointBody0 == body1 && jointBody1 == body0 ) )
00817                                 {
00818                                         // This is the ODE joint connecting the two bodies.
00819                                         // Note that if the two bodies are connected by multiple
00820                                         // Joints, the behavior is undefined.
00821                                         theJoint = currentJoint;
00822                                 }
00823                         }
00824 
00825                         // Make sure the ODE joint was actually found.  This should
00826                         // be guaranteed.
00827                         assert( theJoint );
00828 
00829                         // Now return the associated OPAL Joint.
00830                         return ( Joint* ) dJointGetData( theJoint );
00831                 }
00832 
00833                 void internal_volumeCollisionCallback( void* data, dGeomID o0,
00834                                                        dGeomID o1 )
00835                 {
00836                         if ( dGeomIsSpace( o0 ) || dGeomIsSpace( o1 ) )
00837                         {
00838                                 // Colliding a space with either a geom or another space.
00839                                 dSpaceCollide2( o0, o1, data,
00840                                         &internal_volumeCollisionCallback );
00841                         }
00842                         else
00843                         {
00844                                 // Colliding two geoms.
00845 
00846                                 //dBodyID o0BodyID = dGeomGetBody(o0);
00847                                 //dBodyID o1BodyID = dGeomGetBody(o1);
00848                                 //bool bothHaveBodies = true;
00849                                 //if (0 == o0BodyID || 0 == o1BodyID)
00850                                 //{
00851                                 //  bothHaveBodies = false;
00852                                 //}
00853 
00854                                 // don't do collision detection for the following case:
00855                                 // two shapes that are part of the same solid (they share a
00856                                 // body)
00857                                 // update -> this is already handled by ODE
00858                                 //if (bothHaveBodies && o0BodyID == o1BodyID)
00859                                 //{
00860                                 //  //don't do collision detection
00861                                 //  return;
00862                                 //}
00863 
00864                                 // Get a pointer to the ODESimulator.
00865                                 ODESimulator* sim = ( ODESimulator* ) data;
00866 
00867                                 // Get pointers to the two geoms' GeomData structure.  Both
00868                                 // of these should always be non-NULL.
00869                                 const GeomData* geomData0 = ( ( GeomData* ) dGeomGetData( o0 ) );
00870                                 const GeomData* geomData1 = ( ( GeomData* ) dGeomGetData( o1 ) );
00871                                 assert( geomData0 != NULL );
00872                                 assert( geomData1 != NULL );
00873 
00874                                 // Get pointers to the geoms' ShapeData structures.
00875                                 const ShapeData* shape0 = geomData0->shape;
00876                                 const ShapeData* shape1 = geomData1->shape;
00877 
00878                                 // Check if the two Solids' contact groups generate contacts
00879                                 // when they collide.
00880                                 bool makeContacts = sim->groupsMakeContacts(
00881                                         shape0->contactGroup, shape1->contactGroup );
00882                                 if ( !makeContacts )
00883                                 {
00884                                         return ;
00885                                 }
00886 
00887                                 // Now actually test for collision between the two geoms.
00888                                 // This is a fairly expensive operation.
00889                                 dContactGeom contactArray[ 1 ];
00890                                 int numContacts = dCollide( o0, o1, 1, contactArray,
00891                                         sizeof( dContactGeom ) );
00892 
00893                                 if ( 0 == numContacts )
00894                                 {
00895                                         return ;
00896                                 }
00897                                 else
00898                                 {
00899                                         // These two geoms must be intersecting.
00900 
00901                                         // Get pointers to the geoms' Solids.
00902                                         Solid* solid0 = geomData0->solid;
00903                                         Solid* solid1 = geomData1->solid;
00904 
00905                                         // Not sure at this point if we can know that o1 is the
00906                                         // volume object, so we'll just call this twice.  It
00907                                         // will automatically keep from adding the same Solid
00908                                         // multiple times by using its collision count.  Later,
00909                                         // the volume Solid will be removed from this list.
00910                                         sim->internal_addCollidedSolid( solid0 );
00911                                         sim->internal_addCollidedSolid( solid1 );
00912                                 }
00913                         }
00914                 }
00915 
00916                 void internal_raycastCollisionCallback( void* data, dGeomID o0,
00917                                                         dGeomID o1 )
00918                 {
00919                         if ( dGeomIsSpace( o0 ) || dGeomIsSpace( o1 ) )
00920                         {
00921                                 // Colliding a space with either a geom or another space.
00922                                 dSpaceCollide2( o0, o1, data,
00923                                         &internal_raycastCollisionCallback );
00924                         }
00925                         else
00926                         {
00927                                 // Colliding two geoms.
00928 
00929                                 // Sometimes we get a case where the ray geom is passed in
00930                                 // as both objects, which is stupid.
00931                                 if ( o0 == o1 )
00932                                 {
00933                                         return ;
00934                                 }
00935 
00936                                 // Get a pointer to the ODESimulator.
00937                                 ODESimulator* sim = ( ODESimulator* ) data;
00938 
00939                                 // Get pointers to the two geoms' GeomData structure.  One
00940                                 // of these (the one NOT belonging to the ray geom)
00941                                 // will always be non-NULL.
00942                                 GeomData* geomData0 = ( ( GeomData* ) dGeomGetData( o0 ) );
00943                                 GeomData* geomData1 = ( ( GeomData* ) dGeomGetData( o1 ) );
00944 
00945                                 // Find the contact group of the collided Solid.
00946                                 unsigned int geomContactGroup = defaults::shape::contactGroup;
00947                                 if ( geomData0 )
00948                                 {
00949                                         geomContactGroup = geomData0->shape->contactGroup;
00950                                 }
00951                                 else
00952                                 {
00953                                         geomContactGroup = geomData1->shape->contactGroup;
00954                                 }
00955 
00956                                 // Check if the two Solids' contact groups generate contacts
00957                                 // when they collide.
00958                                 bool makeContacts = sim->groupsMakeContacts(
00959                                         geomContactGroup, sim->internal_getRayContactGroup() );
00960                                 if ( !makeContacts )
00961                                 {
00962                                         return ;
00963                                 }
00964 
00965                                 // Now actually test for collision between the two geoms.
00966                                 // This is a fairly expensive operation.
00967                                 dContactGeom contactArray[ defaults::ode::maxRaycastContacts ];
00968                                 int numContacts = dCollide( o0, o1, 
00969                                         defaults::ode::maxRaycastContacts, contactArray,
00970                                         sizeof( dContactGeom ) );
00971 
00972                                 if ( 0 == numContacts )
00973                                 {
00974                                         return ;
00975                                 }
00976                                 else
00977                                 {
00978                                         // These two geoms must be intersecting.  We will store 
00979                                         // only the closest RaycastResult.
00980                                         int closest = 0;
00981                                         for (int i = 0; i < numContacts; ++i)
00982                                         {
00983                                                 if (contactArray[i].depth < contactArray[closest].depth)
00984                                                 {
00985                                                         closest = i;
00986                                                 }
00987                                         }
00988 
00989                                         // Only one of the geoms will be part of a Solid we 
00990                                         // want to store; the other is the ray.
00991                                         Solid* solid = NULL;
00992                                         if ( geomData0 )
00993                                         {
00994                                                 solid = geomData0->solid;
00995                                         }
00996                                         else
00997                                         {
00998                                                 solid = geomData1->solid;
00999                                         }
01000 
01001                                         Point3r intersection( ( real ) contactArray[ closest ].pos[ 0 ],
01002                                                 ( real ) contactArray[ closest ].pos[ 1 ],
01003                                                 ( real ) contactArray[ closest ].pos[ 2 ] );
01004                                         Vec3r normal( ( real ) contactArray[ closest ].normal[ 0 ],
01005                                                 ( real ) contactArray[ closest ].normal[ 1 ],
01006                                                 ( real ) contactArray[ closest ].normal[ 2 ] );
01007 
01008                                         sim->internal_addRaycastResult( solid, intersection, 
01009                                                 normal, ( real ) contactArray[ closest ].depth );
01010                                 }
01011                         }
01012                 }
01013         }
01014 
01015         void ODESimulator::internal_addCollidedSolid( Solid* solid )
01016         {
01017                 // If the collided Solid is attached to the Sensor performing the
01018                 // volume query, ignore this intersection.
01019                 if ( mSensorSolid == solid )
01020                 {
01021                         return ;
01022                 }
01023 
01024                 ODESolid* solidPtr = ( ( ODESolid* ) solid );
01025 
01026                 if ( solidPtr->internal_getCollisionCount() != mCollisionCount )
01027                 {
01028                         mVolumeQueryResult.internal_addSolid( solid );
01029                         solidPtr->internal_setCollisionCount( mCollisionCount );
01030                 }
01031         }
01032 
01033         void ODESimulator::internal_addRaycastResult( Solid* solid,
01034                 const Point3r& intersection, const Vec3r& normal, real depth )
01035         {
01036                 // If the collided Solid is attached to the Sensor performing the
01037                 // raycast, ignore this intersection.
01038                 if ( mSensorSolid == solid )
01039                 {
01040                         return ;
01041                 }
01042 
01043                 // Add this RaycastResult to the vector of results.
01044                 RaycastResult result;
01045                 result.solid = solid;
01046                 result.intersection = intersection;
01047                 result.normal = normal;
01048                 result.distance = depth;
01049                 mRaycastResults.push_back( result );
01050         }
01051 
01052         unsigned int ODESimulator::internal_getRayContactGroup()
01053         {
01054                 return mRayContactGroup;
01055         }
01056 
01057         //helper function for collision callback
01058         //void createOneSidedContact(dJointID contactJoint, dBodyID movingObject,
01059         //                                       dBodyID staticObject, dVector3 pos)
01060         //{
01061         //treat one object as static, but add make sure to add its velocity
01062         //(at the contact point) to the other
01063 
01064         //dVector3 result;
01065         //dBodyGetPointVel(staticObject, pos[0], pos[1], pos[2], result);
01066 
01068         //const dReal* linearVel = dBodyGetLinearVel(movingObject);
01069         //dVector3 newVel = {linearVel[0] + result[0], linearVel[1] + result[1], linearVel[2] + result[2]};
01070         //dBodySetLinearVel(movingObject, newVel[0], newVel[1], newVel[2]);
01071 
01072         //dBodyEnable(movingObject);
01073         //dJointAttach(contactJoint, 0, movingObject); //this works when movingObject is body2
01074         //dJointAttach(contactJoint, movingObject, 0); //this works when movingObject is body1
01075         //}
01076 
01077         vector<RaycastResult> & ODESimulator::internal_fireRay( const Rayr& r,
01078                 real length, const Solid* attachedSolid,
01079                 unsigned int rayContactGroup )
01080         {
01081                 Point3r origin = r.getOrigin();
01082                 Vec3r dir = r.getDir().unit();
01083 
01084                 mRaycastResults.clear();
01085                 mSensorSolid = attachedSolid;
01086                 mRayContactGroup = rayContactGroup;
01087 
01088                 // Create an ODE ray geom.  Make sure its user data pointer is
01089                 // NULL because this is used in the collision callback to
01090                 // distinguish the ray from other geoms.
01091                 dGeomID rayGeomID = dCreateRay( mRootSpaceID, length );
01092                 dGeomRaySet( rayGeomID, origin[ 0 ], origin[ 1 ], origin[ 2 ], dir[ 0 ],
01093                              dir[ 1 ], dir[ 2 ] );
01094                 dGeomSetData( rayGeomID, NULL );
01095 
01096                 // Check for collisions.  This will fill mRaycastResult with valid
01097                 // data.  Its Solid pointer will remain NULL if nothing was hit.
01098                 dSpaceCollide2( rayGeomID, ( dGeomID ) mRootSpaceID, this,
01099                                 &ode_hidden::internal_raycastCollisionCallback );
01100 
01101                 // Finished with ODE ray, so destroy it.
01102                 dGeomDestroy( rayGeomID );
01103 
01104                 return mRaycastResults;
01105         }
01106 
01107         const VolumeQueryResult& ODESimulator::internal_queryVolume(
01108             const Solid* volume, const Solid* attachedSolid )
01109         {
01110                 mSensorSolid = attachedSolid;
01111                 mCollisionCount++;
01112                 mVolumeQueryResult.internal_clearSolids();
01113                 const std::vector<GeomData*>* geomList =
01114                     ( ( ODESolid* ) volume ) ->internal_getGeomDataList();
01115 
01116                 // Check for collisions with each of the volume Solid's geoms.
01117                 // This will fill up mVolumeQueryResult with those Solids that
01118                 // collide with these geoms.
01119                 std::vector<GeomData*>::const_iterator iter;
01120                 for ( iter = geomList->begin(); iter != geomList->end(); ++iter )
01121                 {
01122                         dGeomID geomID = ( *iter ) ->geomID;
01123                         if ( ( *iter ) ->transformID )
01124                         {
01125                                 // Using geom transform.
01126                                 geomID = ( *iter ) ->transformID;
01127                         }
01128 
01129                         dSpaceCollide2( geomID, ( dGeomID ) mRootSpaceID, this,
01130                                 &ode_hidden::internal_volumeCollisionCallback );
01131                 }
01132 
01133                 // We don't want the volume Solid to be listed in the results.
01134                 mVolumeQueryResult.internal_removeSolid( volume );
01135 
01136                 return mVolumeQueryResult;
01137         }
01138 
01139         void ODESimulator::setGravity( const Vec3r& gravity )
01140         {
01141                 dWorldSetGravity( mWorldID, gravity[ 0 ], gravity[ 1 ], gravity[ 2 ] );
01142         }
01143 
01144         Vec3r ODESimulator::getGravity() const
01145         {
01146                 dVector3 g;
01147                 dWorldGetGravity( mWorldID, g );
01148                 Vec3r gravity( ( real ) g[ 0 ], ( real ) g[ 1 ], ( real ) g[ 2 ] );
01149                 return gravity;
01150         }
01151 
01152         void ODESimulator::setSolverAccuracy( SolverAccuracyLevel level )
01153         {
01154                 Simulator::setSolverAccuracy( level );
01155 
01156                 switch ( level )
01157                 {
01158                         case SOLVER_ACCURACY_VERY_LOW:
01159                                 mSolverType = SOLVER_QUICKSTEP;
01160                                 dWorldSetQuickStepNumIterations( mWorldID, 5 );
01161                                 break;
01162                         case SOLVER_ACCURACY_LOW:
01163                                 mSolverType = SOLVER_QUICKSTEP;
01164                                 dWorldSetQuickStepNumIterations( mWorldID, 10 );
01165                                 break;
01166                         case SOLVER_ACCURACY_MEDIUM:
01167                                 mSolverType = SOLVER_QUICKSTEP;
01168                                 // 20 is the default in ODE
01169                                 dWorldSetQuickStepNumIterations( mWorldID, 20 );
01170                                 break;
01171                         case SOLVER_ACCURACY_HIGH:
01172                                 mSolverType = SOLVER_QUICKSTEP;
01173                                 dWorldSetQuickStepNumIterations( mWorldID, 40 );
01174                                 break;
01175                         case SOLVER_ACCURACY_VERY_HIGH:
01176                                 mSolverType = SOLVER_WORLDSTEP;
01177                                 break;
01178                         default:
01179                                 assert( false );
01180                                 break;
01181                 }
01182         }
01183 
01184         dWorldID ODESimulator::internal_getWorldID() const
01185         {
01186                 return mWorldID;
01187         }
01188 
01189         dSpaceID ODESimulator::internal_getSpaceID() const
01190         {
01191                 return mRootSpaceID;
01192         }
01193 
01194         dJointGroupID ODESimulator::internal_getJointGroupID() const
01195         {
01196                 return mContactJointGroupID;
01197         }
01198 }

Generated on Tue May 16 17:49:51 2006 for OPAL by  doxygen 1.4.6-NO