b2CollidePolygon.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * Copyright (c) 2006-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/Shapes/b2PolygonShape.h>
  20. // Find the max separation between poly1 and poly2 using edge normals from poly1.
  21. static float32 b2FindMaxSeparation(int32* edgeIndex,
  22. const b2PolygonShape* poly1, const b2Transform& xf1,
  23. const b2PolygonShape* poly2, const b2Transform& xf2)
  24. {
  25. int32 count1 = poly1->m_count;
  26. int32 count2 = poly2->m_count;
  27. const b2Vec2* n1s = poly1->m_normals;
  28. const b2Vec2* v1s = poly1->m_vertices;
  29. const b2Vec2* v2s = poly2->m_vertices;
  30. b2Transform xf = b2MulT(xf2, xf1);
  31. int32 bestIndex = 0;
  32. float32 maxSeparation = -b2_maxFloat;
  33. for (int32 i = 0; i < count1; ++i)
  34. {
  35. // Get poly1 normal in frame2.
  36. b2Vec2 n = b2Mul(xf.q, n1s[i]);
  37. b2Vec2 v1 = b2Mul(xf, v1s[i]);
  38. // Find deepest point for normal i.
  39. float32 si = b2_maxFloat;
  40. for (int32 j = 0; j < count2; ++j)
  41. {
  42. float32 sij = b2Dot(n, v2s[j] - v1);
  43. if (sij < si)
  44. {
  45. si = sij;
  46. }
  47. }
  48. if (si > maxSeparation)
  49. {
  50. maxSeparation = si;
  51. bestIndex = i;
  52. }
  53. }
  54. *edgeIndex = bestIndex;
  55. return maxSeparation;
  56. }
  57. static void b2FindIncidentEdge(b2ClipVertex c[2],
  58. const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,
  59. const b2PolygonShape* poly2, const b2Transform& xf2)
  60. {
  61. const b2Vec2* normals1 = poly1->m_normals;
  62. int32 count2 = poly2->m_count;
  63. const b2Vec2* vertices2 = poly2->m_vertices;
  64. const b2Vec2* normals2 = poly2->m_normals;
  65. b2Assert(0 <= edge1 && edge1 < poly1->m_count);
  66. // Get the normal of the reference edge in poly2's frame.
  67. b2Vec2 normal1 = b2MulT(xf2.q, b2Mul(xf1.q, normals1[edge1]));
  68. // Find the incident edge on poly2.
  69. int32 index = 0;
  70. float32 minDot = b2_maxFloat;
  71. for (int32 i = 0; i < count2; ++i)
  72. {
  73. float32 dot = b2Dot(normal1, normals2[i]);
  74. if (dot < minDot)
  75. {
  76. minDot = dot;
  77. index = i;
  78. }
  79. }
  80. // Build the clip vertices for the incident edge.
  81. int32 i1 = index;
  82. int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0;
  83. c[0].v = b2Mul(xf2, vertices2[i1]);
  84. c[0].id.cf.indexA = (uint8)edge1;
  85. c[0].id.cf.indexB = (uint8)i1;
  86. c[0].id.cf.typeA = b2ContactFeature::e_face;
  87. c[0].id.cf.typeB = b2ContactFeature::e_vertex;
  88. c[1].v = b2Mul(xf2, vertices2[i2]);
  89. c[1].id.cf.indexA = (uint8)edge1;
  90. c[1].id.cf.indexB = (uint8)i2;
  91. c[1].id.cf.typeA = b2ContactFeature::e_face;
  92. c[1].id.cf.typeB = b2ContactFeature::e_vertex;
  93. }
  94. // Find edge normal of max separation on A - return if separating axis is found
  95. // Find edge normal of max separation on B - return if separation axis is found
  96. // Choose reference edge as min(minA, minB)
  97. // Find incident edge
  98. // Clip
  99. // The normal points from 1 to 2
  100. void b2CollidePolygons(b2Manifold* manifold,
  101. const b2PolygonShape* polyA, const b2Transform& xfA,
  102. const b2PolygonShape* polyB, const b2Transform& xfB)
  103. {
  104. manifold->pointCount = 0;
  105. float32 totalRadius = polyA->m_radius + polyB->m_radius;
  106. int32 edgeA = 0;
  107. float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB);
  108. if (separationA > totalRadius)
  109. return;
  110. int32 edgeB = 0;
  111. float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA);
  112. if (separationB > totalRadius)
  113. return;
  114. const b2PolygonShape* poly1; // reference polygon
  115. const b2PolygonShape* poly2; // incident polygon
  116. b2Transform xf1, xf2;
  117. int32 edge1; // reference edge
  118. uint8 flip;
  119. const float32 k_tol = 0.1f * b2_linearSlop;
  120. if (separationB > separationA + k_tol)
  121. {
  122. poly1 = polyB;
  123. poly2 = polyA;
  124. xf1 = xfB;
  125. xf2 = xfA;
  126. edge1 = edgeB;
  127. manifold->type = b2Manifold::e_faceB;
  128. flip = 1;
  129. }
  130. else
  131. {
  132. poly1 = polyA;
  133. poly2 = polyB;
  134. xf1 = xfA;
  135. xf2 = xfB;
  136. edge1 = edgeA;
  137. manifold->type = b2Manifold::e_faceA;
  138. flip = 0;
  139. }
  140. b2ClipVertex incidentEdge[2];
  141. b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2);
  142. int32 count1 = poly1->m_count;
  143. const b2Vec2* vertices1 = poly1->m_vertices;
  144. int32 iv1 = edge1;
  145. int32 iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;
  146. b2Vec2 v11 = vertices1[iv1];
  147. b2Vec2 v12 = vertices1[iv2];
  148. b2Vec2 localTangent = v12 - v11;
  149. localTangent.Normalize();
  150. b2Vec2 localNormal = b2Cross(localTangent, 1.0f);
  151. b2Vec2 planePoint = 0.5f * (v11 + v12);
  152. b2Vec2 tangent = b2Mul(xf1.q, localTangent);
  153. b2Vec2 normal = b2Cross(tangent, 1.0f);
  154. v11 = b2Mul(xf1, v11);
  155. v12 = b2Mul(xf1, v12);
  156. // Face offset.
  157. float32 frontOffset = b2Dot(normal, v11);
  158. // Side offsets, extended by polytope skin thickness.
  159. float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius;
  160. float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius;
  161. // Clip incident edge against extruded edge1 side edges.
  162. b2ClipVertex clipPoints1[2];
  163. b2ClipVertex clipPoints2[2];
  164. int np;
  165. // Clip to box side 1
  166. np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1);
  167. if (np < 2)
  168. return;
  169. // Clip to negative box side 1
  170. np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2, iv2);
  171. if (np < 2)
  172. {
  173. return;
  174. }
  175. // Now clipPoints2 contains the clipped points.
  176. manifold->localNormal = localNormal;
  177. manifold->localPoint = planePoint;
  178. int32 pointCount = 0;
  179. for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
  180. {
  181. float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset;
  182. if (separation <= totalRadius)
  183. {
  184. b2ManifoldPoint* cp = manifold->points + pointCount;
  185. cp->localPoint = b2MulT(xf2, clipPoints2[i].v);
  186. cp->id = clipPoints2[i].id;
  187. if (flip)
  188. {
  189. // Swap features
  190. b2ContactFeature cf = cp->id.cf;
  191. cp->id.cf.indexA = cf.indexB;
  192. cp->id.cf.indexB = cf.indexA;
  193. cp->id.cf.typeA = cf.typeB;
  194. cp->id.cf.typeB = cf.typeA;
  195. }
  196. ++pointCount;
  197. }
  198. }
  199. manifold->pointCount = pointCount;
  200. }