/js/box2d/collision/b2Distance.js

https://github.com/coderchrismills/JSGameTest2D · JavaScript · 333 lines · 184 code · 35 blank · 114 comment · 26 complexity · 4a439ba981e8a97c0fc6d7b723762d7a MD5 · raw file

  1. /*
  2. * Copyright (c) 2006-2007 Erin Catto http:
  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, and must not be
  15. * misrepresented the original software.
  16. * 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. var b2Distance = Class.create();
  19. b2Distance.prototype =
  20. {
  21. // GJK using Voronoi regions (Christer Ericson) and region selection
  22. // optimizations (Casey Muratori).
  23. // The origin is either in the region of points[1] or in the edge region. The origin is
  24. // not in region of points[0] because that is the old point.
  25. // Possible regions:
  26. // - points[2]
  27. // - edge points[0]-points[2]
  28. // - edge points[1]-points[2]
  29. // - inside the triangle
  30. initialize: function() {}};
  31. b2Distance.ProcessTwo = function(p1Out, p2Out, p1s, p2s, points)
  32. {
  33. // If in point[1] region
  34. //b2Vec2 r = -points[1];
  35. var rX = -points[1].x;
  36. var rY = -points[1].y;
  37. //b2Vec2 d = points[1] - points[0];
  38. var dX = points[0].x - points[1].x;
  39. var dY = points[0].y - points[1].y;
  40. //float32 length = d.Normalize();
  41. var length = Math.sqrt(dX*dX + dY*dY);
  42. dX /= length;
  43. dY /= length;
  44. //float32 lambda = b2Dot(r, d);
  45. var lambda = rX * dX + rY * dY;
  46. if (lambda <= 0.0 || length < Number.MIN_VALUE)
  47. {
  48. // The simplex is reduced to a point.
  49. //*p1Out = p1s[1];
  50. p1Out.SetV(p1s[1]);
  51. //*p2Out = p2s[1];
  52. p2Out.SetV(p2s[1]);
  53. //p1s[0] = p1s[1];
  54. p1s[0].SetV(p1s[1]);
  55. //p2s[0] = p2s[1];
  56. p2s[0].SetV(p2s[1]);
  57. points[0].SetV(points[1]);
  58. return 1;
  59. }
  60. // Else in edge region
  61. lambda /= length;
  62. //*p1Out = p1s[1] + lambda * (p1s[0] - p1s[1]);
  63. p1Out.x = p1s[1].x + lambda * (p1s[0].x - p1s[1].x);
  64. p1Out.y = p1s[1].y + lambda * (p1s[0].y - p1s[1].y);
  65. //*p2Out = p2s[1] + lambda * (p2s[0] - p2s[1]);
  66. p2Out.x = p2s[1].x + lambda * (p2s[0].x - p2s[1].x);
  67. p2Out.y = p2s[1].y + lambda * (p2s[0].y - p2s[1].y);
  68. return 2;
  69. };
  70. b2Distance.ProcessThree = function(p1Out, p2Out, p1s, p2s, points)
  71. {
  72. //b2Vec2 a = points[0];
  73. var aX = points[0].x;
  74. var aY = points[0].y;
  75. //b2Vec2 b = points[1];
  76. var bX = points[1].x;
  77. var bY = points[1].y;
  78. //b2Vec2 c = points[2];
  79. var cX = points[2].x;
  80. var cY = points[2].y;
  81. //b2Vec2 ab = b - a;
  82. var abX = bX - aX;
  83. var abY = bY - aY;
  84. //b2Vec2 ac = c - a;
  85. var acX = cX - aX;
  86. var acY = cY - aY;
  87. //b2Vec2 bc = c - b;
  88. var bcX = cX - bX;
  89. var bcY = cY - bY;
  90. //float32 sn = -b2Dot(a, ab), sd = b2Dot(b, ab);
  91. var sn = -(aX * abX + aY * abY);
  92. var sd = (bX * abX + bY * abY);
  93. //float32 tn = -b2Dot(a, ac), td = b2Dot(c, ac);
  94. var tn = -(aX * acX + aY * acY);
  95. var td = (cX * acX + cY * acY);
  96. //float32 un = -b2Dot(b, bc), ud = b2Dot(c, bc);
  97. var un = -(bX * bcX + bY * bcY);
  98. var ud = (cX * bcX + cY * bcY);
  99. // In vertex c region?
  100. if (td <= 0.0 && ud <= 0.0)
  101. {
  102. // Single point
  103. //*p1Out = p1s[2];
  104. p1Out.SetV(p1s[2]);
  105. //*p2Out = p2s[2];
  106. p2Out.SetV(p2s[2]);
  107. //p1s[0] = p1s[2];
  108. p1s[0].SetV(p1s[2]);
  109. //p2s[0] = p2s[2];
  110. p2s[0].SetV(p2s[2]);
  111. points[0].SetV(points[2]);
  112. return 1;
  113. }
  114. // Should not be in vertex a or b region.
  115. //b2Settings.b2Assert(sn > 0.0 || tn > 0.0);
  116. //b2Settings.b2Assert(sd > 0.0 || un > 0.0);
  117. //float32 n = b2Cross(ab, ac);
  118. var n = abX * acY - abY * acX;
  119. // Should not be in edge ab region.
  120. //float32 vc = n * b2Cross(a, b);
  121. var vc = n * (aX * bY - aY * bX);
  122. //b2Settings.b2Assert(vc > 0.0 || sn > 0.0 || sd > 0.0);
  123. // In edge bc region?
  124. //float32 va = n * b2Cross(b, c);
  125. var va = n * (bX * cY - bY * cX);
  126. if (va <= 0.0 && un >= 0.0 && ud >= 0.0)
  127. {
  128. //b2Settings.b2Assert(un + ud > 0.0);
  129. //float32 lambda = un / (un + ud);
  130. var lambda = un / (un + ud);
  131. //*p1Out = p1s[1] + lambda * (p1s[2] - p1s[1]);
  132. p1Out.x = p1s[1].x + lambda * (p1s[2].x - p1s[1].x);
  133. p1Out.y = p1s[1].y + lambda * (p1s[2].y - p1s[1].y);
  134. //*p2Out = p2s[1] + lambda * (p2s[2] - p2s[1]);
  135. p2Out.x = p2s[1].x + lambda * (p2s[2].x - p2s[1].x);
  136. p2Out.y = p2s[1].y + lambda * (p2s[2].y - p2s[1].y);
  137. //p1s[0] = p1s[2];
  138. p1s[0].SetV(p1s[2]);
  139. //p2s[0] = p2s[2];
  140. p2s[0].SetV(p2s[2]);
  141. //points[0] = points[2];
  142. points[0].SetV(points[2]);
  143. return 2;
  144. }
  145. // In edge ac region?
  146. //float32 vb = n * b2Cross(c, a);
  147. var vb = n * (cX * aY - cY * aX);
  148. if (vb <= 0.0 && tn >= 0.0 && td >= 0.0)
  149. {
  150. //b2Settings.b2Assert(tn + td > 0.0);
  151. //float32 lambda = tn / (tn + td);
  152. var lambda = tn / (tn + td);
  153. //*p1Out = p1s[0] + lambda * (p1s[2] - p1s[0]);
  154. p1Out.x = p1s[0].x + lambda * (p1s[2].x - p1s[0].x);
  155. p1Out.y = p1s[0].y + lambda * (p1s[2].y - p1s[0].y);
  156. //*p2Out = p2s[0] + lambda * (p2s[2] - p2s[0]);
  157. p2Out.x = p2s[0].x + lambda * (p2s[2].x - p2s[0].x);
  158. p2Out.y = p2s[0].y + lambda * (p2s[2].y - p2s[0].y);
  159. //p1s[1] = p1s[2];
  160. p1s[1].SetV(p1s[2]);
  161. //p2s[1] = p2s[2];
  162. p2s[1].SetV(p2s[2]);
  163. //points[1] = points[2];
  164. points[1].SetV(points[2]);
  165. return 2;
  166. }
  167. // Inside the triangle, compute barycentric coordinates
  168. //float32 denom = va + vb + vc;
  169. var denom = va + vb + vc;
  170. //b2Settings.b2Assert(denom > 0.0);
  171. denom = 1.0 / denom;
  172. //float32 u = va * denom;
  173. var u = va * denom;
  174. //float32 v = vb * denom;
  175. var v = vb * denom;
  176. //float32 w = 1.0f - u - v;
  177. var w = 1.0 - u - v;
  178. //*p1Out = u * p1s[0] + v * p1s[1] + w * p1s[2];
  179. p1Out.x = u * p1s[0].x + v * p1s[1].x + w * p1s[2].x;
  180. p1Out.y = u * p1s[0].y + v * p1s[1].y + w * p1s[2].y;
  181. //*p2Out = u * p2s[0] + v * p2s[1] + w * p2s[2];
  182. p2Out.x = u * p2s[0].x + v * p2s[1].x + w * p2s[2].x;
  183. p2Out.y = u * p2s[0].y + v * p2s[1].y + w * p2s[2].y;
  184. return 3;
  185. };
  186. b2Distance.InPoinsts = function(w, points, pointCount)
  187. {
  188. for (var i = 0; i < pointCount; ++i)
  189. {
  190. if (w.x == points[i].x && w.y == points[i].y)
  191. {
  192. return true;
  193. }
  194. }
  195. return false;
  196. };
  197. b2Distance.Distance = function(p1Out, p2Out, shape1, shape2)
  198. {
  199. //b2Vec2 p1s[3], p2s[3];
  200. var p1s = new Array(3);
  201. var p2s = new Array(3);
  202. //b2Vec2 points[3];
  203. var points = new Array(3);
  204. //int32 pointCount = 0;
  205. var pointCount = 0;
  206. //*p1Out = shape1->m_position;
  207. p1Out.SetV(shape1.m_position);
  208. //*p2Out = shape2->m_position;
  209. p2Out.SetV(shape2.m_position);
  210. var vSqr = 0.0;
  211. var maxIterations = 20;
  212. for (var iter = 0; iter < maxIterations; ++iter)
  213. {
  214. //b2Vec2 v = *p2Out - *p1Out;
  215. var vX = p2Out.x - p1Out.x;
  216. var vY = p2Out.y - p1Out.y;
  217. //b2Vec2 w1 = shape1->Support(v);
  218. var w1 = shape1.Support(vX, vY);
  219. //b2Vec2 w2 = shape2->Support(-v);
  220. var w2 = shape2.Support(-vX, -vY);
  221. //float32 vSqr = b2Dot(v, v);
  222. vSqr = (vX*vX + vY*vY);
  223. //b2Vec2 w = w2 - w1;
  224. var wX = w2.x - w1.x;
  225. var wY = w2.y - w1.y;
  226. //float32 vw = b2Dot(v, w);
  227. var vw = (vX*wX + vY*wY);
  228. //if (vSqr - b2Dot(v, w) <= 0.01f * vSqr)
  229. if (vSqr - b2Dot(vX * wX + vY * wY) <= 0.01 * vSqr)
  230. {
  231. if (pointCount == 0)
  232. {
  233. //*p1Out = w1;
  234. p1Out.SetV(w1);
  235. //*p2Out = w2;
  236. p2Out.SetV(w2);
  237. }
  238. b2Distance.g_GJK_Iterations = iter;
  239. return Math.sqrt(vSqr);
  240. }
  241. switch (pointCount)
  242. {
  243. case 0:
  244. //p1s[0] = w1;
  245. p1s[0].SetV(w1);
  246. //p2s[0] = w2;
  247. p2s[0].SetV(w2);
  248. points[0] = w;
  249. //*p1Out = p1s[0];
  250. p1Out.SetV(p1s[0]);
  251. //*p2Out = p2s[0];
  252. p2Out.SetV(p2s[0]);
  253. ++pointCount;
  254. break;
  255. case 1:
  256. //p1s[1] = w1;
  257. p1s[1].SetV(w1);
  258. //p2s[1] = w2;
  259. p2s[1].SetV(w2);
  260. //points[1] = w;
  261. points[1].x = wX;
  262. points[1].y = wY;
  263. pointCount = b2Distance.ProcessTwo(p1Out, p2Out, p1s, p2s, points);
  264. break;
  265. case 2:
  266. //p1s[2] = w1;
  267. p1s[2].SetV(w1);
  268. //p2s[2] = w2;
  269. p2s[2].SetV(w2);
  270. //points[2] = w;
  271. points[2].x = wX;
  272. points[2].y = wY;
  273. pointCount = b2Distance.ProcessThree(p1Out, p2Out, p1s, p2s, points);
  274. break;
  275. }
  276. // If we have three points, then the origin is in the corresponding triangle.
  277. if (pointCount == 3)
  278. {
  279. b2Distance.g_GJK_Iterations = iter;
  280. return 0.0;
  281. }
  282. //float32 maxSqr = -FLT_MAX;
  283. var maxSqr = -Number.MAX_VALUE;
  284. for (var i = 0; i < pointCount; ++i)
  285. {
  286. //maxSqr = b2Math.b2Max(maxSqr, b2Dot(points[i], points[i]));
  287. maxSqr = b2Math.b2Max(maxSqr, (points[i].x*points[i].x + points[i].y*points[i].y));
  288. }
  289. if (pointCount == 3 || vSqr <= 100.0 * Number.MIN_VALUE * maxSqr)
  290. {
  291. b2Distance.g_GJK_Iterations = iter;
  292. return Math.sqrt(vSqr);
  293. }
  294. }
  295. b2Distance.g_GJK_Iterations = maxIterations;
  296. return Math.sqrt(vSqr);
  297. };
  298. b2Distance.g_GJK_Iterations = 0;