SeparatePoints3.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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.2020.01.11
  7. #pragma once
  8. #include <Mathematics/ConvexHull3.h>
  9. // Separate two point sets, if possible, by computing a plane for which the
  10. // point sets lie on opposite sides. The algorithm computes the convex hull
  11. // of the point sets, then uses the method of separating axes to determine
  12. // whether the two convex polyhedra are disjoint.
  13. // https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
  14. // The ComputeType is for the ConvexHull3 class.
  15. namespace WwiseGTE
  16. {
  17. template <typename Real, typename ComputeType>
  18. class SeparatePoints3
  19. {
  20. public:
  21. // The return value is 'true' if and only if there is a separation.
  22. // If 'true', the returned plane is a separating plane. The code
  23. // assumes that each point set has at least 4 noncoplanar points.
  24. bool operator()(int numPoints0, Vector3<Real> const* points0,
  25. int numPoints1, Vector3<Real> const* points1,
  26. Plane3<Real>& separatingPlane) const
  27. {
  28. // Construct convex hull of point set 0.
  29. ConvexHull3<Real, ComputeType> ch0;
  30. ch0(numPoints0, points0, (Real)0);
  31. if (ch0.GetDimension() != 3)
  32. {
  33. return false;
  34. }
  35. // Construct convex hull of point set 1.
  36. ConvexHull3<Real, ComputeType> ch1;
  37. ch1(numPoints1, points1, (Real)0);
  38. if (ch1.GetDimension() != 3)
  39. {
  40. return false;
  41. }
  42. auto const& hull0 = ch0.GetHullUnordered();
  43. auto const& hull1 = ch1.GetHullUnordered();
  44. int numTriangles0 = static_cast<int>(hull0.size());
  45. int const* indices0 = reinterpret_cast<int const*>(&hull0[0]);
  46. int numTriangles1 = static_cast<int>(hull1.size());
  47. int const* indices1 = reinterpret_cast<int const*>(&hull1[0]);
  48. // Test faces of hull 0 for possible separation of points.
  49. int i, i0, i1, i2, side0, side1;
  50. Vector3<Real> diff0, diff1;
  51. for (i = 0; i < numTriangles0; ++i)
  52. {
  53. // Look up face (assert: i0 != i1 && i0 != i2 && i1 != i2).
  54. i0 = indices0[3 * i];
  55. i1 = indices0[3 * i + 1];
  56. i2 = indices0[3 * i + 2];
  57. // Compute potential separating plane
  58. // (assert: normal != (0,0,0)).
  59. separatingPlane = Plane3<Real>({ points0[i0], points0[i1], points0[i2] });
  60. // Determine whether hull 1 is on same side of plane.
  61. side1 = OnSameSide(separatingPlane, numTriangles1, indices1, points1);
  62. if (side1)
  63. {
  64. // Determine on which side of plane hull 0 lies.
  65. side0 = WhichSide(separatingPlane, numTriangles0, indices0, points0);
  66. if (side0 * side1 <= 0) // Plane separates hulls.
  67. {
  68. return true;
  69. }
  70. }
  71. }
  72. // Test faces of hull 1 for possible separation of points.
  73. for (i = 0; i < numTriangles1; ++i)
  74. {
  75. // Look up edge (assert: i0 != i1 && i0 != i2 && i1 != i2).
  76. i0 = indices1[3 * i];
  77. i1 = indices1[3 * i + 1];
  78. i2 = indices1[3 * i + 2];
  79. // Compute perpendicular to face
  80. // (assert: normal != (0,0,0)).
  81. separatingPlane = Plane3<Real>({ points1[i0], points1[i1], points1[i2] });
  82. // Determine whether hull 0 is on same side of plane.
  83. side0 = OnSameSide(separatingPlane, numTriangles0, indices0, points0);
  84. if (side0)
  85. {
  86. // Determine on which side of plane hull 1 lies.
  87. side1 = WhichSide(separatingPlane, numTriangles1, indices1,
  88. points1);
  89. if (side0 * side1 <= 0) // Plane separates hulls.
  90. {
  91. return true;
  92. }
  93. }
  94. }
  95. // Build edge set for hull 0.
  96. std::set<std::pair<int, int>> edgeSet0;
  97. for (i = 0; i < numTriangles0; ++i)
  98. {
  99. // Look up face (assert: i0 != i1 && i0 != i2 && i1 != i2).
  100. i0 = indices0[3 * i];
  101. i1 = indices0[3 * i + 1];
  102. i2 = indices0[3 * i + 2];
  103. edgeSet0.insert(std::make_pair(i0, i1));
  104. edgeSet0.insert(std::make_pair(i0, i2));
  105. edgeSet0.insert(std::make_pair(i1, i2));
  106. }
  107. // Build edge list for hull 1.
  108. std::set<std::pair<int, int>> edgeSet1;
  109. for (i = 0; i < numTriangles1; ++i)
  110. {
  111. // Look up face (assert: i0 != i1 && i0 != i2 && i1 != i2).
  112. i0 = indices1[3 * i];
  113. i1 = indices1[3 * i + 1];
  114. i2 = indices1[3 * i + 2];
  115. edgeSet1.insert(std::make_pair(i0, i1));
  116. edgeSet1.insert(std::make_pair(i0, i2));
  117. edgeSet1.insert(std::make_pair(i1, i2));
  118. }
  119. // Test planes whose normals are cross products of two edges, one
  120. // from each hull.
  121. for (auto const& e0 : edgeSet0)
  122. {
  123. // Get edge.
  124. diff0 = points0[e0.second] - points0[e0.first];
  125. for (auto const& e1 : edgeSet1)
  126. {
  127. diff1 = points1[e1.second] - points1[e1.first];
  128. // Compute potential separating plane.
  129. separatingPlane.normal = UnitCross(diff0, diff1);
  130. separatingPlane.constant = Dot(separatingPlane.normal,
  131. points0[e0.first]);
  132. // Determine if hull 0 is on same side of plane.
  133. side0 = OnSameSide(separatingPlane, numTriangles0, indices0,
  134. points0);
  135. side1 = OnSameSide(separatingPlane, numTriangles1, indices1,
  136. points1);
  137. if (side0 * side1 < 0) // Plane separates hulls.
  138. {
  139. return true;
  140. }
  141. }
  142. }
  143. return false;
  144. }
  145. private:
  146. int OnSameSide(Plane3<Real> const& plane, int numTriangles,
  147. int const* indices, Vector3<Real> const* points) const
  148. {
  149. // Test whether all points on same side of plane Dot(N,X) = c.
  150. int posSide = 0, negSide = 0;
  151. for (int t = 0; t < numTriangles; ++t)
  152. {
  153. for (int i = 0; i < 3; ++i)
  154. {
  155. int v = indices[3 * t + i];
  156. Real c0 = Dot(plane.normal, points[v]);
  157. if (c0 > plane.constant)
  158. {
  159. ++posSide;
  160. }
  161. else if (c0 < plane.constant)
  162. {
  163. ++negSide;
  164. }
  165. if (posSide && negSide)
  166. {
  167. // Plane splits point set.
  168. return 0;
  169. }
  170. }
  171. }
  172. return (posSide ? +1 : -1);
  173. }
  174. int WhichSide(Plane3<Real> const& plane, int numTriangles,
  175. int const* indices, Vector3<Real> const* points) const
  176. {
  177. // Establish which side of plane hull is on.
  178. for (int t = 0; t < numTriangles; ++t)
  179. {
  180. for (int i = 0; i < 3; ++i)
  181. {
  182. int v = indices[3 * t + i];
  183. Real c0 = Dot(plane.normal, points[v]);
  184. if (c0 > plane.constant)
  185. {
  186. // Positive side.
  187. return +1;
  188. }
  189. if (c0 < plane.constant)
  190. {
  191. // Negative side.
  192. return -1;
  193. }
  194. }
  195. }
  196. // Hull is effectively collinear.
  197. return 0;
  198. }
  199. };
  200. }