IntrLine3Triangle3.h 5.9 KB

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