Blender  V2.59
btConvexConvexAlgorithm.cpp
Go to the documentation of this file.
00001 /*
00002 Bullet Continuous Collision Detection and Physics Library
00003 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
00004 
00005 This software is provided 'as-is', without any express or implied warranty.
00006 In no event will the authors be held liable for any damages arising from the use of this software.
00007 Permission is granted to anyone to use this software for any purpose, 
00008 including commercial applications, and to alter it and redistribute it freely, 
00009 subject to the following restrictions:
00010 
00011 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00013 3. This notice may not be removed or altered from any source distribution.
00014 */
00015 
00019 //define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER 1
00020 
00021 #include "btConvexConvexAlgorithm.h"
00022 
00023 //#include <stdio.h>
00024 #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h"
00025 #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
00026 #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
00027 #include "BulletCollision/CollisionShapes/btConvexShape.h"
00028 #include "BulletCollision/CollisionShapes/btCapsuleShape.h"
00029 
00030 
00031 #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h"
00032 #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
00033 #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
00034 #include "BulletCollision/CollisionShapes/btBoxShape.h"
00035 #include "BulletCollision/CollisionDispatch/btManifoldResult.h"
00036 
00037 #include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h"
00038 #include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h"
00039 #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h"
00040 #include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h"
00041 
00042 
00043 
00044 #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h"
00045 #include "BulletCollision/CollisionShapes/btSphereShape.h"
00046 
00047 #include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h"
00048 
00049 #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h"
00050 #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h"
00051 
00052 
00053 
00055 
00056 
00057 
00058 static SIMD_FORCE_INLINE void segmentsClosestPoints(
00059         btVector3& ptsVector,
00060         btVector3& offsetA,
00061         btVector3& offsetB,
00062         btScalar& tA, btScalar& tB,
00063         const btVector3& translation,
00064         const btVector3& dirA, btScalar hlenA,
00065         const btVector3& dirB, btScalar hlenB )
00066 {
00067         // compute the parameters of the closest points on each line segment
00068 
00069         btScalar dirA_dot_dirB = btDot(dirA,dirB);
00070         btScalar dirA_dot_trans = btDot(dirA,translation);
00071         btScalar dirB_dot_trans = btDot(dirB,translation);
00072 
00073         btScalar denom = 1.0f - dirA_dot_dirB * dirA_dot_dirB;
00074 
00075         if ( denom == 0.0f ) {
00076                 tA = 0.0f;
00077         } else {
00078                 tA = ( dirA_dot_trans - dirB_dot_trans * dirA_dot_dirB ) / denom;
00079                 if ( tA < -hlenA )
00080                         tA = -hlenA;
00081                 else if ( tA > hlenA )
00082                         tA = hlenA;
00083         }
00084 
00085         tB = tA * dirA_dot_dirB - dirB_dot_trans;
00086 
00087         if ( tB < -hlenB ) {
00088                 tB = -hlenB;
00089                 tA = tB * dirA_dot_dirB + dirA_dot_trans;
00090 
00091                 if ( tA < -hlenA )
00092                         tA = -hlenA;
00093                 else if ( tA > hlenA )
00094                         tA = hlenA;
00095         } else if ( tB > hlenB ) {
00096                 tB = hlenB;
00097                 tA = tB * dirA_dot_dirB + dirA_dot_trans;
00098 
00099                 if ( tA < -hlenA )
00100                         tA = -hlenA;
00101                 else if ( tA > hlenA )
00102                         tA = hlenA;
00103         }
00104 
00105         // compute the closest points relative to segment centers.
00106 
00107         offsetA = dirA * tA;
00108         offsetB = dirB * tB;
00109 
00110         ptsVector = translation - offsetA + offsetB;
00111 }
00112 
00113 
00114 static SIMD_FORCE_INLINE btScalar capsuleCapsuleDistance(
00115         btVector3& normalOnB,
00116         btVector3& pointOnB,
00117         btScalar capsuleLengthA,
00118         btScalar        capsuleRadiusA,
00119         btScalar capsuleLengthB,
00120         btScalar        capsuleRadiusB,
00121         int capsuleAxisA,
00122         int capsuleAxisB,
00123         const btTransform& transformA,
00124         const btTransform& transformB,
00125         btScalar distanceThreshold )
00126 {
00127         btVector3 directionA = transformA.getBasis().getColumn(capsuleAxisA);
00128         btVector3 translationA = transformA.getOrigin();
00129         btVector3 directionB = transformB.getBasis().getColumn(capsuleAxisB);
00130         btVector3 translationB = transformB.getOrigin();
00131 
00132         // translation between centers
00133 
00134         btVector3 translation = translationB - translationA;
00135 
00136         // compute the closest points of the capsule line segments
00137 
00138         btVector3 ptsVector;           // the vector between the closest points
00139         
00140         btVector3 offsetA, offsetB;    // offsets from segment centers to their closest points
00141         btScalar tA, tB;              // parameters on line segment
00142 
00143         segmentsClosestPoints( ptsVector, offsetA, offsetB, tA, tB, translation,
00144                                                    directionA, capsuleLengthA, directionB, capsuleLengthB );
00145 
00146         btScalar distance = ptsVector.length() - capsuleRadiusA - capsuleRadiusB;
00147 
00148         if ( distance > distanceThreshold )
00149                 return distance;
00150 
00151         btScalar lenSqr = ptsVector.length2();
00152         if (lenSqr<= (SIMD_EPSILON*SIMD_EPSILON))
00153         {
00154                 //degenerate case where 2 capsules are likely at the same location: take a vector tangential to 'directionA'
00155                 btVector3 q;
00156                 btPlaneSpace1(directionA,normalOnB,q);
00157         } else
00158         {
00159                 // compute the contact normal
00160                 normalOnB = ptsVector*-btRecipSqrt(lenSqr);
00161         }
00162         pointOnB = transformB.getOrigin()+offsetB + normalOnB * capsuleRadiusB;
00163 
00164         return distance;
00165 }
00166 
00167 
00168 
00169 
00170 
00171 
00172 
00174 
00175 
00176 
00177 
00178 
00179 btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface*                       simplexSolver, btConvexPenetrationDepthSolver* pdSolver)
00180 {
00181         m_numPerturbationIterations = 0;
00182         m_minimumPointsPerturbationThreshold = 3;
00183         m_simplexSolver = simplexSolver;
00184         m_pdSolver = pdSolver;
00185 }
00186 
00187 btConvexConvexAlgorithm::CreateFunc::~CreateFunc() 
00188 { 
00189 }
00190 
00191 btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold)
00192 : btActivatingCollisionAlgorithm(ci,body0,body1),
00193 m_simplexSolver(simplexSolver),
00194 m_pdSolver(pdSolver),
00195 m_ownManifold (false),
00196 m_manifoldPtr(mf),
00197 m_lowLevelOfDetail(false),
00198 #ifdef USE_SEPDISTANCE_UTIL2
00199 m_sepDistance((static_cast<btConvexShape*>(body0->getCollisionShape()))->getAngularMotionDisc(),
00200                           (static_cast<btConvexShape*>(body1->getCollisionShape()))->getAngularMotionDisc()),
00201 #endif
00202 m_numPerturbationIterations(numPerturbationIterations),
00203 m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold)
00204 {
00205         (void)body0;
00206         (void)body1;
00207 }
00208 
00209 
00210 
00211 
00212 btConvexConvexAlgorithm::~btConvexConvexAlgorithm()
00213 {
00214         if (m_ownManifold)
00215         {
00216                 if (m_manifoldPtr)
00217                         m_dispatcher->releaseManifold(m_manifoldPtr);
00218         }
00219 }
00220 
00221 void    btConvexConvexAlgorithm ::setLowLevelOfDetail(bool useLowLevel)
00222 {
00223         m_lowLevelOfDetail = useLowLevel;
00224 }
00225 
00226 
00227 struct btPerturbedContactResult : public btManifoldResult
00228 {
00229         btManifoldResult* m_originalManifoldResult;
00230         btTransform m_transformA;
00231         btTransform m_transformB;
00232         btTransform     m_unPerturbedTransform;
00233         bool    m_perturbA;
00234         btIDebugDraw*   m_debugDrawer;
00235 
00236 
00237         btPerturbedContactResult(btManifoldResult* originalResult,const btTransform& transformA,const btTransform& transformB,const btTransform& unPerturbedTransform,bool perturbA,btIDebugDraw* debugDrawer)
00238                 :m_originalManifoldResult(originalResult),
00239                 m_transformA(transformA),
00240                 m_transformB(transformB),
00241                 m_unPerturbedTransform(unPerturbedTransform),
00242                 m_perturbA(perturbA),
00243                 m_debugDrawer(debugDrawer)
00244         {
00245         }
00246         virtual ~ btPerturbedContactResult()
00247         {
00248         }
00249 
00250         virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar orgDepth)
00251         {
00252                 btVector3 endPt,startPt;
00253                 btScalar newDepth;
00254                 btVector3 newNormal;
00255 
00256                 if (m_perturbA)
00257                 {
00258                         btVector3 endPtOrg = pointInWorld + normalOnBInWorld*orgDepth;
00259                         endPt = (m_unPerturbedTransform*m_transformA.inverse())(endPtOrg);
00260                         newDepth = (endPt -  pointInWorld).dot(normalOnBInWorld);
00261                         startPt = endPt+normalOnBInWorld*newDepth;
00262                 } else
00263                 {
00264                         endPt = pointInWorld + normalOnBInWorld*orgDepth;
00265                         startPt = (m_unPerturbedTransform*m_transformB.inverse())(pointInWorld);
00266                         newDepth = (endPt -  startPt).dot(normalOnBInWorld);
00267                         
00268                 }
00269 
00270 //#define DEBUG_CONTACTS 1
00271 #ifdef DEBUG_CONTACTS
00272                 m_debugDrawer->drawLine(startPt,endPt,btVector3(1,0,0));
00273                 m_debugDrawer->drawSphere(startPt,0.05,btVector3(0,1,0));
00274                 m_debugDrawer->drawSphere(endPt,0.05,btVector3(0,0,1));
00275 #endif //DEBUG_CONTACTS
00276 
00277                 
00278                 m_originalManifoldResult->addContactPoint(normalOnBInWorld,startPt,newDepth);
00279         }
00280 
00281 };
00282 
00283 extern btScalar gContactBreakingThreshold;
00284 
00285 
00286 //
00287 // Convex-Convex collision algorithm
00288 //
00289 void btConvexConvexAlgorithm ::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
00290 {
00291 
00292         if (!m_manifoldPtr)
00293         {
00294                 //swapped?
00295                 m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1);
00296                 m_ownManifold = true;
00297         }
00298         resultOut->setPersistentManifold(m_manifoldPtr);
00299 
00300         //comment-out next line to test multi-contact generation
00301         //resultOut->getPersistentManifold()->clearManifold();
00302         
00303 
00304         btConvexShape* min0 = static_cast<btConvexShape*>(body0->getCollisionShape());
00305         btConvexShape* min1 = static_cast<btConvexShape*>(body1->getCollisionShape());
00306 
00307         btVector3  normalOnB;
00308                 btVector3  pointOnBWorld;
00309 #ifndef BT_DISABLE_CAPSULE_CAPSULE_COLLIDER
00310         if ((min0->getShapeType() == CAPSULE_SHAPE_PROXYTYPE) && (min1->getShapeType() == CAPSULE_SHAPE_PROXYTYPE))
00311         {
00312                 btCapsuleShape* capsuleA = (btCapsuleShape*) min0;
00313                 btCapsuleShape* capsuleB = (btCapsuleShape*) min1;
00314                 btVector3 localScalingA = capsuleA->getLocalScaling();
00315                 btVector3 localScalingB = capsuleB->getLocalScaling();
00316                 
00317                 btScalar threshold = m_manifoldPtr->getContactBreakingThreshold();
00318 
00319                 btScalar dist = capsuleCapsuleDistance(normalOnB,       pointOnBWorld,capsuleA->getHalfHeight(),capsuleA->getRadius(),
00320                         capsuleB->getHalfHeight(),capsuleB->getRadius(),capsuleA->getUpAxis(),capsuleB->getUpAxis(),
00321                         body0->getWorldTransform(),body1->getWorldTransform(),threshold);
00322 
00323                 if (dist<threshold)
00324                 {
00325                         btAssert(normalOnB.length2()>=(SIMD_EPSILON*SIMD_EPSILON));
00326                         resultOut->addContactPoint(normalOnB,pointOnBWorld,dist);       
00327                 }
00328                 resultOut->refreshContactPoints();
00329                 return;
00330         }
00331 #endif //BT_DISABLE_CAPSULE_CAPSULE_COLLIDER
00332 
00333 
00334 #ifdef USE_SEPDISTANCE_UTIL2
00335         if (dispatchInfo.m_useConvexConservativeDistanceUtil)
00336         {
00337                 m_sepDistance.updateSeparatingDistance(body0->getWorldTransform(),body1->getWorldTransform());
00338         }
00339 
00340         if (!dispatchInfo.m_useConvexConservativeDistanceUtil || m_sepDistance.getConservativeSeparatingDistance()<=0.f)
00341 #endif //USE_SEPDISTANCE_UTIL2
00342 
00343         {
00344 
00345         
00346         btGjkPairDetector::ClosestPointInput input;
00347 
00348         btGjkPairDetector       gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver);
00349         //TODO: if (dispatchInfo.m_useContinuous)
00350         gjkPairDetector.setMinkowskiA(min0);
00351         gjkPairDetector.setMinkowskiB(min1);
00352 
00353 #ifdef USE_SEPDISTANCE_UTIL2
00354         if (dispatchInfo.m_useConvexConservativeDistanceUtil)
00355         {
00356                 input.m_maximumDistanceSquared = BT_LARGE_FLOAT;
00357         } else
00358 #endif //USE_SEPDISTANCE_UTIL2
00359         {
00360                 if (dispatchInfo.m_convexMaxDistanceUseCPT)
00361                 {
00362                         input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactProcessingThreshold();
00363                 } else
00364                 {
00365                         input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold();
00366                 }
00367                 input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared;
00368         }
00369 
00370         input.m_stackAlloc = dispatchInfo.m_stackAllocator;
00371         input.m_transformA = body0->getWorldTransform();
00372         input.m_transformB = body1->getWorldTransform();
00373 
00374         gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw);
00375 
00376         
00377 
00378 #ifdef USE_SEPDISTANCE_UTIL2
00379         btScalar sepDist = 0.f;
00380         if (dispatchInfo.m_useConvexConservativeDistanceUtil)
00381         {
00382                 sepDist = gjkPairDetector.getCachedSeparatingDistance();
00383                 if (sepDist>SIMD_EPSILON)
00384                 {
00385                         sepDist += dispatchInfo.m_convexConservativeDistanceThreshold;
00386                         //now perturbe directions to get multiple contact points
00387                         
00388                 }
00389         }
00390 #endif //USE_SEPDISTANCE_UTIL2
00391 
00392         //now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects
00393         
00394         //perform perturbation when more then 'm_minimumPointsPerturbationThreshold' points
00395         if (m_numPerturbationIterations && resultOut->getPersistentManifold()->getNumContacts() < m_minimumPointsPerturbationThreshold)
00396         {
00397                 
00398                 int i;
00399                 btVector3 v0,v1;
00400                 btVector3 sepNormalWorldSpace;
00401         
00402                 sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis().normalized();
00403                 btPlaneSpace1(sepNormalWorldSpace,v0,v1);
00404 
00405 
00406                 bool perturbeA = true;
00407                 const btScalar angleLimit = 0.125f * SIMD_PI;
00408                 btScalar perturbeAngle;
00409                 btScalar radiusA = min0->getAngularMotionDisc();
00410                 btScalar radiusB = min1->getAngularMotionDisc();
00411                 if (radiusA < radiusB)
00412                 {
00413                         perturbeAngle = gContactBreakingThreshold /radiusA;
00414                         perturbeA = true;
00415                 } else
00416                 {
00417                         perturbeAngle = gContactBreakingThreshold / radiusB;
00418                         perturbeA = false;
00419                 }
00420                 if ( perturbeAngle > angleLimit ) 
00421                                 perturbeAngle = angleLimit;
00422 
00423                 btTransform unPerturbedTransform;
00424                 if (perturbeA)
00425                 {
00426                         unPerturbedTransform = input.m_transformA;
00427                 } else
00428                 {
00429                         unPerturbedTransform = input.m_transformB;
00430                 }
00431                 
00432                 for ( i=0;i<m_numPerturbationIterations;i++)
00433                 {
00434                         if (v0.length2()>SIMD_EPSILON)
00435                         {
00436                         btQuaternion perturbeRot(v0,perturbeAngle);
00437                         btScalar iterationAngle = i*(SIMD_2_PI/btScalar(m_numPerturbationIterations));
00438                         btQuaternion rotq(sepNormalWorldSpace,iterationAngle);
00439                         
00440                         
00441                         if (perturbeA)
00442                         {
00443                                 input.m_transformA.setBasis(  btMatrix3x3(rotq.inverse()*perturbeRot*rotq)*body0->getWorldTransform().getBasis());
00444                                 input.m_transformB = body1->getWorldTransform();
00445 #ifdef DEBUG_CONTACTS
00446                                 dispatchInfo.m_debugDraw->drawTransform(input.m_transformA,10.0);
00447 #endif //DEBUG_CONTACTS
00448                         } else
00449                         {
00450                                 input.m_transformA = body0->getWorldTransform();
00451                                 input.m_transformB.setBasis( btMatrix3x3(rotq.inverse()*perturbeRot*rotq)*body1->getWorldTransform().getBasis());
00452 #ifdef DEBUG_CONTACTS
00453                                 dispatchInfo.m_debugDraw->drawTransform(input.m_transformB,10.0);
00454 #endif
00455                         }
00456                         
00457                         btPerturbedContactResult perturbedResultOut(resultOut,input.m_transformA,input.m_transformB,unPerturbedTransform,perturbeA,dispatchInfo.m_debugDraw);
00458                         gjkPairDetector.getClosestPoints(input,perturbedResultOut,dispatchInfo.m_debugDraw);
00459                         }
00460                         
00461                 }
00462         }
00463 
00464         
00465 
00466 #ifdef USE_SEPDISTANCE_UTIL2
00467         if (dispatchInfo.m_useConvexConservativeDistanceUtil && (sepDist>SIMD_EPSILON))
00468         {
00469                 m_sepDistance.initSeparatingDistance(gjkPairDetector.getCachedSeparatingAxis(),sepDist,body0->getWorldTransform(),body1->getWorldTransform());
00470         }
00471 #endif //USE_SEPDISTANCE_UTIL2
00472 
00473 
00474         }
00475 
00476         if (m_ownManifold)
00477         {
00478                 resultOut->refreshContactPoints();
00479         }
00480 
00481 }
00482 
00483 
00484 
00485 bool disableCcd = false;
00486 btScalar        btConvexConvexAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
00487 {
00488         (void)resultOut;
00489         (void)dispatchInfo;
00491     
00494         btScalar resultFraction = btScalar(1.);
00495 
00496 
00497         btScalar squareMot0 = (col0->getInterpolationWorldTransform().getOrigin() - col0->getWorldTransform().getOrigin()).length2();
00498         btScalar squareMot1 = (col1->getInterpolationWorldTransform().getOrigin() - col1->getWorldTransform().getOrigin()).length2();
00499     
00500         if (squareMot0 < col0->getCcdSquareMotionThreshold() &&
00501                 squareMot1 < col1->getCcdSquareMotionThreshold())
00502                 return resultFraction;
00503 
00504         if (disableCcd)
00505                 return btScalar(1.);
00506 
00507 
00508         //An adhoc way of testing the Continuous Collision Detection algorithms
00509         //One object is approximated as a sphere, to simplify things
00510         //Starting in penetration should report no time of impact
00511         //For proper CCD, better accuracy and handling of 'allowed' penetration should be added
00512         //also the mainloop of the physics should have a kind of toi queue (something like Brian Mirtich's application of Timewarp for Rigidbodies)
00513 
00514                 
00516         {
00517                 btConvexShape* convex0 = static_cast<btConvexShape*>(col0->getCollisionShape());
00518 
00519                 btSphereShape   sphere1(col1->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation
00520                 btConvexCast::CastResult result;
00521                 btVoronoiSimplexSolver voronoiSimplex;
00522                 //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex);
00524                 btGjkConvexCast ccd1( convex0 ,&sphere1,&voronoiSimplex);
00525                 //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0);
00526                 if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(),
00527                         col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result))
00528                 {
00529                 
00530                         //store result.m_fraction in both bodies
00531                 
00532                         if (col0->getHitFraction()> result.m_fraction)
00533                                 col0->setHitFraction( result.m_fraction );
00534 
00535                         if (col1->getHitFraction() > result.m_fraction)
00536                                 col1->setHitFraction( result.m_fraction);
00537 
00538                         if (resultFraction > result.m_fraction)
00539                                 resultFraction = result.m_fraction;
00540 
00541                 }
00542                 
00543                 
00544 
00545 
00546         }
00547 
00549         {
00550                 btConvexShape* convex1 = static_cast<btConvexShape*>(col1->getCollisionShape());
00551 
00552                 btSphereShape   sphere0(col0->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation
00553                 btConvexCast::CastResult result;
00554                 btVoronoiSimplexSolver voronoiSimplex;
00555                 //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex);
00557                 btGjkConvexCast ccd1(&sphere0,convex1,&voronoiSimplex);
00558                 //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0);
00559                 if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(),
00560                         col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result))
00561                 {
00562                 
00563                         //store result.m_fraction in both bodies
00564                 
00565                         if (col0->getHitFraction()      > result.m_fraction)
00566                                 col0->setHitFraction( result.m_fraction);
00567 
00568                         if (col1->getHitFraction() > result.m_fraction)
00569                                 col1->setHitFraction( result.m_fraction);
00570 
00571                         if (resultFraction > result.m_fraction)
00572                                 resultFraction = result.m_fraction;
00573 
00574                 }
00575         }
00576         
00577         return resultFraction;
00578 
00579 }
00580