SeparatePoints2.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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/ConvexHull2.h>
  9. // Separate two point sets, if possible, by computing a line 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 polygons are disjoint.
  13. // https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
  14. // The ComputeType is for the ConvexHull2 class.
  15. namespace WwiseGTE
  16. {
  17. template <typename Real, typename ComputeType>
  18. class SeparatePoints2
  19. {
  20. public:
  21. // The return value is 'true' if and only if there is a separation.
  22. // If 'true', the returned line is a separating line. The code
  23. // assumes that each point set has at least 3 noncollinear points.
  24. bool operator()(int numPoints0, Vector2<Real> const* points0,
  25. int numPoints1, Vector2<Real> const* points1,
  26. Line2<Real>& separatingLine) const
  27. {
  28. // Construct convex hull of point set 0.
  29. ConvexHull2<Real, ComputeType> ch0;
  30. ch0(numPoints0, points0, (Real)0);
  31. if (ch0.GetDimension() != 2)
  32. {
  33. return false;
  34. }
  35. // Construct convex hull of point set 1.
  36. ConvexHull2<Real, ComputeType> ch1;
  37. ch1(numPoints1, points1, (Real)0);
  38. if (ch1.GetDimension() != 2)
  39. {
  40. return false;
  41. }
  42. int numEdges0 = static_cast<int>(ch0.GetHull().size());
  43. int const* edges0 = &ch0.GetHull()[0];
  44. int numEdges1 = static_cast<int>(ch1.GetHull().size());
  45. int const* edges1 = &ch1.GetHull()[0];
  46. // Test edges of hull 0 for possible separation of points.
  47. int j0, j1, i0, i1, side0, side1;
  48. Vector2<Real> lineNormal;
  49. Real lineConstant;
  50. for (j1 = 0, j0 = numEdges0 - 1; j1 < numEdges0; j0 = j1++)
  51. {
  52. // Look up edge (assert: i0 != i1 ).
  53. i0 = edges0[j0];
  54. i1 = edges0[j1];
  55. // Compute potential separating line
  56. // (assert: (xNor,yNor) != (0,0)).
  57. separatingLine.origin = points0[i0];
  58. separatingLine.direction = points0[i1] - points0[i0];
  59. Normalize(separatingLine.direction);
  60. lineNormal = Perp(separatingLine.direction);
  61. lineConstant = Dot(lineNormal, separatingLine.origin);
  62. // Determine whether hull 1 is on same side of line.
  63. side1 = OnSameSide(lineNormal, lineConstant, numEdges1, edges1,
  64. points1);
  65. if (side1)
  66. {
  67. // Determine on which side of line hull 0 lies.
  68. side0 = WhichSide(lineNormal, lineConstant, numEdges0,
  69. edges0, points0);
  70. if (side0 * side1 <= 0) // Line separates hulls.
  71. {
  72. return true;
  73. }
  74. }
  75. }
  76. // Test edges of hull 1 for possible separation of points.
  77. for (j1 = 0, j0 = numEdges1 - 1; j1 < numEdges1; j0 = j1++)
  78. {
  79. // Look up edge (assert: i0 != i1 ).
  80. i0 = edges1[j0];
  81. i1 = edges1[j1];
  82. // Compute perpendicular to edge
  83. // (assert: (xNor,yNor) != (0,0)).
  84. separatingLine.origin = points1[i0];
  85. separatingLine.direction = points1[i1] - points1[i0];
  86. Normalize(separatingLine.direction);
  87. lineNormal = Perp(separatingLine.direction);
  88. lineConstant = Dot(lineNormal, separatingLine.origin);
  89. // Determine whether hull 0 is on same side of line.
  90. side0 = OnSameSide(lineNormal, lineConstant, numEdges0, edges0,
  91. points0);
  92. if (side0)
  93. {
  94. // Determine on which side of line hull 1 lies.
  95. side1 = WhichSide(lineNormal, lineConstant, numEdges1,
  96. edges1, points1);
  97. if (side0 * side1 <= 0) // Line separates hulls.
  98. {
  99. return true;
  100. }
  101. }
  102. }
  103. return false;
  104. }
  105. private:
  106. int OnSameSide(Vector2<Real> const& lineNormal, Real lineConstant,
  107. int numEdges, int const* edges, Vector2<Real> const* points) const
  108. {
  109. // Test whether all points on same side of line Dot(N,X) = c.
  110. Real c0;
  111. int posSide = 0, negSide = 0;
  112. for (int i1 = 0, i0 = numEdges - 1; i1 < numEdges; i0 = i1++)
  113. {
  114. c0 = Dot(lineNormal, points[edges[i0]]);
  115. if (c0 > lineConstant)
  116. {
  117. ++posSide;
  118. }
  119. else if (c0 < lineConstant)
  120. {
  121. ++negSide;
  122. }
  123. if (posSide && negSide)
  124. {
  125. // Line splits point set.
  126. return 0;
  127. }
  128. c0 = Dot(lineNormal, points[edges[i1]]);
  129. if (c0 > lineConstant)
  130. {
  131. ++posSide;
  132. }
  133. else if (c0 < lineConstant)
  134. {
  135. ++negSide;
  136. }
  137. if (posSide && negSide)
  138. {
  139. // Line splits point set.
  140. return 0;
  141. }
  142. }
  143. return (posSide ? +1 : -1);
  144. }
  145. int WhichSide(Vector2<Real> const& lineNormal, Real lineConstant,
  146. int numEdges, int const* edges, Vector2<Real> const* points) const
  147. {
  148. // Establish which side of line hull is on.
  149. Real c0;
  150. for (int i1 = 0, i0 = numEdges - 1; i1 < numEdges; i0 = i1++)
  151. {
  152. c0 = Dot(lineNormal, points[edges[i0]]);
  153. if (c0 > lineConstant)
  154. {
  155. // Hull on positive side.
  156. return +1;
  157. }
  158. if (c0 < lineConstant)
  159. {
  160. // Hull on negative side.
  161. return -1;
  162. }
  163. c0 = Dot(lineNormal, points[edges[i1]]);
  164. if (c0 > lineConstant)
  165. {
  166. // Hull on positive side.
  167. return +1;
  168. }
  169. if (c0 < lineConstant)
  170. {
  171. // Hull on negative side.
  172. return -1;
  173. }
  174. }
  175. // Hull is effectively collinear.
  176. return 0;
  177. }
  178. };
  179. }