Polygon2.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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/IntrSegment2Segment2.h>
  9. #include <set>
  10. #include <vector>
  11. // The Polygon2 object represents a simple polygon: No duplicate vertices,
  12. // closed (each vertex is shared by exactly two edges), and no
  13. // self-intersections at interior edge points. The 'vertexPool' array can
  14. // contain more points than needed to define the polygon, which allows the
  15. // vertex pool to have multiple polygons associated with it. Thus, the
  16. // programmer must ensure that the vertex pool persists as long as any
  17. // Polygon2 objects exist that depend on the pool. The number of polygon
  18. // vertices is 'numIndices' and must be 3 or larger. The 'indices' array
  19. // refers to the points in 'vertexPool' that are part of the polygon and must
  20. // have 'numIndices' unique elements. The edges of the polygon are pairs of
  21. // indices into 'vertexPool',
  22. // edge[0] = (indices[0], indices[1])
  23. // :
  24. // edge[numIndices-2] = (indices[numIndices-2], indices[numIndices-1])
  25. // edge[numIndices-1] = (indices[numIndices-1], indices[0])
  26. // The programmer should ensure the polygon is simple. The geometric
  27. // queries are valid regardless of whether the polygon is oriented clockwise
  28. // or counterclockwise.
  29. //
  30. // NOTE: Comparison operators are not provided. The semantics of equal
  31. // polygons is complicated and (at the moment) not useful. The vertex pools
  32. // can be different and indices do not match, but the vertices they reference
  33. // can match. Even with a shared vertex pool, the indices can be "rotated",
  34. // leading to the same polygon abstractly but the data structures do not
  35. // match.
  36. namespace WwiseGTE
  37. {
  38. template <typename Real>
  39. class Polygon2
  40. {
  41. public:
  42. // Construction. The constructor succeeds when 'numIndices' >= 3 and
  43. // 'vertexPool' and 'indices' are not null; we cannot test whether you
  44. // have a valid number of elements in the input arrays. A copy is
  45. // made of 'indices', but the 'vertexPool' is not copied. If the
  46. // constructor fails, the internal vertex pointer is set to null, the
  47. // index array has no elements, and the orientation is set to
  48. // clockwise.
  49. Polygon2(Vector2<Real> const* vertexPool, int numIndices,
  50. int const* indices, bool counterClockwise)
  51. :
  52. mVertexPool(vertexPool),
  53. mCounterClockwise(counterClockwise)
  54. {
  55. if (numIndices >= 3 && vertexPool && indices)
  56. {
  57. for (int i = 0; i < numIndices; ++i)
  58. {
  59. mVertices.insert(indices[i]);
  60. }
  61. if (numIndices == static_cast<int>(mVertices.size()))
  62. {
  63. mIndices.resize(numIndices);
  64. std::copy(indices, indices + numIndices, mIndices.begin());
  65. return;
  66. }
  67. // At least one duplicated vertex was encountered, so the
  68. // polygon is not simple. Fail the constructor call.
  69. mVertices.clear();
  70. }
  71. // Invalid input to the Polygon2 constructor.
  72. mVertexPool = nullptr;
  73. mCounterClockwise = false;
  74. }
  75. // To validate construction, create an object as shown:
  76. // Polygon2<Real> polygon(parameters);
  77. // if (!polygon) { <constructor failed, handle accordingly>; }
  78. inline operator bool() const
  79. {
  80. return mVertexPool != nullptr;
  81. }
  82. // Member access.
  83. inline Vector2<Real> const* GetVertexPool() const
  84. {
  85. return mVertexPool;
  86. }
  87. inline std::set<int> const& GetVertices() const
  88. {
  89. return mVertices;
  90. }
  91. inline std::vector<int> const& GetIndices() const
  92. {
  93. return mIndices;
  94. }
  95. inline bool CounterClockwise() const
  96. {
  97. return mCounterClockwise;
  98. }
  99. // Geometric queries.
  100. Vector2<Real> ComputeVertexAverage() const
  101. {
  102. Vector2<Real> average = Vector2<Real>::Zero();
  103. if (mVertexPool)
  104. {
  105. for (int index : mVertices)
  106. {
  107. average += mVertexPool[index];
  108. }
  109. average /= static_cast<Real>(mVertices.size());
  110. }
  111. return average;
  112. }
  113. Real ComputePerimeterLength() const
  114. {
  115. Real length(0);
  116. if (mVertexPool)
  117. {
  118. Vector2<Real> v0 = mVertexPool[mIndices.back()];
  119. for (int index : mIndices)
  120. {
  121. Vector2<Real> v1 = mVertexPool[index];
  122. length += Length(v1 - v0);
  123. v0 = v1;
  124. }
  125. }
  126. return length;
  127. }
  128. Real ComputeArea() const
  129. {
  130. Real area(0);
  131. if (mVertexPool)
  132. {
  133. int const numIndices = static_cast<int>(mIndices.size());
  134. Vector2<Real> v0 = mVertexPool[mIndices[numIndices - 2]];
  135. Vector2<Real> v1 = mVertexPool[mIndices[numIndices - 1]];
  136. for (int index : mIndices)
  137. {
  138. Vector2<Real> v2 = mVertexPool[index];
  139. area += v1[0] * (v2[1] - v0[1]);
  140. v0 = v1;
  141. v1 = v2;
  142. }
  143. area *= (Real)0.5;
  144. }
  145. return std::fabs(area);
  146. }
  147. // Simple polygons have no self-intersections at interior points
  148. // of edges. The test is an exhaustive all-pairs intersection
  149. // test for edges, which is inefficient for polygons with a large
  150. // number of vertices. TODO: Provide an efficient algorithm that
  151. // uses the algorithm of class RectangleManager.h.
  152. bool IsSimple() const
  153. {
  154. if (!mVertexPool)
  155. {
  156. return false;
  157. }
  158. // For mVertexPool to be nonnull, the number of indices is
  159. // guaranteed to be at least 3.
  160. int const numIndices = static_cast<int>(mIndices.size());
  161. if (numIndices == 3)
  162. {
  163. // The polygon is a triangle.
  164. return true;
  165. }
  166. return IsSimpleInternal();
  167. }
  168. // Convex polygons are simple polygons where the angles between
  169. // consecutive edges are less than or equal to pi radians.
  170. bool IsConvex() const
  171. {
  172. if (!mVertexPool)
  173. {
  174. return false;
  175. }
  176. // For mVertexPool to be nonnull, the number of indices is
  177. // guaranteed to be at least 3.
  178. int const numIndices = static_cast<int>(mIndices.size());
  179. if (numIndices == 3)
  180. {
  181. // The polygon is a triangle.
  182. return true;
  183. }
  184. return IsSimpleInternal() && IsConvexInternal();
  185. }
  186. private:
  187. // These calls have preconditions that mVertexPool is not null and
  188. // mIndices.size() > 3. The heart of the algorithms are implemented
  189. // here.
  190. bool IsSimpleInternal() const
  191. {
  192. Segment2<Real> seg0, seg1;
  193. TIQuery<Real, Segment2<Real>, Segment2<Real>> query;
  194. typename TIQuery<Real, Segment2<Real>, Segment2<Real>>::Result result;
  195. int const numIndices = static_cast<int>(mIndices.size());
  196. for (int i0 = 0; i0 < numIndices; ++i0)
  197. {
  198. int i0p1 = (i0 + 1) % numIndices;
  199. seg0.p[0] = mVertexPool[mIndices[i0]];
  200. seg0.p[1] = mVertexPool[mIndices[i0p1]];
  201. int i1min = (i0 + 2) % numIndices;
  202. int i1max = (i0 - 2 + numIndices) % numIndices;
  203. for (int i1 = i1min; i1 <= i1max; ++i1)
  204. {
  205. int i1p1 = (i1 + 1) % numIndices;
  206. seg1.p[0] = mVertexPool[mIndices[i1]];
  207. seg1.p[1] = mVertexPool[mIndices[i1p1]];
  208. result = query(seg0, seg1);
  209. if (result.intersect)
  210. {
  211. return false;
  212. }
  213. }
  214. }
  215. return true;
  216. }
  217. bool IsConvexInternal() const
  218. {
  219. Real sign = (mCounterClockwise ? (Real)1 : (Real)-1);
  220. int const numIndices = static_cast<int>(mIndices.size());
  221. for (int i = 0; i < numIndices; ++i)
  222. {
  223. int iPrev = (i + numIndices - 1) % numIndices;
  224. int iNext = (i + 1) % numIndices;
  225. Vector2<Real> vPrev = mVertexPool[mIndices[iPrev]];
  226. Vector2<Real> vCurr = mVertexPool[mIndices[i]];
  227. Vector2<Real> vNext = mVertexPool[mIndices[iNext]];
  228. Vector2<Real> edge0 = vCurr - vPrev;
  229. Vector2<Real> edge1 = vNext - vCurr;
  230. Real test = sign * DotPerp(edge0, edge1);
  231. if (test < (Real)0)
  232. {
  233. return false;
  234. }
  235. }
  236. return true;
  237. }
  238. Vector2<Real> const* mVertexPool;
  239. std::set<int> mVertices;
  240. std::vector<int> mIndices;
  241. bool mCounterClockwise;
  242. };
  243. }