IntrConvexPolygonHyperplane.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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/TIQuery.h>
  9. #include <Mathematics/FIQuery.h>
  10. #include <Mathematics/Hyperplane.h>
  11. #include <Mathematics/Vector.h>
  12. #include <list>
  13. #include <vector>
  14. // The intersection queries are based on the document
  15. // https://www.geometrictools.com/Documentation/ClipConvexPolygonByHyperplane.pdf
  16. namespace WwiseGTE
  17. {
  18. template <int N, typename Real>
  19. class TIQuery<Real, std::vector<Vector<N, Real>>, Hyperplane<N, Real>>
  20. {
  21. public:
  22. enum class Configuration
  23. {
  24. SPLIT,
  25. POSITIVE_SIDE_VERTEX,
  26. POSITIVE_SIDE_EDGE,
  27. POSITIVE_SIDE_STRICT,
  28. NEGATIVE_SIDE_VERTEX,
  29. NEGATIVE_SIDE_EDGE,
  30. NEGATIVE_SIDE_STRICT,
  31. CONTAINED,
  32. INVALID_POLYGON
  33. };
  34. struct Result
  35. {
  36. bool intersect;
  37. Configuration configuration;
  38. };
  39. Result operator()(std::vector<Vector<N, Real>> const& polygon, Hyperplane<N, Real> const& hyperplane)
  40. {
  41. Result result;
  42. size_t const numVertices = polygon.size();
  43. if (numVertices < 3)
  44. {
  45. // The convex polygon must have at least 3 vertices.
  46. result.intersect = false;
  47. result.configuration = Configuration::INVALID_POLYGON;
  48. return result;
  49. }
  50. // Determine on which side of the hyperplane each vertex lies.
  51. size_t numPositive = 0, numNegative = 0, numZero = 0;
  52. for (size_t i = 0; i < numVertices; ++i)
  53. {
  54. Real h = Dot(hyperplane.normal, polygon[i]) - hyperplane.constant;
  55. if (h > (Real)0)
  56. {
  57. ++numPositive;
  58. }
  59. else if (h < (Real)0)
  60. {
  61. ++numNegative;
  62. }
  63. else
  64. {
  65. ++numZero;
  66. }
  67. }
  68. if (numPositive > 0)
  69. {
  70. if (numNegative > 0)
  71. {
  72. result.intersect = true;
  73. result.configuration = Configuration::SPLIT;
  74. }
  75. else if (numZero == 0)
  76. {
  77. result.intersect = false;
  78. result.configuration = Configuration::POSITIVE_SIDE_STRICT;
  79. }
  80. else if (numZero == 1)
  81. {
  82. result.intersect = true;
  83. result.configuration = Configuration::POSITIVE_SIDE_VERTEX;
  84. }
  85. else // numZero > 1
  86. {
  87. result.intersect = true;
  88. result.configuration = Configuration::POSITIVE_SIDE_EDGE;
  89. }
  90. }
  91. else if (numNegative > 0)
  92. {
  93. if (numZero == 0)
  94. {
  95. result.intersect = false;
  96. result.configuration = Configuration::NEGATIVE_SIDE_STRICT;
  97. }
  98. else if (numZero == 1)
  99. {
  100. // The polygon touches the plane in a vertex or an edge.
  101. result.intersect = true;
  102. result.configuration = Configuration::NEGATIVE_SIDE_VERTEX;
  103. }
  104. else // numZero > 1
  105. {
  106. result.intersect = true;
  107. result.configuration = Configuration::NEGATIVE_SIDE_EDGE;
  108. }
  109. }
  110. else // numZero == numVertices
  111. {
  112. result.intersect = true;
  113. result.configuration = Configuration::CONTAINED;
  114. }
  115. return result;
  116. }
  117. };
  118. template <int N, typename Real>
  119. class FIQuery<Real, std::vector<Vector<N, Real>>, Hyperplane<N, Real>>
  120. {
  121. public:
  122. enum class Configuration
  123. {
  124. SPLIT,
  125. POSITIVE_SIDE_VERTEX,
  126. POSITIVE_SIDE_EDGE,
  127. POSITIVE_SIDE_STRICT,
  128. NEGATIVE_SIDE_VERTEX,
  129. NEGATIVE_SIDE_EDGE,
  130. NEGATIVE_SIDE_STRICT,
  131. CONTAINED,
  132. INVALID_POLYGON
  133. };
  134. struct Result
  135. {
  136. // The intersection is either empty, a single vertex, a single
  137. // edge or the polygon is contained by the hyperplane.
  138. Configuration configuration;
  139. std::vector<Vector<N, Real>> intersection;
  140. // If 'configuration' is POSITIVE_* or SPLIT, this polygon is the
  141. // portion of the query input 'polygon' on the positive side of
  142. // the hyperplane with possibly a vertex or edge on the hyperplane.
  143. std::vector<Vector<N, Real>> positivePolygon;
  144. // If 'configuration' is NEGATIVE_* or SPLIT, this polygon is the
  145. // portion of the query input 'polygon' on the negative side of
  146. // the hyperplane with possibly a vertex or edge on the hyperplane.
  147. std::vector<Vector<N, Real>> negativePolygon;
  148. };
  149. Result operator()(std::vector<Vector<N, Real>> const& polygon, Hyperplane<N, Real> const& hyperplane)
  150. {
  151. Result result;
  152. size_t const numVertices = polygon.size();
  153. if (numVertices < 3)
  154. {
  155. // The convex polygon must have at least 3 vertices.
  156. result.configuration = Configuration::INVALID_POLYGON;
  157. return result;
  158. }
  159. // Determine on which side of the hyperplane the vertices live.
  160. // The index maxPosIndex stores the index of the vertex on the
  161. // positive side of the hyperplane that is farthest from the
  162. // hyperplane. The index maxNegIndex stores the index of the
  163. // vertex on the negative side of the hyperplane that is farthest
  164. // from the hyperplane. If one or the other such vertex does not
  165. // exist, the corresponding index will remain its initial value of
  166. // max(size_t).
  167. std::vector<Real> height(numVertices);
  168. std::vector<size_t> zeroHeightIndices;
  169. zeroHeightIndices.reserve(numVertices);
  170. size_t numPositive = 0, numNegative = 0;
  171. Real maxPosHeight = -std::numeric_limits<Real>::max();
  172. Real maxNegHeight = std::numeric_limits<Real>::max();
  173. size_t maxPosIndex = std::numeric_limits<size_t>::max();
  174. size_t maxNegIndex = std::numeric_limits<size_t>::max();
  175. for (size_t i = 0; i < numVertices; ++i)
  176. {
  177. height[i] = Dot(hyperplane.normal, polygon[i]) - hyperplane.constant;
  178. if (height[i] > (Real)0)
  179. {
  180. ++numPositive;
  181. if (height[i] > maxPosHeight)
  182. {
  183. maxPosHeight = height[i];
  184. maxPosIndex = i;
  185. }
  186. }
  187. else if (height[i] < (Real)0)
  188. {
  189. ++numNegative;
  190. if (height[i] < maxNegHeight)
  191. {
  192. maxNegHeight = height[i];
  193. maxNegIndex = i;
  194. }
  195. }
  196. else
  197. {
  198. zeroHeightIndices.push_back(i);
  199. }
  200. }
  201. if (numPositive > 0)
  202. {
  203. if (numNegative > 0)
  204. {
  205. result.configuration = Configuration::SPLIT;
  206. bool doSwap = (maxPosHeight < -maxNegHeight);
  207. if (doSwap)
  208. {
  209. for (auto& h : height)
  210. {
  211. h = -h;
  212. }
  213. std::swap(maxPosIndex, maxNegIndex);
  214. }
  215. SplitPolygon(polygon, height, maxPosIndex, result);
  216. if (doSwap)
  217. {
  218. std::swap(result.positivePolygon, result.negativePolygon);
  219. }
  220. }
  221. else
  222. {
  223. size_t numZero = zeroHeightIndices.size();
  224. if (numZero == 0)
  225. {
  226. result.configuration = Configuration::POSITIVE_SIDE_STRICT;
  227. }
  228. else if (numZero == 1)
  229. {
  230. result.configuration = Configuration::POSITIVE_SIDE_VERTEX;
  231. result.intersection =
  232. {
  233. polygon[zeroHeightIndices[0]]
  234. };
  235. }
  236. else // numZero > 1
  237. {
  238. result.configuration = Configuration::POSITIVE_SIDE_EDGE;
  239. result.intersection =
  240. {
  241. polygon[zeroHeightIndices[0]],
  242. polygon[zeroHeightIndices[1]]
  243. };
  244. }
  245. result.positivePolygon = polygon;
  246. }
  247. }
  248. else if (numNegative > 0)
  249. {
  250. size_t numZero = zeroHeightIndices.size();
  251. if (numZero == 0)
  252. {
  253. result.configuration = Configuration::NEGATIVE_SIDE_STRICT;
  254. }
  255. else if (numZero == 1)
  256. {
  257. result.configuration = Configuration::NEGATIVE_SIDE_VERTEX;
  258. result.intersection =
  259. {
  260. polygon[zeroHeightIndices[0]]
  261. };
  262. }
  263. else // numZero > 1
  264. {
  265. result.configuration = Configuration::NEGATIVE_SIDE_EDGE;
  266. result.intersection =
  267. {
  268. polygon[zeroHeightIndices[0]],
  269. polygon[zeroHeightIndices[1]]
  270. };
  271. }
  272. result.negativePolygon = polygon;
  273. }
  274. else // numZero == numVertices
  275. {
  276. result.configuration = Configuration::CONTAINED;
  277. result.intersection = polygon;
  278. }
  279. return result;
  280. }
  281. protected:
  282. void SplitPolygon(std::vector<Vector<N, Real>> const& polygon,
  283. std::vector<Real> const& height, size_t maxPosIndex, Result& result)
  284. {
  285. // Find the largest contiguous subset of indices for which
  286. // height[i] >= 0.
  287. size_t const numVertices = polygon.size();
  288. std::list<Vector<N, Real>> positiveList;
  289. positiveList.push_back(polygon[maxPosIndex]);
  290. size_t end0 = maxPosIndex;
  291. size_t end0prev = std::numeric_limits<size_t>::max();
  292. for (size_t i = 0; i < numVertices; ++i)
  293. {
  294. end0prev = (end0 + numVertices - 1) % numVertices;
  295. if (height[end0prev] >= (Real)0)
  296. {
  297. positiveList.push_front(polygon[end0prev]);
  298. end0 = end0prev;
  299. }
  300. else
  301. {
  302. break;
  303. }
  304. }
  305. size_t end1 = maxPosIndex;
  306. size_t end1next = std::numeric_limits<size_t>::max();
  307. for (size_t i = 0; i < numVertices; ++i)
  308. {
  309. end1next = (end1 + 1) % numVertices;
  310. if (height[end1next] >= (Real)0)
  311. {
  312. positiveList.push_back(polygon[end1next]);
  313. end1 = end1next;
  314. }
  315. else
  316. {
  317. break;
  318. }
  319. }
  320. size_t index = end1next;
  321. std::list<Vector<N, Real>> negativeList;
  322. for (size_t i = 0; i < numVertices; ++i)
  323. {
  324. negativeList.push_back(polygon[index]);
  325. index = (index + 1) % numVertices;
  326. if (index == end0)
  327. {
  328. break;
  329. }
  330. }
  331. // Clip the polygon.
  332. if (height[end0] > (Real)0)
  333. {
  334. Real t = -height[end0prev] / (height[end0] - height[end0prev]);
  335. Real omt = (Real)1 - t;
  336. Vector<N, Real> V = omt * polygon[end0prev] + t * polygon[end0];
  337. positiveList.push_front(V);
  338. negativeList.push_back(V);
  339. result.intersection.push_back(V);
  340. }
  341. else
  342. {
  343. negativeList.push_back(polygon[end0]);
  344. result.intersection.push_back(polygon[end0]);
  345. }
  346. if (height[end1] > (Real)0)
  347. {
  348. Real t = -height[end1next] / (height[end1] - height[end1next]);
  349. Real omt = (Real)1 - t;
  350. Vector<N, Real> V = omt * polygon[end1next] + t * polygon[end1];
  351. positiveList.push_back(V);
  352. negativeList.push_front(V);
  353. result.intersection.push_back(V);
  354. }
  355. else
  356. {
  357. negativeList.push_front(polygon[end1]);
  358. result.intersection.push_back(polygon[end1]);
  359. }
  360. result.positivePolygon.reserve(positiveList.size());
  361. for (auto const& p : positiveList)
  362. {
  363. result.positivePolygon.push_back(p);
  364. }
  365. result.negativePolygon.reserve(negativeList.size());
  366. for (auto const& p : negativeList)
  367. {
  368. result.negativePolygon.push_back(p);
  369. }
  370. }
  371. };
  372. }