PageRenderTime 93ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/external/bullet-2.81-rev2613/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp

https://gitlab.com/dannywillems/mass_collide
C++ | 457 lines | 323 code | 84 blank | 50 comment | 39 complexity | e19db83eb2a590daef946d04573c7900 MD5 | raw file
  1. /*
  2. Bullet Continuous Collision Detection and Physics Library
  3. Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
  4. This software is provided 'as-is', without any express or implied warranty.
  5. In no event will the authors be held liable for any damages arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it freely,
  8. subject to the following restrictions:
  9. 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.
  10. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  11. 3. This notice may not be removed or altered from any source distribution.
  12. */
  13. #include "btGjkPairDetector.h"
  14. #include "BulletCollision/CollisionShapes/btConvexShape.h"
  15. #include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h"
  16. #include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h"
  17. #if defined(DEBUG) || defined (_DEBUG)
  18. //#define TEST_NON_VIRTUAL 1
  19. #include <stdio.h> //for debug printf
  20. #ifdef __SPU__
  21. #include <spu_printf.h>
  22. #define printf spu_printf
  23. //#define DEBUG_SPU_COLLISION_DETECTION 1
  24. #endif //__SPU__
  25. #endif
  26. //must be above the machine epsilon
  27. #define REL_ERROR2 btScalar(1.0e-6)
  28. //temp globals, to improve GJK/EPA/penetration calculations
  29. int gNumDeepPenetrationChecks = 0;
  30. int gNumGjkChecks = 0;
  31. btGjkPairDetector::btGjkPairDetector(const btConvexShape* objectA,const btConvexShape* objectB,btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver* penetrationDepthSolver)
  32. :m_cachedSeparatingAxis(btScalar(0.),btScalar(1.),btScalar(0.)),
  33. m_penetrationDepthSolver(penetrationDepthSolver),
  34. m_simplexSolver(simplexSolver),
  35. m_minkowskiA(objectA),
  36. m_minkowskiB(objectB),
  37. m_shapeTypeA(objectA->getShapeType()),
  38. m_shapeTypeB(objectB->getShapeType()),
  39. m_marginA(objectA->getMargin()),
  40. m_marginB(objectB->getMargin()),
  41. m_ignoreMargin(false),
  42. m_lastUsedMethod(-1),
  43. m_catchDegeneracies(1)
  44. {
  45. }
  46. btGjkPairDetector::btGjkPairDetector(const btConvexShape* objectA,const btConvexShape* objectB,int shapeTypeA,int shapeTypeB,btScalar marginA, btScalar marginB, btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver* penetrationDepthSolver)
  47. :m_cachedSeparatingAxis(btScalar(0.),btScalar(1.),btScalar(0.)),
  48. m_penetrationDepthSolver(penetrationDepthSolver),
  49. m_simplexSolver(simplexSolver),
  50. m_minkowskiA(objectA),
  51. m_minkowskiB(objectB),
  52. m_shapeTypeA(shapeTypeA),
  53. m_shapeTypeB(shapeTypeB),
  54. m_marginA(marginA),
  55. m_marginB(marginB),
  56. m_ignoreMargin(false),
  57. m_lastUsedMethod(-1),
  58. m_catchDegeneracies(1)
  59. {
  60. }
  61. void btGjkPairDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults)
  62. {
  63. (void)swapResults;
  64. getClosestPointsNonVirtual(input,output,debugDraw);
  65. }
  66. #ifdef __SPU__
  67. void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw)
  68. #else
  69. void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw)
  70. #endif
  71. {
  72. m_cachedSeparatingDistance = 0.f;
  73. btScalar distance=btScalar(0.);
  74. btVector3 normalInB(btScalar(0.),btScalar(0.),btScalar(0.));
  75. btVector3 pointOnA,pointOnB;
  76. btTransform localTransA = input.m_transformA;
  77. btTransform localTransB = input.m_transformB;
  78. btVector3 positionOffset = (localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5);
  79. localTransA.getOrigin() -= positionOffset;
  80. localTransB.getOrigin() -= positionOffset;
  81. bool check2d = m_minkowskiA->isConvex2d() && m_minkowskiB->isConvex2d();
  82. btScalar marginA = m_marginA;
  83. btScalar marginB = m_marginB;
  84. gNumGjkChecks++;
  85. #ifdef DEBUG_SPU_COLLISION_DETECTION
  86. spu_printf("inside gjk\n");
  87. #endif
  88. //for CCD we don't use margins
  89. if (m_ignoreMargin)
  90. {
  91. marginA = btScalar(0.);
  92. marginB = btScalar(0.);
  93. #ifdef DEBUG_SPU_COLLISION_DETECTION
  94. spu_printf("ignoring margin\n");
  95. #endif
  96. }
  97. m_curIter = 0;
  98. int gGjkMaxIter = 1000;//this is to catch invalid input, perhaps check for #NaN?
  99. m_cachedSeparatingAxis.setValue(0,1,0);
  100. bool isValid = false;
  101. bool checkSimplex = false;
  102. bool checkPenetration = true;
  103. m_degenerateSimplex = 0;
  104. m_lastUsedMethod = -1;
  105. {
  106. btScalar squaredDistance = BT_LARGE_FLOAT;
  107. btScalar delta = btScalar(0.);
  108. btScalar margin = marginA + marginB;
  109. m_simplexSolver->reset();
  110. for ( ; ; )
  111. //while (true)
  112. {
  113. btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* input.m_transformA.getBasis();
  114. btVector3 seperatingAxisInB = m_cachedSeparatingAxis* input.m_transformB.getBasis();
  115. #if 1
  116. btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
  117. btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
  118. // btVector3 pInA = localGetSupportingVertexWithoutMargin(m_shapeTypeA, m_minkowskiA, seperatingAxisInA,input.m_convexVertexData[0]);//, &featureIndexA);
  119. // btVector3 qInB = localGetSupportingVertexWithoutMargin(m_shapeTypeB, m_minkowskiB, seperatingAxisInB,input.m_convexVertexData[1]);//, &featureIndexB);
  120. #else
  121. #ifdef __SPU__
  122. btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
  123. btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
  124. #else
  125. btVector3 pInA = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
  126. btVector3 qInB = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
  127. #ifdef TEST_NON_VIRTUAL
  128. btVector3 pInAv = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
  129. btVector3 qInBv = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
  130. btAssert((pInAv-pInA).length() < 0.0001);
  131. btAssert((qInBv-qInB).length() < 0.0001);
  132. #endif //
  133. #endif //__SPU__
  134. #endif
  135. btVector3 pWorld = localTransA(pInA);
  136. btVector3 qWorld = localTransB(qInB);
  137. #ifdef DEBUG_SPU_COLLISION_DETECTION
  138. spu_printf("got local supporting vertices\n");
  139. #endif
  140. if (check2d)
  141. {
  142. pWorld[2] = 0.f;
  143. qWorld[2] = 0.f;
  144. }
  145. btVector3 w = pWorld - qWorld;
  146. delta = m_cachedSeparatingAxis.dot(w);
  147. // potential exit, they don't overlap
  148. if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * input.m_maximumDistanceSquared))
  149. {
  150. m_degenerateSimplex = 10;
  151. checkSimplex=true;
  152. //checkPenetration = false;
  153. break;
  154. }
  155. //exit 0: the new point is already in the simplex, or we didn't come any closer
  156. if (m_simplexSolver->inSimplex(w))
  157. {
  158. m_degenerateSimplex = 1;
  159. checkSimplex = true;
  160. break;
  161. }
  162. // are we getting any closer ?
  163. btScalar f0 = squaredDistance - delta;
  164. btScalar f1 = squaredDistance * REL_ERROR2;
  165. if (f0 <= f1)
  166. {
  167. if (f0 <= btScalar(0.))
  168. {
  169. m_degenerateSimplex = 2;
  170. } else
  171. {
  172. m_degenerateSimplex = 11;
  173. }
  174. checkSimplex = true;
  175. break;
  176. }
  177. #ifdef DEBUG_SPU_COLLISION_DETECTION
  178. spu_printf("addVertex 1\n");
  179. #endif
  180. //add current vertex to simplex
  181. m_simplexSolver->addVertex(w, pWorld, qWorld);
  182. #ifdef DEBUG_SPU_COLLISION_DETECTION
  183. spu_printf("addVertex 2\n");
  184. #endif
  185. btVector3 newCachedSeparatingAxis;
  186. //calculate the closest point to the origin (update vector v)
  187. if (!m_simplexSolver->closest(newCachedSeparatingAxis))
  188. {
  189. m_degenerateSimplex = 3;
  190. checkSimplex = true;
  191. break;
  192. }
  193. if(newCachedSeparatingAxis.length2()<REL_ERROR2)
  194. {
  195. m_cachedSeparatingAxis = newCachedSeparatingAxis;
  196. m_degenerateSimplex = 6;
  197. checkSimplex = true;
  198. break;
  199. }
  200. btScalar previousSquaredDistance = squaredDistance;
  201. squaredDistance = newCachedSeparatingAxis.length2();
  202. #if 0
  203. ///warning: this termination condition leads to some problems in 2d test case see Bullet/Demos/Box2dDemo
  204. if (squaredDistance>previousSquaredDistance)
  205. {
  206. m_degenerateSimplex = 7;
  207. squaredDistance = previousSquaredDistance;
  208. checkSimplex = false;
  209. break;
  210. }
  211. #endif //
  212. //redundant m_simplexSolver->compute_points(pointOnA, pointOnB);
  213. //are we getting any closer ?
  214. if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance)
  215. {
  216. // m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
  217. checkSimplex = true;
  218. m_degenerateSimplex = 12;
  219. break;
  220. }
  221. m_cachedSeparatingAxis = newCachedSeparatingAxis;
  222. //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject
  223. if (m_curIter++ > gGjkMaxIter)
  224. {
  225. #if defined(DEBUG) || defined (_DEBUG) || defined (DEBUG_SPU_COLLISION_DETECTION)
  226. printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter);
  227. printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",
  228. m_cachedSeparatingAxis.getX(),
  229. m_cachedSeparatingAxis.getY(),
  230. m_cachedSeparatingAxis.getZ(),
  231. squaredDistance,
  232. m_minkowskiA->getShapeType(),
  233. m_minkowskiB->getShapeType());
  234. #endif
  235. break;
  236. }
  237. bool check = (!m_simplexSolver->fullSimplex());
  238. //bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex());
  239. if (!check)
  240. {
  241. //do we need this backup_closest here ?
  242. // m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
  243. m_degenerateSimplex = 13;
  244. break;
  245. }
  246. }
  247. if (checkSimplex)
  248. {
  249. m_simplexSolver->compute_points(pointOnA, pointOnB);
  250. normalInB = m_cachedSeparatingAxis;
  251. btScalar lenSqr =m_cachedSeparatingAxis.length2();
  252. //valid normal
  253. if (lenSqr < 0.0001)
  254. {
  255. m_degenerateSimplex = 5;
  256. }
  257. if (lenSqr > SIMD_EPSILON*SIMD_EPSILON)
  258. {
  259. btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
  260. normalInB *= rlen; //normalize
  261. btScalar s = btSqrt(squaredDistance);
  262. btAssert(s > btScalar(0.0));
  263. pointOnA -= m_cachedSeparatingAxis * (marginA / s);
  264. pointOnB += m_cachedSeparatingAxis * (marginB / s);
  265. distance = ((btScalar(1.)/rlen) - margin);
  266. isValid = true;
  267. m_lastUsedMethod = 1;
  268. } else
  269. {
  270. m_lastUsedMethod = 2;
  271. }
  272. }
  273. bool catchDegeneratePenetrationCase =
  274. (m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < 0.01));
  275. //if (checkPenetration && !isValid)
  276. if (checkPenetration && (!isValid || catchDegeneratePenetrationCase ))
  277. {
  278. //penetration case
  279. //if there is no way to handle penetrations, bail out
  280. if (m_penetrationDepthSolver)
  281. {
  282. // Penetration depth case.
  283. btVector3 tmpPointOnA,tmpPointOnB;
  284. gNumDeepPenetrationChecks++;
  285. m_cachedSeparatingAxis.setZero();
  286. bool isValid2 = m_penetrationDepthSolver->calcPenDepth(
  287. *m_simplexSolver,
  288. m_minkowskiA,m_minkowskiB,
  289. localTransA,localTransB,
  290. m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB,
  291. debugDraw,input.m_stackAlloc
  292. );
  293. if (isValid2)
  294. {
  295. btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA;
  296. btScalar lenSqr = tmpNormalInB.length2();
  297. if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON))
  298. {
  299. tmpNormalInB = m_cachedSeparatingAxis;
  300. lenSqr = m_cachedSeparatingAxis.length2();
  301. }
  302. if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON))
  303. {
  304. tmpNormalInB /= btSqrt(lenSqr);
  305. btScalar distance2 = -(tmpPointOnA-tmpPointOnB).length();
  306. //only replace valid penetrations when the result is deeper (check)
  307. if (!isValid || (distance2 < distance))
  308. {
  309. distance = distance2;
  310. pointOnA = tmpPointOnA;
  311. pointOnB = tmpPointOnB;
  312. normalInB = tmpNormalInB;
  313. isValid = true;
  314. m_lastUsedMethod = 3;
  315. } else
  316. {
  317. m_lastUsedMethod = 8;
  318. }
  319. } else
  320. {
  321. m_lastUsedMethod = 9;
  322. }
  323. } else
  324. {
  325. ///this is another degenerate case, where the initial GJK calculation reports a degenerate case
  326. ///EPA reports no penetration, and the second GJK (using the supporting vector without margin)
  327. ///reports a valid positive distance. Use the results of the second GJK instead of failing.
  328. ///thanks to Jacob.Langford for the reproduction case
  329. ///http://code.google.com/p/bullet/issues/detail?id=250
  330. if (m_cachedSeparatingAxis.length2() > btScalar(0.))
  331. {
  332. btScalar distance2 = (tmpPointOnA-tmpPointOnB).length()-margin;
  333. //only replace valid distances when the distance is less
  334. if (!isValid || (distance2 < distance))
  335. {
  336. distance = distance2;
  337. pointOnA = tmpPointOnA;
  338. pointOnB = tmpPointOnB;
  339. pointOnA -= m_cachedSeparatingAxis * marginA ;
  340. pointOnB += m_cachedSeparatingAxis * marginB ;
  341. normalInB = m_cachedSeparatingAxis;
  342. normalInB.normalize();
  343. isValid = true;
  344. m_lastUsedMethod = 6;
  345. } else
  346. {
  347. m_lastUsedMethod = 5;
  348. }
  349. }
  350. }
  351. }
  352. }
  353. }
  354. if (isValid && ((distance < 0) || (distance*distance < input.m_maximumDistanceSquared)))
  355. {
  356. #if 0
  357. ///some debugging
  358. // if (check2d)
  359. {
  360. printf("n = %2.3f,%2.3f,%2.3f. ",normalInB[0],normalInB[1],normalInB[2]);
  361. printf("distance = %2.3f exit=%d deg=%d\n",distance,m_lastUsedMethod,m_degenerateSimplex);
  362. }
  363. #endif
  364. m_cachedSeparatingAxis = normalInB;
  365. m_cachedSeparatingDistance = distance;
  366. output.addContactPoint(
  367. normalInB,
  368. pointOnB+positionOffset,
  369. distance);
  370. }
  371. }