btGjkPairDetector.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 
00016 #include "btGjkPairDetector.h"
00017 #include "BulletCollision/CollisionShapes/btConvexShape.h"
00018 #include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h"
00019 #include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h"
00020 
00021 
00022 
00023 #if defined(DEBUG) || defined (_DEBUG)
00024 //#define TEST_NON_VIRTUAL 1
00025 #include <stdio.h> //for debug printf
00026 #ifdef __SPU__
00027 #include <spu_printf.h>
00028 #define printf spu_printf
00029 //#define DEBUG_SPU_COLLISION_DETECTION 1
00030 #endif //__SPU__
00031 #endif
00032 
00033 //must be above the machine epsilon
00034 #define REL_ERROR2 btScalar(1.0e-6)
00035 
00036 //temp globals, to improve GJK/EPA/penetration calculations
00037 int gNumDeepPenetrationChecks = 0;
00038 int gNumGjkChecks = 0;
00039 
00040 
00041 btGjkPairDetector::btGjkPairDetector(const btConvexShape* objectA,const btConvexShape* objectB,btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver*  penetrationDepthSolver)
00042 :m_cachedSeparatingAxis(btScalar(0.),btScalar(1.),btScalar(0.)),
00043 m_penetrationDepthSolver(penetrationDepthSolver),
00044 m_simplexSolver(simplexSolver),
00045 m_minkowskiA(objectA),
00046 m_minkowskiB(objectB),
00047 m_shapeTypeA(objectA->getShapeType()),
00048 m_shapeTypeB(objectB->getShapeType()),
00049 m_marginA(objectA->getMargin()),
00050 m_marginB(objectB->getMargin()),
00051 m_ignoreMargin(false),
00052 m_lastUsedMethod(-1),
00053 m_catchDegeneracies(1)
00054 {
00055 }
00056 btGjkPairDetector::btGjkPairDetector(const btConvexShape* objectA,const btConvexShape* objectB,int shapeTypeA,int shapeTypeB,btScalar marginA, btScalar marginB, btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver*        penetrationDepthSolver)
00057 :m_cachedSeparatingAxis(btScalar(0.),btScalar(1.),btScalar(0.)),
00058 m_penetrationDepthSolver(penetrationDepthSolver),
00059 m_simplexSolver(simplexSolver),
00060 m_minkowskiA(objectA),
00061 m_minkowskiB(objectB),
00062 m_shapeTypeA(shapeTypeA),
00063 m_shapeTypeB(shapeTypeB),
00064 m_marginA(marginA),
00065 m_marginB(marginB),
00066 m_ignoreMargin(false),
00067 m_lastUsedMethod(-1),
00068 m_catchDegeneracies(1)
00069 {
00070 }
00071 
00072 void    btGjkPairDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults)
00073 {
00074         (void)swapResults;
00075 
00076         getClosestPointsNonVirtual(input,output,debugDraw);
00077 }
00078 
00079 #ifdef __SPU__
00080 void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw)
00081 #else
00082 void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw)
00083 #endif
00084 {
00085         m_cachedSeparatingDistance = 0.f;
00086 
00087         btScalar distance=btScalar(0.);
00088         btVector3       normalInB(btScalar(0.),btScalar(0.),btScalar(0.));
00089         btVector3 pointOnA,pointOnB;
00090         btTransform     localTransA = input.m_transformA;
00091         btTransform localTransB = input.m_transformB;
00092         btVector3 positionOffset = (localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5);
00093         localTransA.getOrigin() -= positionOffset;
00094         localTransB.getOrigin() -= positionOffset;
00095 
00096         bool check2d = m_minkowskiA->isConvex2d() && m_minkowskiB->isConvex2d();
00097 
00098         btScalar marginA = m_marginA;
00099         btScalar marginB = m_marginB;
00100 
00101         gNumGjkChecks++;
00102 
00103 #ifdef DEBUG_SPU_COLLISION_DETECTION
00104         spu_printf("inside gjk\n");
00105 #endif
00106         //for CCD we don't use margins
00107         if (m_ignoreMargin)
00108         {
00109                 marginA = btScalar(0.);
00110                 marginB = btScalar(0.);
00111 #ifdef DEBUG_SPU_COLLISION_DETECTION
00112                 spu_printf("ignoring margin\n");
00113 #endif
00114         }
00115 
00116         m_curIter = 0;
00117         int gGjkMaxIter = 1000;//this is to catch invalid input, perhaps check for #NaN?
00118         m_cachedSeparatingAxis.setValue(0,1,0);
00119 
00120         bool isValid = false;
00121         bool checkSimplex = false;
00122         bool checkPenetration = true;
00123         m_degenerateSimplex = 0;
00124 
00125         m_lastUsedMethod = -1;
00126 
00127         {
00128                 btScalar squaredDistance = BT_LARGE_FLOAT;
00129                 btScalar delta = btScalar(0.);
00130                 
00131                 btScalar margin = marginA + marginB;
00132                 
00133                 
00134 
00135                 m_simplexSolver->reset();
00136                 
00137                 for ( ; ; )
00138                 //while (true)
00139                 {
00140 
00141                         btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* input.m_transformA.getBasis();
00142                         btVector3 seperatingAxisInB = m_cachedSeparatingAxis* input.m_transformB.getBasis();
00143 
00144 #if 1
00145 
00146                         btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
00147                         btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
00148 
00149 //                      btVector3 pInA  = localGetSupportingVertexWithoutMargin(m_shapeTypeA, m_minkowskiA, seperatingAxisInA,input.m_convexVertexData[0]);//, &featureIndexA);
00150 //                      btVector3 qInB  = localGetSupportingVertexWithoutMargin(m_shapeTypeB, m_minkowskiB, seperatingAxisInB,input.m_convexVertexData[1]);//, &featureIndexB);
00151 
00152 #else
00153 #ifdef __SPU__
00154                         btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
00155                         btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
00156 #else
00157                         btVector3 pInA = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
00158                         btVector3 qInB = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
00159 #ifdef TEST_NON_VIRTUAL
00160                         btVector3 pInAv = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
00161                         btVector3 qInBv = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
00162                         btAssert((pInAv-pInA).length() < 0.0001);
00163                         btAssert((qInBv-qInB).length() < 0.0001);
00164 #endif //
00165 #endif //__SPU__
00166 #endif
00167 
00168 
00169                         btVector3  pWorld = localTransA(pInA);  
00170                         btVector3  qWorld = localTransB(qInB);
00171 
00172 #ifdef DEBUG_SPU_COLLISION_DETECTION
00173                 spu_printf("got local supporting vertices\n");
00174 #endif
00175 
00176                         if (check2d)
00177                         {
00178                                 pWorld[2] = 0.f;
00179                                 qWorld[2] = 0.f;
00180                         }
00181 
00182                         btVector3 w     = pWorld - qWorld;
00183                         delta = m_cachedSeparatingAxis.dot(w);
00184 
00185                         // potential exit, they don't overlap
00186                         if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * input.m_maximumDistanceSquared)) 
00187                         {
00188                                 m_degenerateSimplex = 10;
00189                                 checkSimplex=true;
00190                                 //checkPenetration = false;
00191                                 break;
00192                         }
00193 
00194                         //exit 0: the new point is already in the simplex, or we didn't come any closer
00195                         if (m_simplexSolver->inSimplex(w))
00196                         {
00197                                 m_degenerateSimplex = 1;
00198                                 checkSimplex = true;
00199                                 break;
00200                         }
00201                         // are we getting any closer ?
00202                         btScalar f0 = squaredDistance - delta;
00203                         btScalar f1 = squaredDistance * REL_ERROR2;
00204 
00205                         if (f0 <= f1)
00206                         {
00207                                 if (f0 <= btScalar(0.))
00208                                 {
00209                                         m_degenerateSimplex = 2;
00210                                 } else
00211                                 {
00212                                         m_degenerateSimplex = 11;
00213                                 }
00214                                 checkSimplex = true;
00215                                 break;
00216                         }
00217 
00218 #ifdef DEBUG_SPU_COLLISION_DETECTION
00219                 spu_printf("addVertex 1\n");
00220 #endif
00221                         //add current vertex to simplex
00222                         m_simplexSolver->addVertex(w, pWorld, qWorld);
00223 #ifdef DEBUG_SPU_COLLISION_DETECTION
00224                 spu_printf("addVertex 2\n");
00225 #endif
00226                         btVector3 newCachedSeparatingAxis;
00227 
00228                         //calculate the closest point to the origin (update vector v)
00229                         if (!m_simplexSolver->closest(newCachedSeparatingAxis))
00230                         {
00231                                 m_degenerateSimplex = 3;
00232                                 checkSimplex = true;
00233                                 break;
00234                         }
00235 
00236                         if(newCachedSeparatingAxis.length2()<REL_ERROR2)
00237             {
00238                                 m_cachedSeparatingAxis = newCachedSeparatingAxis;
00239                 m_degenerateSimplex = 6;
00240                 checkSimplex = true;
00241                 break;
00242             }
00243 
00244                         btScalar previousSquaredDistance = squaredDistance;
00245                         squaredDistance = newCachedSeparatingAxis.length2();
00246 #if 0
00248                         if (squaredDistance>previousSquaredDistance)
00249                         {
00250                                 m_degenerateSimplex = 7;
00251                                 squaredDistance = previousSquaredDistance;
00252                 checkSimplex = false;
00253                 break;
00254                         }
00255 #endif //
00256                         
00257                         m_cachedSeparatingAxis = newCachedSeparatingAxis;
00258 
00259                         //redundant m_simplexSolver->compute_points(pointOnA, pointOnB);
00260 
00261                         //are we getting any closer ?
00262                         if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance) 
00263                         { 
00264                                 m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
00265                                 checkSimplex = true;
00266                                 m_degenerateSimplex = 12;
00267                                 
00268                                 break;
00269                         }
00270 
00271                           //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject   
00272               if (m_curIter++ > gGjkMaxIter)   
00273               {   
00274                       #if defined(DEBUG) || defined (_DEBUG) || defined (DEBUG_SPU_COLLISION_DETECTION)
00275 
00276                               printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter);   
00277                               printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",   
00278                               m_cachedSeparatingAxis.getX(),   
00279                               m_cachedSeparatingAxis.getY(),   
00280                               m_cachedSeparatingAxis.getZ(),   
00281                               squaredDistance,   
00282                               m_minkowskiA->getShapeType(),   
00283                               m_minkowskiB->getShapeType());   
00284 
00285                       #endif   
00286                       break;   
00287 
00288               } 
00289 
00290 
00291                         bool check = (!m_simplexSolver->fullSimplex());
00292                         //bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex());
00293 
00294                         if (!check)
00295                         {
00296                                 //do we need this backup_closest here ?
00297                                 m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
00298                                 m_degenerateSimplex = 13;
00299                                 break;
00300                         }
00301                 }
00302 
00303                 if (checkSimplex)
00304                 {
00305                         m_simplexSolver->compute_points(pointOnA, pointOnB);
00306                         normalInB = pointOnA-pointOnB;
00307                         btScalar lenSqr =m_cachedSeparatingAxis.length2();
00308                         
00309                         //valid normal
00310                         if (lenSqr < 0.0001)
00311                         {
00312                                 m_degenerateSimplex = 5;
00313                         } 
00314                         if (lenSqr > SIMD_EPSILON*SIMD_EPSILON)
00315                         {
00316                                 btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
00317                                 normalInB *= rlen; //normalize
00318                                 btScalar s = btSqrt(squaredDistance);
00319                         
00320                                 btAssert(s > btScalar(0.0));
00321                                 pointOnA -= m_cachedSeparatingAxis * (marginA / s);
00322                                 pointOnB += m_cachedSeparatingAxis * (marginB / s);
00323                                 distance = ((btScalar(1.)/rlen) - margin);
00324                                 isValid = true;
00325                                 
00326                                 m_lastUsedMethod = 1;
00327                         } else
00328                         {
00329                                 m_lastUsedMethod = 2;
00330                         }
00331                 }
00332 
00333                 bool catchDegeneratePenetrationCase = 
00334                         (m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < 0.01));
00335 
00336                 //if (checkPenetration && !isValid)
00337                 if (checkPenetration && (!isValid || catchDegeneratePenetrationCase ))
00338                 {
00339                         //penetration case
00340 
00341                         //if there is no way to handle penetrations, bail out
00342                         if (m_penetrationDepthSolver)
00343                         {
00344                                 // Penetration depth case.
00345                                 btVector3 tmpPointOnA,tmpPointOnB;
00346                                 
00347                                 gNumDeepPenetrationChecks++;
00348                                 m_cachedSeparatingAxis.setZero();
00349 
00350                                 bool isValid2 = m_penetrationDepthSolver->calcPenDepth( 
00351                                         *m_simplexSolver, 
00352                                         m_minkowskiA,m_minkowskiB,
00353                                         localTransA,localTransB,
00354                                         m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB,
00355                                         debugDraw,input.m_stackAlloc
00356                                         );
00357 
00358 
00359                                 if (isValid2)
00360                                 {
00361                                         btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA;
00362                                         btScalar lenSqr = tmpNormalInB.length2();
00363                                         if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON))
00364                                         {
00365                                                 tmpNormalInB = m_cachedSeparatingAxis;
00366                                                 lenSqr = m_cachedSeparatingAxis.length2();
00367                                         }
00368 
00369                                         if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON))
00370                                         {
00371                                                 tmpNormalInB /= btSqrt(lenSqr);
00372                                                 btScalar distance2 = -(tmpPointOnA-tmpPointOnB).length();
00373                                                 //only replace valid penetrations when the result is deeper (check)
00374                                                 if (!isValid || (distance2 < distance))
00375                                                 {
00376                                                         distance = distance2;
00377                                                         pointOnA = tmpPointOnA;
00378                                                         pointOnB = tmpPointOnB;
00379                                                         normalInB = tmpNormalInB;
00380                                                         isValid = true;
00381                                                         m_lastUsedMethod = 3;
00382                                                 } else
00383                                                 {
00384                                                         m_lastUsedMethod = 8;
00385                                                 }
00386                                         } else
00387                                         {
00388                                                 m_lastUsedMethod = 9;
00389                                         }
00390                                 } else
00391 
00392                                 {
00398 
00399                                 
00400                                         if (m_cachedSeparatingAxis.length2() > btScalar(0.))
00401                                         {
00402                                                 btScalar distance2 = (tmpPointOnA-tmpPointOnB).length()-margin;
00403                                                 //only replace valid distances when the distance is less
00404                                                 if (!isValid || (distance2 < distance))
00405                                                 {
00406                                                         distance = distance2;
00407                                                         pointOnA = tmpPointOnA;
00408                                                         pointOnB = tmpPointOnB;
00409                                                         pointOnA -= m_cachedSeparatingAxis * marginA ;
00410                                                         pointOnB += m_cachedSeparatingAxis * marginB ;
00411                                                         normalInB = m_cachedSeparatingAxis;
00412                                                         normalInB.normalize();
00413                                                         isValid = true;
00414                                                         m_lastUsedMethod = 6;
00415                                                 } else
00416                                                 {
00417                                                         m_lastUsedMethod = 5;
00418                                                 }
00419                                         }
00420                                 }
00421                                 
00422                         }
00423 
00424                 }
00425         }
00426 
00427         
00428 
00429         if (isValid && ((distance < 0) || (distance*distance < input.m_maximumDistanceSquared)))
00430         {
00431 #if 0
00433 //              if (check2d)
00434                 {
00435                         printf("n = %2.3f,%2.3f,%2.3f. ",normalInB[0],normalInB[1],normalInB[2]);
00436                         printf("distance = %2.3f exit=%d deg=%d\n",distance,m_lastUsedMethod,m_degenerateSimplex);
00437                 }
00438 #endif 
00439 
00440                 m_cachedSeparatingAxis = normalInB;
00441                 m_cachedSeparatingDistance = distance;
00442 
00443                 output.addContactPoint(
00444                         normalInB,
00445                         pointOnB+positionOffset,
00446                         distance);
00447 
00448         }
00449 
00450 
00451 }
00452 
00453 
00454 
00455 
00456 

Generated on Mon Feb 15 22:17:04 2010 for Bullet Collision Detection & Physics Library by  doxygen 1.6.1