IntrTriangle3OrientedBox3.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/FIQuery.h>
  9. #include <Mathematics/TIQuery.h>
  10. #include <Mathematics/IntrConvexPolygonHyperplane.h>
  11. #include <Mathematics/Triangle.h>
  12. #include <Mathematics/OrientedBox.h>
  13. #include <Mathematics/Vector3.h>
  14. // The test-intersection query is based on the document
  15. // https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
  16. // The find-intersection query clips the triangle against the faces of
  17. // the oriented box.
  18. namespace WwiseGTE
  19. {
  20. template <typename Real>
  21. class TIQuery<Real, Triangle3<Real>, OrientedBox3<Real>>
  22. {
  23. public:
  24. struct Result
  25. {
  26. bool intersect;
  27. };
  28. Result operator()(Triangle3<Real> const& triangle, OrientedBox3<Real> const& box)
  29. {
  30. Result result;
  31. Real min0, max0, min1, max1;
  32. Vector3<Real> D, edge[3];
  33. // Test direction of triangle normal.
  34. edge[0] = triangle.v[1] - triangle.v[0];
  35. edge[1] = triangle.v[2] - triangle.v[0];
  36. D = Cross(edge[0], edge[1]);
  37. min0 = Dot(D, triangle.v[0]);
  38. max0 = min0;
  39. GetProjection(D, box, min1, max1);
  40. if (max1 < min0 || max0 < min1)
  41. {
  42. result.intersect = false;
  43. return result;
  44. }
  45. // Test direction of box faces.
  46. for (int i = 0; i < 3; ++i)
  47. {
  48. D = box.axis[i];
  49. GetProjection(D, triangle, min0, max0);
  50. Real DdC = Dot(D, box.center);
  51. min1 = DdC - box.extent[i];
  52. max1 = DdC + box.extent[i];
  53. if (max1 < min0 || max0 < min1)
  54. {
  55. result.intersect = false;
  56. return result;
  57. }
  58. }
  59. // Test direction of triangle-box edge cross products.
  60. edge[2] = edge[1] - edge[0];
  61. for (int i0 = 0; i0 < 3; ++i0)
  62. {
  63. for (int i1 = 0; i1 < 3; ++i1)
  64. {
  65. D = Cross(edge[i0], box.axis[i1]);
  66. GetProjection(D, triangle, min0, max0);
  67. GetProjection(D, box, min1, max1);
  68. if (max1 < min0 || max0 < min1)
  69. {
  70. result.intersect = false;
  71. return result;
  72. }
  73. }
  74. }
  75. result.intersect = true;
  76. return result;
  77. }
  78. private:
  79. void GetProjection(Vector3<Real> const& axis, Triangle3<Real> const& triangle, Real& imin, Real& imax)
  80. {
  81. Real dot[3] =
  82. {
  83. Dot(axis, triangle.v[0]),
  84. Dot(axis, triangle.v[1]),
  85. Dot(axis, triangle.v[2])
  86. };
  87. imin = dot[0];
  88. imax = imin;
  89. if (dot[1] < imin)
  90. {
  91. imin = dot[1];
  92. }
  93. else if (dot[1] > imax)
  94. {
  95. imax = dot[1];
  96. }
  97. if (dot[2] < imin)
  98. {
  99. imin = dot[2];
  100. }
  101. else if (dot[2] > imax)
  102. {
  103. imax = dot[2];
  104. }
  105. }
  106. void GetProjection(Vector3<Real> const& axis, OrientedBox3<Real> const& box, Real& imin, Real& imax)
  107. {
  108. Real origin = Dot(axis, box.center);
  109. Real maximumExtent =
  110. std::fabs(box.extent[0] * Dot(axis, box.axis[0])) +
  111. std::fabs(box.extent[1] * Dot(axis, box.axis[1])) +
  112. std::fabs(box.extent[2] * Dot(axis, box.axis[2]));
  113. imin = origin - maximumExtent;
  114. imax = origin + maximumExtent;
  115. }
  116. };
  117. template <typename Real>
  118. class FIQuery<Real, Triangle3<Real>, OrientedBox3<Real>>
  119. {
  120. public:
  121. struct Result
  122. {
  123. std::vector<Vector3<Real>> insidePolygon;
  124. std::vector<std::vector<Vector3<Real>>> outsidePolygons;
  125. };
  126. Result operator()(Triangle3<Real> const& triangle, OrientedBox3<Real> const& box)
  127. {
  128. Result result;
  129. // Start with the triangle and clip it against each face of the
  130. // box. The largest number of vertices for the polygon of
  131. // intersection is 7.
  132. result.insidePolygon.resize(3);
  133. for (int i = 0; i < 3; ++i)
  134. {
  135. result.insidePolygon[i] = triangle.v[i];
  136. }
  137. typedef FIQuery<Real, std::vector<Vector<3, Real>>, Hyperplane<3, Real>> PPQuery;
  138. Plane3<Real> plane;
  139. PPQuery ppQuery;
  140. typename PPQuery::Result ppResult;
  141. for (int dir = -1; dir <= 1; dir += 2)
  142. {
  143. for (int side = 0; side < 3; ++side)
  144. {
  145. // Create a plane for the box face that points inside the box.
  146. plane.normal = ((Real)dir) * box.axis[side];
  147. plane.constant = Dot(plane.normal, box.center) - box.extent[side];
  148. ppResult = ppQuery(result.insidePolygon, plane);
  149. switch (ppResult.configuration)
  150. {
  151. case PPQuery::Configuration::SPLIT:
  152. result.insidePolygon = ppResult.positivePolygon;
  153. result.outsidePolygons.push_back(ppResult.negativePolygon);
  154. break;
  155. case PPQuery::Configuration::POSITIVE_SIDE_VERTEX:
  156. case PPQuery::Configuration::POSITIVE_SIDE_EDGE:
  157. case PPQuery::Configuration::POSITIVE_SIDE_STRICT:
  158. // The result.insidePolygon is already
  159. // ppResult.positivePolygon, but to make it clear,
  160. // assign it here.
  161. result.insidePolygon = ppResult.positivePolygon;
  162. break;
  163. case PPQuery::Configuration::NEGATIVE_SIDE_VERTEX:
  164. case PPQuery::Configuration::NEGATIVE_SIDE_EDGE:
  165. case PPQuery::Configuration::NEGATIVE_SIDE_STRICT:
  166. result.insidePolygon.clear();
  167. result.outsidePolygons.push_back(ppResult.negativePolygon);
  168. return result;
  169. case PPQuery::Configuration::CONTAINED:
  170. // A triangle coplanar with a box face will be
  171. // processed as if it is inside the box.
  172. result.insidePolygon = ppResult.intersection;
  173. break;
  174. default:
  175. result.insidePolygon.clear();
  176. result.outsidePolygons.clear();
  177. break;
  178. }
  179. }
  180. }
  181. return result;
  182. }
  183. };
  184. }