b2Distance.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*
  2. * Copyright (c) 2007 Erin Catto http://www.gphysics.com
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. * Permission is granted to anyone to use this software for any purpose,
  8. * including commercial applications, and to alter it and redistribute it
  9. * freely, subject to the following restrictions:
  10. * 1. The origin of this software must not be misrepresented; you must not
  11. * claim that you wrote the original software. If you use this software
  12. * in a product, an acknowledgment in the product documentation would be
  13. * appreciated but is not required.
  14. * 2. Altered source versions must be plainly marked as such, and must not be
  15. * misrepresented as being the original software.
  16. * 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "b2Collision.h"
  19. #include "Shapes/b2CircleShape.h"
  20. #include "Shapes/b2PolygonShape.h"
  21. #include "Shapes/b2EdgeShape.h"
  22. int32 g_GJK_Iterations = 0;
  23. // GJK using Voronoi regions (Christer Ericson) and region selection
  24. // optimizations (Casey Muratori).
  25. // The origin is either in the region of points[1] or in the edge region. The origin is
  26. // not in region of points[0] because that is the old point.
  27. static int32 ProcessTwo(b2Vec2* x1, b2Vec2* x2, b2Vec2* p1s, b2Vec2* p2s, b2Vec2* points)
  28. {
  29. // If in point[1] region
  30. b2Vec2 r = -points[1];
  31. b2Vec2 d = points[0] - points[1];
  32. float32 length = d.Normalize();
  33. float32 lambda = b2Dot(r, d);
  34. if (lambda <= 0.0f || length < B2_FLT_EPSILON)
  35. {
  36. // The simplex is reduced to a point.
  37. *x1 = p1s[1];
  38. *x2 = p2s[1];
  39. p1s[0] = p1s[1];
  40. p2s[0] = p2s[1];
  41. points[0] = points[1];
  42. return 1;
  43. }
  44. // Else in edge region
  45. lambda /= length;
  46. *x1 = p1s[1] + lambda * (p1s[0] - p1s[1]);
  47. *x2 = p2s[1] + lambda * (p2s[0] - p2s[1]);
  48. return 2;
  49. }
  50. // Possible regions:
  51. // - points[2]
  52. // - edge points[0]-points[2]
  53. // - edge points[1]-points[2]
  54. // - inside the triangle
  55. static int32 ProcessThree(b2Vec2* x1, b2Vec2* x2, b2Vec2* p1s, b2Vec2* p2s, b2Vec2* points)
  56. {
  57. b2Vec2 a = points[0];
  58. b2Vec2 b = points[1];
  59. b2Vec2 c = points[2];
  60. b2Vec2 ab = b - a;
  61. b2Vec2 ac = c - a;
  62. b2Vec2 bc = c - b;
  63. float32 sn = -b2Dot(a, ab), sd = b2Dot(b, ab);
  64. float32 tn = -b2Dot(a, ac), td = b2Dot(c, ac);
  65. float32 un = -b2Dot(b, bc), ud = b2Dot(c, bc);
  66. // In vertex c region?
  67. if (td <= 0.0f && ud <= 0.0f)
  68. {
  69. // Single point
  70. *x1 = p1s[2];
  71. *x2 = p2s[2];
  72. p1s[0] = p1s[2];
  73. p2s[0] = p2s[2];
  74. points[0] = points[2];
  75. return 1;
  76. }
  77. // Should not be in vertex a or b region.
  78. B2_NOT_USED(sd);
  79. B2_NOT_USED(sn);
  80. b2Assert(sn > 0.0f || tn > 0.0f);
  81. b2Assert(sd > 0.0f || un > 0.0f);
  82. float32 n = b2Cross(ab, ac);
  83. #ifdef TARGET_FLOAT32_IS_FIXED
  84. n = (n < 0.0)? -1.0 : ((n > 0.0)? 1.0 : 0.0);
  85. #endif
  86. // Should not be in edge ab region.
  87. float32 vc = n * b2Cross(a, b);
  88. b2Assert(vc > 0.0f || sn > 0.0f || sd > 0.0f);
  89. // In edge bc region?
  90. float32 va = n * b2Cross(b, c);
  91. if (va <= 0.0f && un >= 0.0f && ud >= 0.0f && (un+ud) > 0.0f)
  92. {
  93. b2Assert(un + ud > 0.0f);
  94. float32 lambda = un / (un + ud);
  95. *x1 = p1s[1] + lambda * (p1s[2] - p1s[1]);
  96. *x2 = p2s[1] + lambda * (p2s[2] - p2s[1]);
  97. p1s[0] = p1s[2];
  98. p2s[0] = p2s[2];
  99. points[0] = points[2];
  100. return 2;
  101. }
  102. // In edge ac region?
  103. float32 vb = n * b2Cross(c, a);
  104. if (vb <= 0.0f && tn >= 0.0f && td >= 0.0f && (tn+td) > 0.0f)
  105. {
  106. b2Assert(tn + td > 0.0f);
  107. float32 lambda = tn / (tn + td);
  108. *x1 = p1s[0] + lambda * (p1s[2] - p1s[0]);
  109. *x2 = p2s[0] + lambda * (p2s[2] - p2s[0]);
  110. p1s[1] = p1s[2];
  111. p2s[1] = p2s[2];
  112. points[1] = points[2];
  113. return 2;
  114. }
  115. // Inside the triangle, compute barycentric coordinates
  116. float32 denom = va + vb + vc;
  117. b2Assert(denom > 0.0f);
  118. denom = 1.0f / denom;
  119. #ifdef TARGET_FLOAT32_IS_FIXED
  120. *x1 = denom * (va * p1s[0] + vb * p1s[1] + vc * p1s[2]);
  121. *x2 = denom * (va * p2s[0] + vb * p2s[1] + vc * p2s[2]);
  122. #else
  123. float32 u = va * denom;
  124. float32 v = vb * denom;
  125. float32 w = 1.0f - u - v;
  126. *x1 = u * p1s[0] + v * p1s[1] + w * p1s[2];
  127. *x2 = u * p2s[0] + v * p2s[1] + w * p2s[2];
  128. #endif
  129. return 3;
  130. }
  131. static bool InPoints(const b2Vec2& w, const b2Vec2* points, int32 pointCount)
  132. {
  133. const float32 k_tolerance = 100.0f * B2_FLT_EPSILON;
  134. for (int32 i = 0; i < pointCount; ++i)
  135. {
  136. b2Vec2 d = b2Abs(w - points[i]);
  137. b2Vec2 m = b2Max(b2Abs(w), b2Abs(points[i]));
  138. if (d.x < k_tolerance * (m.x + 1.0f) &&
  139. d.y < k_tolerance * (m.y + 1.0f))
  140. {
  141. return true;
  142. }
  143. }
  144. return false;
  145. }
  146. template <typename T1, typename T2>
  147. float32 DistanceGeneric(b2Vec2* x1, b2Vec2* x2,
  148. const T1* shape1, const b2XForm& xf1,
  149. const T2* shape2, const b2XForm& xf2)
  150. {
  151. b2Vec2 p1s[3], p2s[3];
  152. b2Vec2 points[3];
  153. int32 pointCount = 0;
  154. *x1 = shape1->GetFirstVertex(xf1);
  155. *x2 = shape2->GetFirstVertex(xf2);
  156. float32 vSqr = 0.0f;
  157. const int32 maxIterations = 20;
  158. for (int32 iter = 0; iter < maxIterations; ++iter)
  159. {
  160. b2Vec2 v = *x2 - *x1;
  161. b2Vec2 w1 = shape1->Support(xf1, v);
  162. b2Vec2 w2 = shape2->Support(xf2, -v);
  163. vSqr = b2Dot(v, v);
  164. b2Vec2 w = w2 - w1;
  165. float32 vw = b2Dot(v, w);
  166. if (vSqr - vw <= 0.01f * vSqr || InPoints(w, points, pointCount)) // or w in points
  167. {
  168. if (pointCount == 0)
  169. {
  170. *x1 = w1;
  171. *x2 = w2;
  172. }
  173. g_GJK_Iterations = iter;
  174. return b2Sqrt(vSqr);
  175. }
  176. switch (pointCount)
  177. {
  178. case 0:
  179. p1s[0] = w1;
  180. p2s[0] = w2;
  181. points[0] = w;
  182. *x1 = p1s[0];
  183. *x2 = p2s[0];
  184. ++pointCount;
  185. break;
  186. case 1:
  187. p1s[1] = w1;
  188. p2s[1] = w2;
  189. points[1] = w;
  190. pointCount = ProcessTwo(x1, x2, p1s, p2s, points);
  191. break;
  192. case 2:
  193. p1s[2] = w1;
  194. p2s[2] = w2;
  195. points[2] = w;
  196. pointCount = ProcessThree(x1, x2, p1s, p2s, points);
  197. break;
  198. }
  199. // If we have three points, then the origin is in the corresponding triangle.
  200. if (pointCount == 3)
  201. {
  202. g_GJK_Iterations = iter;
  203. return 0.0f;
  204. }
  205. float32 maxSqr = -B2_FLT_MAX;
  206. for (int32 i = 0; i < pointCount; ++i)
  207. {
  208. maxSqr = b2Max(maxSqr, b2Dot(points[i], points[i]));
  209. }
  210. #ifdef TARGET_FLOAT32_IS_FIXED
  211. if (pointCount == 3 || vSqr <= 5.0*B2_FLT_EPSILON * maxSqr)
  212. #else
  213. if (vSqr <= 100.0f * B2_FLT_EPSILON * maxSqr)
  214. #endif
  215. {
  216. g_GJK_Iterations = iter;
  217. v = *x2 - *x1;
  218. vSqr = b2Dot(v, v);
  219. return b2Sqrt(vSqr);
  220. }
  221. }
  222. g_GJK_Iterations = maxIterations;
  223. return b2Sqrt(vSqr);
  224. }
  225. static float32 DistanceCC(
  226. b2Vec2* x1, b2Vec2* x2,
  227. const b2CircleShape* circle1, const b2XForm& xf1,
  228. const b2CircleShape* circle2, const b2XForm& xf2)
  229. {
  230. b2Vec2 p1 = b2Mul(xf1, circle1->GetLocalPosition());
  231. b2Vec2 p2 = b2Mul(xf2, circle2->GetLocalPosition());
  232. b2Vec2 d = p2 - p1;
  233. float32 dSqr = b2Dot(d, d);
  234. float32 r1 = circle1->GetRadius() - b2_toiSlop;
  235. float32 r2 = circle2->GetRadius() - b2_toiSlop;
  236. float32 r = r1 + r2;
  237. if (dSqr > r * r)
  238. {
  239. float32 dLen = d.Normalize();
  240. float32 distance = dLen - r;
  241. *x1 = p1 + r1 * d;
  242. *x2 = p2 - r2 * d;
  243. return distance;
  244. }
  245. else if (dSqr > B2_FLT_EPSILON * B2_FLT_EPSILON)
  246. {
  247. d.Normalize();
  248. *x1 = p1 + r1 * d;
  249. *x2 = *x1;
  250. return 0.0f;
  251. }
  252. *x1 = p1;
  253. *x2 = *x1;
  254. return 0.0f;
  255. }
  256. static float32 DistanceEdgeCircle(
  257. b2Vec2* x1, b2Vec2* x2,
  258. const b2EdgeShape* edge, const b2XForm& xf1,
  259. const b2CircleShape* circle, const b2XForm& xf2)
  260. {
  261. b2Vec2 vWorld;
  262. b2Vec2 d;
  263. float32 dSqr;
  264. float32 dLen;
  265. float32 r = circle->GetRadius() - b2_toiSlop;
  266. b2Vec2 cWorld = b2Mul(xf2, circle->GetLocalPosition());
  267. b2Vec2 cLocal = b2MulT(xf1, cWorld);
  268. float32 dirDist = b2Dot(cLocal - edge->GetCoreVertex1(), edge->GetDirectionVector());
  269. if (dirDist <= 0.0f) {
  270. vWorld = b2Mul(xf1, edge->GetCoreVertex1());
  271. } else if (dirDist >= edge->GetLength()) {
  272. vWorld = b2Mul(xf1, edge->GetCoreVertex2());
  273. } else {
  274. *x1 = b2Mul(xf1, edge->GetCoreVertex1() + dirDist * edge->GetDirectionVector());
  275. dLen = b2Dot(cLocal - edge->GetCoreVertex1(), edge->GetNormalVector());
  276. if (dLen < 0.0f) {
  277. if (dLen < -r) {
  278. *x2 = b2Mul(xf1, cLocal + r * edge->GetNormalVector());
  279. return -dLen - r;
  280. } else {
  281. *x2 = *x1;
  282. return 0.0f;
  283. }
  284. } else {
  285. if (dLen > r) {
  286. *x2 = b2Mul(xf1, cLocal - r * edge->GetNormalVector());
  287. return dLen - r;
  288. } else {
  289. *x2 = *x1;
  290. return 0.0f;
  291. }
  292. }
  293. }
  294. *x1 = vWorld;
  295. d = cWorld - vWorld;
  296. dSqr = b2Dot(d, d);
  297. if (dSqr > r * r) {
  298. dLen = d.Normalize();
  299. *x2 = cWorld - r * d;
  300. return dLen - r;
  301. } else {
  302. *x2 = vWorld;
  303. return 0.0f;
  304. }
  305. }
  306. // This is used for polygon-vs-circle distance.
  307. struct Point
  308. {
  309. b2Vec2 Support(const b2XForm&, const b2Vec2&) const
  310. {
  311. return p;
  312. }
  313. b2Vec2 GetFirstVertex(const b2XForm&) const
  314. {
  315. return p;
  316. }
  317. b2Vec2 p;
  318. };
  319. // GJK is more robust with polygon-vs-point than polygon-vs-circle.
  320. // So we convert polygon-vs-circle to polygon-vs-point.
  321. static float32 DistancePC(
  322. b2Vec2* x1, b2Vec2* x2,
  323. const b2PolygonShape* polygon, const b2XForm& xf1,
  324. const b2CircleShape* circle, const b2XForm& xf2)
  325. {
  326. Point point;
  327. point.p = b2Mul(xf2, circle->GetLocalPosition());
  328. float32 distance = DistanceGeneric(x1, x2, polygon, xf1, &point, b2XForm_identity);
  329. float32 r = circle->GetRadius() - b2_toiSlop;
  330. if (distance > r)
  331. {
  332. distance -= r;
  333. b2Vec2 d = *x2 - *x1;
  334. d.Normalize();
  335. *x2 -= r * d;
  336. }
  337. else
  338. {
  339. distance = 0.0f;
  340. *x2 = *x1;
  341. }
  342. return distance;
  343. }
  344. float32 b2Distance(b2Vec2* x1, b2Vec2* x2,
  345. const b2Shape* shape1, const b2XForm& xf1,
  346. const b2Shape* shape2, const b2XForm& xf2)
  347. {
  348. b2ShapeType type1 = shape1->GetType();
  349. b2ShapeType type2 = shape2->GetType();
  350. if (type1 == e_circleShape && type2 == e_circleShape)
  351. {
  352. return DistanceCC(x1, x2, (b2CircleShape*)shape1, xf1, (b2CircleShape*)shape2, xf2);
  353. }
  354. if (type1 == e_polygonShape && type2 == e_circleShape)
  355. {
  356. return DistancePC(x1, x2, (b2PolygonShape*)shape1, xf1, (b2CircleShape*)shape2, xf2);
  357. }
  358. if (type1 == e_circleShape && type2 == e_polygonShape)
  359. {
  360. return DistancePC(x2, x1, (b2PolygonShape*)shape2, xf2, (b2CircleShape*)shape1, xf1);
  361. }
  362. if (type1 == e_polygonShape && type2 == e_polygonShape)
  363. {
  364. return DistanceGeneric(x1, x2, (b2PolygonShape*)shape1, xf1, (b2PolygonShape*)shape2, xf2);
  365. }
  366. if (type1 == e_edgeShape && type2 == e_circleShape)
  367. {
  368. return DistanceEdgeCircle(x1, x2, (b2EdgeShape*)shape1, xf1, (b2CircleShape*)shape2, xf2);
  369. }
  370. if (type1 == e_circleShape && type2 == e_edgeShape)
  371. {
  372. return DistanceEdgeCircle(x2, x1, (b2EdgeShape*)shape2, xf2, (b2CircleShape*)shape1, xf1);
  373. }
  374. if (type1 == e_polygonShape && type2 == e_edgeShape)
  375. {
  376. return DistanceGeneric(x2, x1, (b2EdgeShape*)shape2, xf2, (b2PolygonShape*)shape1, xf1);
  377. }
  378. if (type1 == e_edgeShape && type2 == e_polygonShape)
  379. {
  380. return DistanceGeneric(x1, x2, (b2EdgeShape*)shape1, xf1, (b2PolygonShape*)shape2, xf2);
  381. }
  382. return 0.0f;
  383. }