IntrTriangle2Triangle2.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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/IntrConvexPolygonHyperplane.h>
  9. #include <Mathematics/Triangle.h>
  10. #include <Mathematics/Vector2.h>
  11. // The test-intersection queries are based on the document
  12. // https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
  13. // The find-intersection query for stationary triangles is based on clipping
  14. // one triangle against the edges of the other to compute the intersection
  15. // set (if it exists). The find-intersection query for moving triangles is
  16. // based on the previously mentioned document about the method of separating
  17. // axes.
  18. namespace WwiseGTE
  19. {
  20. // Test whether two triangles intersect using the method of separating
  21. // axes. The set of intersection, if it exists, is not computed. The
  22. // input triangles' vertices must be counterclockwise ordered.
  23. template <typename Real>
  24. class TIQuery<Real, Triangle2<Real>, Triangle2<Real>>
  25. {
  26. public:
  27. struct Result
  28. {
  29. bool intersect;
  30. };
  31. Result operator()(Triangle2<Real> const& triangle0, Triangle2<Real> const& triangle1)
  32. {
  33. Result result =
  34. {
  35. !Separated(triangle0, triangle1) && !Separated(triangle1, triangle0)
  36. };
  37. return result;
  38. }
  39. protected:
  40. // The triangle vertices are projected to t-values for the line P+t*D.
  41. // The D-vector is nonzero but does not have to be unit length. The
  42. // return value is +1 if all t >= 0, -1 if all t <= 0, but 0 otherwise
  43. // in which case the line splits the triangle into two subtriangles,
  44. // each of positive area.
  45. int WhichSide(Triangle2<Real> const& triangle, Vector2<Real> const& P, Vector2<Real> const& D) const
  46. {
  47. int positive = 0, negative = 0;
  48. for (int i = 0; i < 3; ++i)
  49. {
  50. Real t = Dot(D, triangle.v[i] - P);
  51. if (t > (Real)0)
  52. {
  53. ++positive;
  54. }
  55. else if (t < (Real)0)
  56. {
  57. --negative;
  58. }
  59. if (positive && negative)
  60. {
  61. // The triangle has vertices strictly on both sides of
  62. // the line, so the line splits the triangle into two
  63. // subtriangles each of positive area.
  64. return 0;
  65. }
  66. }
  67. // Either positive > 0 or negative > 0 but not both are positive.
  68. return (positive > 0 ? +1 : -1);
  69. }
  70. bool Separated(Triangle2<Real> const& triangle0, Triangle2<Real> const& triangle1) const
  71. {
  72. // Test edges of triangle0 for separation. Because of the
  73. // counterclockwise ordering, the projection interval for
  74. // triangle0 is [T,0] for some T < 0. Determine whether
  75. // triangle1 is on the positive side of the line; if it is,
  76. // the triangles are separated.
  77. for (int i0 = 2, i1 = 0; i1 < 3; i0 = i1++)
  78. {
  79. // The potential separating axis is P+t*D.
  80. Vector2<Real> P = triangle0.v[i0];
  81. Vector2<Real> D = Perp(triangle0.v[i1] - triangle0.v[i0]);
  82. if (WhichSide(triangle1, P, D) > 0)
  83. {
  84. // The triangle1 projection interval is [a,b] where a > 0,
  85. // so the triangles are separated.
  86. return true;
  87. }
  88. }
  89. return false;
  90. }
  91. };
  92. // Find the convex polygon, segment or point of intersection of two
  93. // triangles. The input triangles' vertices must be counterclockwise
  94. // ordered.
  95. template <typename Real>
  96. class FIQuery<Real, Triangle2<Real>, Triangle2<Real>>
  97. {
  98. public:
  99. struct Result
  100. {
  101. // An intersection exists iff intersection.size() > 0.
  102. std::vector<Vector2<Real>> intersection;
  103. };
  104. Result operator()(Triangle2<Real> const& triangle0, Triangle2<Real> const& triangle1)
  105. {
  106. Result result;
  107. // Start with triangle1 and clip against the edges of triangle0.
  108. std::vector<Vector2<Real>> polygon =
  109. {
  110. triangle1.v[0], triangle1.v[1], triangle1.v[2]
  111. };
  112. typedef FIQuery<Real, std::vector<Vector<2, Real>>, Hyperplane<2, Real>> PPQuery;
  113. PPQuery ppQuery;
  114. for (int i1 = 2, i0 = 0; i0 < 3; i1 = i0++)
  115. {
  116. // Create the clipping line for the current edge. The edge
  117. // normal N points inside the triangle.
  118. Vector2<Real> P = triangle0.v[i0];
  119. Vector2<Real> N = Perp(triangle0.v[i1] - triangle0.v[i0]);
  120. Hyperplane<2, Real> clippingLine(N, Dot(N, P));
  121. // Do the clipping operation.
  122. auto ppResult = ppQuery(polygon, clippingLine);
  123. if (ppResult.positivePolygon.size() == 0)
  124. {
  125. // The current clipped polygon is outside triangle0.
  126. return result;
  127. }
  128. polygon = std::move(ppResult.positivePolygon);
  129. }
  130. result.intersection = polygon;
  131. return result;
  132. }
  133. };
  134. }