b2_collide_circle.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // MIT License
  2. // Copyright (c) 2019 Erin Catto
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. // The above copyright notice and this permission notice shall be included in all
  10. // copies or substantial portions of the Software.
  11. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  17. // SOFTWARE.
  18. #include "box2d/b2_collision.h"
  19. #include "box2d/b2_circle_shape.h"
  20. #include "box2d/b2_polygon_shape.h"
  21. void b2CollideCircles(
  22. b2Manifold* manifold,
  23. const b2CircleShape* circleA, const b2Transform& xfA,
  24. const b2CircleShape* circleB, const b2Transform& xfB)
  25. {
  26. manifold->pointCount = 0;
  27. b2Vec2 pA = b2Mul(xfA, circleA->m_p);
  28. b2Vec2 pB = b2Mul(xfB, circleB->m_p);
  29. b2Vec2 d = pB - pA;
  30. float distSqr = b2Dot(d, d);
  31. float rA = circleA->m_radius, rB = circleB->m_radius;
  32. float radius = rA + rB;
  33. if (distSqr > radius * radius)
  34. {
  35. return;
  36. }
  37. manifold->type = b2Manifold::e_circles;
  38. manifold->localPoint = circleA->m_p;
  39. manifold->localNormal.SetZero();
  40. manifold->pointCount = 1;
  41. manifold->points[0].localPoint = circleB->m_p;
  42. manifold->points[0].id.key = 0;
  43. }
  44. void b2CollidePolygonAndCircle(
  45. b2Manifold* manifold,
  46. const b2PolygonShape* polygonA, const b2Transform& xfA,
  47. const b2CircleShape* circleB, const b2Transform& xfB)
  48. {
  49. manifold->pointCount = 0;
  50. // Compute circle position in the frame of the polygon.
  51. b2Vec2 c = b2Mul(xfB, circleB->m_p);
  52. b2Vec2 cLocal = b2MulT(xfA, c);
  53. // Find the min separating edge.
  54. int32 normalIndex = 0;
  55. float separation = -b2_maxFloat;
  56. float radius = polygonA->m_radius + circleB->m_radius;
  57. int32 vertexCount = polygonA->m_count;
  58. const b2Vec2* vertices = polygonA->m_vertices;
  59. const b2Vec2* normals = polygonA->m_normals;
  60. for (int32 i = 0; i < vertexCount; ++i)
  61. {
  62. float s = b2Dot(normals[i], cLocal - vertices[i]);
  63. if (s > radius)
  64. {
  65. // Early out.
  66. return;
  67. }
  68. if (s > separation)
  69. {
  70. separation = s;
  71. normalIndex = i;
  72. }
  73. }
  74. // Vertices that subtend the incident face.
  75. int32 vertIndex1 = normalIndex;
  76. int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
  77. b2Vec2 v1 = vertices[vertIndex1];
  78. b2Vec2 v2 = vertices[vertIndex2];
  79. // If the center is inside the polygon ...
  80. if (separation < b2_epsilon)
  81. {
  82. manifold->pointCount = 1;
  83. manifold->type = b2Manifold::e_faceA;
  84. manifold->localNormal = normals[normalIndex];
  85. manifold->localPoint = 0.5f * (v1 + v2);
  86. manifold->points[0].localPoint = circleB->m_p;
  87. manifold->points[0].id.key = 0;
  88. return;
  89. }
  90. // Compute barycentric coordinates
  91. float u1 = b2Dot(cLocal - v1, v2 - v1);
  92. float u2 = b2Dot(cLocal - v2, v1 - v2);
  93. if (u1 <= 0.0f)
  94. {
  95. if (b2DistanceSquared(cLocal, v1) > radius * radius)
  96. {
  97. return;
  98. }
  99. manifold->pointCount = 1;
  100. manifold->type = b2Manifold::e_faceA;
  101. manifold->localNormal = cLocal - v1;
  102. manifold->localNormal.Normalize();
  103. manifold->localPoint = v1;
  104. manifold->points[0].localPoint = circleB->m_p;
  105. manifold->points[0].id.key = 0;
  106. }
  107. else if (u2 <= 0.0f)
  108. {
  109. if (b2DistanceSquared(cLocal, v2) > radius * radius)
  110. {
  111. return;
  112. }
  113. manifold->pointCount = 1;
  114. manifold->type = b2Manifold::e_faceA;
  115. manifold->localNormal = cLocal - v2;
  116. manifold->localNormal.Normalize();
  117. manifold->localPoint = v2;
  118. manifold->points[0].localPoint = circleB->m_p;
  119. manifold->points[0].id.key = 0;
  120. }
  121. else
  122. {
  123. b2Vec2 faceCenter = 0.5f * (v1 + v2);
  124. float s = b2Dot(cLocal - faceCenter, normals[vertIndex1]);
  125. if (s > radius)
  126. {
  127. return;
  128. }
  129. manifold->pointCount = 1;
  130. manifold->type = b2Manifold::e_faceA;
  131. manifold->localNormal = normals[vertIndex1];
  132. manifold->localPoint = faceCenter;
  133. manifold->points[0].localPoint = circleB->m_p;
  134. manifold->points[0].id.key = 0;
  135. }
  136. }