b2Collision.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
  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 <Box2D/Collision/b2Collision.h>
  19. #include <Box2D/Collision/b2Distance.h>
  20. void b2WorldManifold::Initialize(const b2Manifold* manifold,
  21. const b2Transform& xfA, float32 radiusA,
  22. const b2Transform& xfB, float32 radiusB)
  23. {
  24. if (manifold->pointCount == 0)
  25. {
  26. return;
  27. }
  28. switch (manifold->type)
  29. {
  30. case b2Manifold::e_circles:
  31. {
  32. normal.Set(1.0f, 0.0f);
  33. b2Vec2 pointA = b2Mul(xfA, manifold->localPoint);
  34. b2Vec2 pointB = b2Mul(xfB, manifold->points[0].localPoint);
  35. if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon)
  36. {
  37. normal = pointB - pointA;
  38. normal.Normalize();
  39. }
  40. b2Vec2 cA = pointA + radiusA * normal;
  41. b2Vec2 cB = pointB - radiusB * normal;
  42. points[0] = 0.5f * (cA + cB);
  43. separations[0] = b2Dot(cB - cA, normal);
  44. }
  45. break;
  46. case b2Manifold::e_faceA:
  47. {
  48. normal = b2Mul(xfA.q, manifold->localNormal);
  49. b2Vec2 planePoint = b2Mul(xfA, manifold->localPoint);
  50. for (int32 i = 0; i < manifold->pointCount; ++i)
  51. {
  52. b2Vec2 clipPoint = b2Mul(xfB, manifold->points[i].localPoint);
  53. b2Vec2 cA = clipPoint + (radiusA - b2Dot(clipPoint - planePoint, normal)) * normal;
  54. b2Vec2 cB = clipPoint - radiusB * normal;
  55. points[i] = 0.5f * (cA + cB);
  56. separations[i] = b2Dot(cB - cA, normal);
  57. }
  58. }
  59. break;
  60. case b2Manifold::e_faceB:
  61. {
  62. normal = b2Mul(xfB.q, manifold->localNormal);
  63. b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint);
  64. for (int32 i = 0; i < manifold->pointCount; ++i)
  65. {
  66. b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint);
  67. b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal;
  68. b2Vec2 cA = clipPoint - radiusA * normal;
  69. points[i] = 0.5f * (cA + cB);
  70. separations[i] = b2Dot(cA - cB, normal);
  71. }
  72. // Ensure normal points from A to B.
  73. normal = -normal;
  74. }
  75. break;
  76. }
  77. }
  78. void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
  79. const b2Manifold* manifold1, const b2Manifold* manifold2)
  80. {
  81. for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
  82. {
  83. state1[i] = b2_nullState;
  84. state2[i] = b2_nullState;
  85. }
  86. // Detect persists and removes.
  87. for (int32 i = 0; i < manifold1->pointCount; ++i)
  88. {
  89. b2ContactID id = manifold1->points[i].id;
  90. state1[i] = b2_removeState;
  91. for (int32 j = 0; j < manifold2->pointCount; ++j)
  92. {
  93. if (manifold2->points[j].id.key == id.key)
  94. {
  95. state1[i] = b2_persistState;
  96. break;
  97. }
  98. }
  99. }
  100. // Detect persists and adds.
  101. for (int32 i = 0; i < manifold2->pointCount; ++i)
  102. {
  103. b2ContactID id = manifold2->points[i].id;
  104. state2[i] = b2_addState;
  105. for (int32 j = 0; j < manifold1->pointCount; ++j)
  106. {
  107. if (manifold1->points[j].id.key == id.key)
  108. {
  109. state2[i] = b2_persistState;
  110. break;
  111. }
  112. }
  113. }
  114. }
  115. // From Real-time Collision Detection, p179.
  116. bool b2AABB::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const
  117. {
  118. float32 tmin = -b2_maxFloat;
  119. float32 tmax = b2_maxFloat;
  120. b2Vec2 p = input.p1;
  121. b2Vec2 d = input.p2 - input.p1;
  122. b2Vec2 absD = b2Abs(d);
  123. b2Vec2 normal;
  124. for (int32 i = 0; i < 2; ++i)
  125. {
  126. if (absD(i) < b2_epsilon)
  127. {
  128. // Parallel.
  129. if (p(i) < lowerBound(i) || upperBound(i) < p(i))
  130. {
  131. return false;
  132. }
  133. }
  134. else
  135. {
  136. float32 inv_d = 1.0f / d(i);
  137. float32 t1 = (lowerBound(i) - p(i)) * inv_d;
  138. float32 t2 = (upperBound(i) - p(i)) * inv_d;
  139. // Sign of the normal vector.
  140. float32 s = -1.0f;
  141. if (t1 > t2)
  142. {
  143. b2Swap(t1, t2);
  144. s = 1.0f;
  145. }
  146. // Push the min up
  147. if (t1 > tmin)
  148. {
  149. normal.SetZero();
  150. normal(i) = s;
  151. tmin = t1;
  152. }
  153. // Pull the max down
  154. tmax = b2Min(tmax, t2);
  155. if (tmin > tmax)
  156. {
  157. return false;
  158. }
  159. }
  160. }
  161. // Does the ray start inside the box?
  162. // Does the ray intersect beyond the max fraction?
  163. if (tmin < 0.0f || input.maxFraction < tmin)
  164. {
  165. return false;
  166. }
  167. // Intersection.
  168. output->fraction = tmin;
  169. output->normal = normal;
  170. return true;
  171. }
  172. // Sutherland-Hodgman clipping.
  173. int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
  174. const b2Vec2& normal, float32 offset, int32 vertexIndexA)
  175. {
  176. // Start with no output points
  177. int32 numOut = 0;
  178. // Calculate the distance of end points to the line
  179. float32 distance0 = b2Dot(normal, vIn[0].v) - offset;
  180. float32 distance1 = b2Dot(normal, vIn[1].v) - offset;
  181. // If the points are behind the plane
  182. if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];
  183. if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];
  184. // If the points are on different sides of the plane
  185. if (distance0 * distance1 < 0.0f)
  186. {
  187. // Find intersection point of edge and plane
  188. float32 interp = distance0 / (distance0 - distance1);
  189. vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);
  190. // VertexA is hitting edgeB.
  191. vOut[numOut].id.cf.indexA = static_cast<uint8>(vertexIndexA);
  192. vOut[numOut].id.cf.indexB = vIn[0].id.cf.indexB;
  193. vOut[numOut].id.cf.typeA = b2ContactFeature::e_vertex;
  194. vOut[numOut].id.cf.typeB = b2ContactFeature::e_face;
  195. ++numOut;
  196. }
  197. return numOut;
  198. }
  199. bool b2TestOverlap( const b2Shape* shapeA, int32 indexA,
  200. const b2Shape* shapeB, int32 indexB,
  201. const b2Transform& xfA, const b2Transform& xfB)
  202. {
  203. b2DistanceInput input;
  204. input.proxyA.Set(shapeA, indexA);
  205. input.proxyB.Set(shapeB, indexB);
  206. input.transformA = xfA;
  207. input.transformB = xfB;
  208. input.useRadii = true;
  209. b2SimplexCache cache;
  210. cache.count = 0;
  211. b2DistanceOutput output;
  212. b2Distance(&output, &cache, &input);
  213. return output.distance < 10.0f * b2_epsilon;
  214. }