IntrSegment3Triangle3.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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/Segment.h>
  11. #include <Mathematics/Triangle.h>
  12. #include <Mathematics/Vector3.h>
  13. namespace WwiseGTE
  14. {
  15. template <typename Real>
  16. class TIQuery<Real, Segment3<Real>, Triangle3<Real>>
  17. {
  18. public:
  19. struct Result
  20. {
  21. bool intersect;
  22. };
  23. Result operator()(Segment3<Real> const& segment, Triangle3<Real> const& triangle)
  24. {
  25. Result result;
  26. Vector3<Real> segOrigin, segDirection;
  27. Real segExtent;
  28. segment.GetCenteredForm(segOrigin, segDirection, segExtent);
  29. // Compute the offset origin, edges, and normal.
  30. Vector3<Real> diff = segOrigin - triangle.v[0];
  31. Vector3<Real> edge1 = triangle.v[1] - triangle.v[0];
  32. Vector3<Real> edge2 = triangle.v[2] - triangle.v[0];
  33. Vector3<Real> normal = Cross(edge1, edge2);
  34. // Solve Q + t*D = b1*E1 + b2*E2 (Q = diff, D = segment direction,
  35. // E1 = edge1, E2 = edge2, N = Cross(E1,E2)) by
  36. // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
  37. // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
  38. // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
  39. Real DdN = Dot(segDirection, normal);
  40. Real sign;
  41. if (DdN > (Real)0)
  42. {
  43. sign = (Real)1;
  44. }
  45. else if (DdN < (Real)0)
  46. {
  47. sign = (Real)-1;
  48. DdN = -DdN;
  49. }
  50. else
  51. {
  52. // Segment and triangle are parallel, call it a "no
  53. // intersection" even if the segment does intersect.
  54. result.intersect = false;
  55. return result;
  56. }
  57. Real DdQxE2 = sign * DotCross(segDirection, diff, edge2);
  58. if (DdQxE2 >= (Real)0)
  59. {
  60. Real DdE1xQ = sign * DotCross(segDirection, edge1, diff);
  61. if (DdE1xQ >= (Real)0)
  62. {
  63. if (DdQxE2 + DdE1xQ <= DdN)
  64. {
  65. // Line intersects triangle, check whether segment
  66. // does.
  67. Real QdN = -sign * Dot(diff, normal);
  68. Real extDdN = segExtent * DdN;
  69. if (-extDdN <= QdN && QdN <= extDdN)
  70. {
  71. // Segment intersects triangle.
  72. result.intersect = true;
  73. return result;
  74. }
  75. // else: |t| > extent, no intersection
  76. }
  77. // else: b1+b2 > 1, no intersection
  78. }
  79. // else: b2 < 0, no intersection
  80. }
  81. // else: b1 < 0, no intersection
  82. result.intersect = false;
  83. return result;
  84. }
  85. };
  86. template <typename Real>
  87. class FIQuery<Real, Segment3<Real>, Triangle3<Real>>
  88. {
  89. public:
  90. struct Result
  91. {
  92. Result()
  93. :
  94. intersect(false),
  95. parameter((Real)0),
  96. triangleBary{ (Real)0, (Real)0, (Real)0 },
  97. point{ (Real)0, (Real)0, (Real)0 }
  98. {
  99. }
  100. bool intersect;
  101. Real parameter;
  102. std::array<Real, 3> triangleBary;
  103. Vector3<Real> point;
  104. };
  105. Result operator()(Segment3<Real> const& segment, Triangle3<Real> const& triangle)
  106. {
  107. Result result;
  108. Vector3<Real> segOrigin, segDirection;
  109. Real segExtent;
  110. segment.GetCenteredForm(segOrigin, segDirection, segExtent);
  111. // Compute the offset origin, edges, and normal.
  112. Vector3<Real> diff = segOrigin - triangle.v[0];
  113. Vector3<Real> edge1 = triangle.v[1] - triangle.v[0];
  114. Vector3<Real> edge2 = triangle.v[2] - triangle.v[0];
  115. Vector3<Real> normal = Cross(edge1, edge2);
  116. // Solve Q + t*D = b1*E1 + b2*E2 (Q = diff, D = segment direction,
  117. // E1 = edge1, E2 = edge2, N = Cross(E1,E2)) by
  118. // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
  119. // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
  120. // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
  121. Real DdN = Dot(segDirection, normal);
  122. Real sign;
  123. if (DdN > (Real)0)
  124. {
  125. sign = (Real)1;
  126. }
  127. else if (DdN < (Real)0)
  128. {
  129. sign = (Real)-1;
  130. DdN = -DdN;
  131. }
  132. else
  133. {
  134. // Segment and triangle are parallel, call it a "no
  135. // intersection" even if the segment does intersect.
  136. result.intersect = false;
  137. return result;
  138. }
  139. Real DdQxE2 = sign * DotCross(segDirection, diff, edge2);
  140. if (DdQxE2 >= (Real)0)
  141. {
  142. Real DdE1xQ = sign * DotCross(segDirection, edge1, diff);
  143. if (DdE1xQ >= (Real)0)
  144. {
  145. if (DdQxE2 + DdE1xQ <= DdN)
  146. {
  147. // Line intersects triangle, check whether segment
  148. // does.
  149. Real QdN = -sign * Dot(diff, normal);
  150. Real extDdN = segExtent * DdN;
  151. if (-extDdN <= QdN && QdN <= extDdN)
  152. {
  153. // Segment intersects triangle.
  154. result.intersect = true;
  155. Real inv = ((Real)1) / DdN;
  156. result.parameter = QdN * inv;
  157. result.triangleBary[1] = DdQxE2 * inv;
  158. result.triangleBary[2] = DdE1xQ * inv;
  159. result.triangleBary[0] =
  160. (Real)1 - result.triangleBary[1] - result.triangleBary[2];
  161. result.point = segOrigin + result.parameter * segDirection;
  162. return result;
  163. }
  164. // else: |t| > extent, no intersection
  165. }
  166. // else: b1+b2 > 1, no intersection
  167. }
  168. // else: b2 < 0, no intersection
  169. }
  170. // else: b1 < 0, no intersection
  171. result.intersect = false;
  172. return result;
  173. }
  174. };
  175. }