IsPlanarGraph.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  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 <algorithm>
  9. #include <array>
  10. #include <map>
  11. #include <set>
  12. #include <vector>
  13. // Test whether an undirected graph is planar. The input positions must be
  14. // unique and the input edges must be unique, so the number of positions is
  15. // at least 2 and the number of edges is at least one. The elements of the
  16. // edges array must be indices in {0,..,positions.size()-1}.
  17. //
  18. // A sort-and-sweep algorithm is used to determine edge-edge intersections.
  19. // If none of the intersections occur at edge-interior points, the graph is
  20. // planar. See Game Physics (2nd edition), Section 6.2.2: Culling with
  21. // Axis-Aligned Bounding Boxes for such an algorithm. The operator()
  22. // returns 'true' when the graph is planar. If it returns 'false', the
  23. // 'invalidIntersections' set contains pairs of edges that intersect at an
  24. // edge-interior point (that by definition is not a graph vertex). Each set
  25. // element is a pair of indices into the 'edges' array; the indices are
  26. // ordered so that element[0] < element[1]. The Real type must be chosen
  27. // to guarantee exact computation of edge-edge intersections.
  28. namespace WwiseGTE
  29. {
  30. template <typename Real>
  31. class IsPlanarGraph
  32. {
  33. public:
  34. IsPlanarGraph()
  35. :
  36. mZero(0),
  37. mOne(1)
  38. {
  39. }
  40. enum
  41. {
  42. IPG_IS_PLANAR_GRAPH = 0,
  43. IPG_INVALID_INPUT_SIZES = 1,
  44. IPG_DUPLICATED_POSITIONS = 2,
  45. IPG_DUPLICATED_EDGES = 4,
  46. IPG_DEGENERATE_EDGES = 8,
  47. IPG_EDGES_WITH_INVALID_VERTICES = 16,
  48. IPG_INVALID_INTERSECTIONS = 32
  49. };
  50. // The function returns a combination of the IPG_* flags listed in the
  51. // previous enumeration. A combined value of 0 indicates the input
  52. // forms a planar graph. If the combined value is not zero, you may
  53. // examine the flags for the failure conditions and use the Get*
  54. // member accessors to obtain specific information about the failure.
  55. // If the positions.size() < 2 or edges.size() == 0, the
  56. // IPG_INVALID_INPUT_SIZES flag is set.
  57. int operator()(std::vector<std::array<Real, 2>> const& positions,
  58. std::vector<std::array<int, 2>> const& edges)
  59. {
  60. mDuplicatedPositions.clear();
  61. mDuplicatedEdges.clear();
  62. mDegenerateEdges.clear();
  63. mEdgesWithInvalidVertices.clear();
  64. mInvalidIntersections.clear();
  65. int flags = IsValidTopology(positions, edges);
  66. if (flags == IPG_INVALID_INPUT_SIZES)
  67. {
  68. return flags;
  69. }
  70. std::set<OrderedEdge> overlappingRectangles;
  71. ComputeOverlappingRectangles(positions, edges, overlappingRectangles);
  72. for (auto key : overlappingRectangles)
  73. {
  74. // Get the endpoints of the line segments for the edges whose
  75. // bounding rectangles overlapped. Determine whether the line
  76. // segments intersect. If they do, determine how they
  77. // intersect.
  78. std::array<int, 2> e0 = edges[key.V[0]];
  79. std::array<int, 2> e1 = edges[key.V[1]];
  80. std::array<Real, 2> const& p0 = positions[e0[0]];
  81. std::array<Real, 2> const& p1 = positions[e0[1]];
  82. std::array<Real, 2> const& q0 = positions[e1[0]];
  83. std::array<Real, 2> const& q1 = positions[e1[1]];
  84. if (InvalidSegmentIntersection(p0, p1, q0, q1))
  85. {
  86. mInvalidIntersections.push_back(key);
  87. }
  88. }
  89. if (mInvalidIntersections.size() > 0)
  90. {
  91. flags |= IPG_INVALID_INTERSECTIONS;
  92. }
  93. return flags;
  94. }
  95. // A pair of indices (v0,v1) into the positions array is stored as
  96. // (min(v0,v1), max(v0,v1)). This supports sorted containers of
  97. // edges.
  98. struct OrderedEdge
  99. {
  100. OrderedEdge(int v0 = -1, int v1 = -1)
  101. {
  102. if (v0 < v1)
  103. {
  104. // v0 is minimum
  105. V[0] = v0;
  106. V[1] = v1;
  107. }
  108. else
  109. {
  110. // v1 is minimum
  111. V[0] = v1;
  112. V[1] = v0;
  113. }
  114. }
  115. bool operator<(OrderedEdge const& edge) const
  116. {
  117. // Lexicographical ordering used by std::array<int,2>.
  118. return V < edge.V;
  119. }
  120. std::array<int, 2> V;
  121. };
  122. inline std::vector<std::vector<int>> const& GetDuplicatedPositions() const
  123. {
  124. return mDuplicatedPositions;
  125. }
  126. inline std::vector<std::vector<int>> const& GetDuplicatedEdges() const
  127. {
  128. return mDuplicatedEdges;
  129. }
  130. inline std::vector<int> const& GetDegenerateEdges() const
  131. {
  132. return mDegenerateEdges;
  133. }
  134. inline std::vector<int> const& GetEdgesWithInvalidVertices() const
  135. {
  136. return mEdgesWithInvalidVertices;
  137. }
  138. inline std::vector<typename IsPlanarGraph<Real>::OrderedEdge> const&
  139. GetInvalidIntersections() const
  140. {
  141. return mInvalidIntersections;
  142. }
  143. private:
  144. class Endpoint
  145. {
  146. public:
  147. Real value; // endpoint value
  148. int type; // '0' if interval min, '1' if interval max.
  149. int index; // index of interval containing this endpoint
  150. // Comparison operator for sorting.
  151. bool operator<(Endpoint const& endpoint) const
  152. {
  153. if (value < endpoint.value)
  154. {
  155. return true;
  156. }
  157. if (value > endpoint.value)
  158. {
  159. return false;
  160. }
  161. return type < endpoint.type;
  162. }
  163. };
  164. int IsValidTopology(std::vector<std::array<Real, 2>> const& positions,
  165. std::vector<std::array<int, 2>> const& edges)
  166. {
  167. int const numPositions = static_cast<int>(positions.size());
  168. int const numEdges = static_cast<int>(edges.size());
  169. if (numPositions < 2 || numEdges == 0)
  170. {
  171. // The graph must have at least one edge.
  172. return IPG_INVALID_INPUT_SIZES;
  173. }
  174. // The positions must be unique.
  175. int flags = IPG_IS_PLANAR_GRAPH;
  176. std::map<std::array<Real, 2>, std::vector<int>> uniquePositions;
  177. for (int i = 0; i < numPositions; ++i)
  178. {
  179. std::array<Real, 2> p = positions[i];
  180. auto iter = uniquePositions.find(p);
  181. if (iter == uniquePositions.end())
  182. {
  183. std::vector<int> indices;
  184. indices.push_back(i);
  185. uniquePositions.insert(std::make_pair(p, indices));
  186. }
  187. else
  188. {
  189. iter->second.push_back(i);
  190. }
  191. }
  192. if (uniquePositions.size() < positions.size())
  193. {
  194. // At least two positions are duplicated.
  195. for (auto const& element : uniquePositions)
  196. {
  197. if (element.second.size() > 1)
  198. {
  199. mDuplicatedPositions.push_back(element.second);
  200. }
  201. }
  202. flags |= IPG_DUPLICATED_POSITIONS;
  203. }
  204. // The edges must be unique.
  205. std::map<OrderedEdge, std::vector<int>> uniqueEdges;
  206. for (int i = 0; i < numEdges; ++i)
  207. {
  208. OrderedEdge key(edges[i][0], edges[i][1]);
  209. auto iter = uniqueEdges.find(key);
  210. if (iter == uniqueEdges.end())
  211. {
  212. std::vector<int> indices;
  213. indices.push_back(i);
  214. uniqueEdges.insert(std::make_pair(key, indices));
  215. }
  216. else
  217. {
  218. iter->second.push_back(i);
  219. }
  220. }
  221. if (uniqueEdges.size() < edges.size())
  222. {
  223. // At least two edges are duplicated, possibly even a pair of
  224. // edges (v0,v1) and (v1,v0) which is not allowed because the
  225. // graph is undirected.
  226. for (auto const& element : uniqueEdges)
  227. {
  228. if (element.second.size() > 1)
  229. {
  230. mDuplicatedEdges.push_back(element.second);
  231. }
  232. }
  233. flags |= IPG_DUPLICATED_EDGES;
  234. }
  235. // The edges are represented as pairs of indices into the
  236. // 'positions' array. The indices for a single edge must be
  237. // different (no edges allowed from a vertex to itself) and all
  238. // indices must be valid. At the same time, keep track of unique
  239. // edges.
  240. for (int i = 0; i < numEdges; ++i)
  241. {
  242. std::array<int, 2> e = edges[i];
  243. if (e[0] == e[1])
  244. {
  245. // The edge is degenerate, originating and terminating at
  246. // the same vertex.
  247. mDegenerateEdges.push_back(i);
  248. flags |= IPG_DEGENERATE_EDGES;
  249. }
  250. if (e[0] < 0 || e[0] >= numPositions || e[1] < 0 || e[1] >= numPositions)
  251. {
  252. // The edge has an index that references a nonexistent
  253. // vertex.
  254. mEdgesWithInvalidVertices.push_back(i);
  255. flags |= IPG_EDGES_WITH_INVALID_VERTICES;
  256. }
  257. }
  258. return flags;
  259. }
  260. void ComputeOverlappingRectangles(std::vector<std::array<Real, 2>> const& positions,
  261. std::vector<std::array<int, 2>> const& edges,
  262. std::set<OrderedEdge>& overlappingRectangles) const
  263. {
  264. // Compute axis-aligned bounding rectangles for the edges.
  265. int const numEdges = static_cast<int>(edges.size());
  266. std::vector<std::array<Real, 2>> emin(numEdges);
  267. std::vector<std::array<Real, 2>> emax(numEdges);
  268. for (int i = 0; i < numEdges; ++i)
  269. {
  270. std::array<int, 2> e = edges[i];
  271. std::array<Real, 2> const& p0 = positions[e[0]];
  272. std::array<Real, 2> const& p1 = positions[e[1]];
  273. for (int j = 0; j < 2; ++j)
  274. {
  275. if (p0[j] < p1[j])
  276. {
  277. emin[i][j] = p0[j];
  278. emax[i][j] = p1[j];
  279. }
  280. else
  281. {
  282. emin[i][j] = p1[j];
  283. emax[i][j] = p0[j];
  284. }
  285. }
  286. }
  287. // Get the rectangle endpoints.
  288. int const numEndpoints = 2 * numEdges;
  289. std::vector<Endpoint> xEndpoints(numEndpoints);
  290. std::vector<Endpoint> yEndpoints(numEndpoints);
  291. for (int i = 0, j = 0; i < numEdges; ++i)
  292. {
  293. xEndpoints[j].type = 0;
  294. xEndpoints[j].value = emin[i][0];
  295. xEndpoints[j].index = i;
  296. yEndpoints[j].type = 0;
  297. yEndpoints[j].value = emin[i][1];
  298. yEndpoints[j].index = i;
  299. ++j;
  300. xEndpoints[j].type = 1;
  301. xEndpoints[j].value = emax[i][0];
  302. xEndpoints[j].index = i;
  303. yEndpoints[j].type = 1;
  304. yEndpoints[j].value = emax[i][1];
  305. yEndpoints[j].index = i;
  306. ++j;
  307. }
  308. // Sort the rectangle endpoints.
  309. std::sort(xEndpoints.begin(), xEndpoints.end());
  310. std::sort(yEndpoints.begin(), yEndpoints.end());
  311. // Sweep through the endpoints to determine overlapping
  312. // x-intervals. Use an active set of rectangles to reduce the
  313. // complexity of the algorithm.
  314. std::set<int> active;
  315. for (int i = 0; i < numEndpoints; ++i)
  316. {
  317. Endpoint const& endpoint = xEndpoints[i];
  318. int index = endpoint.index;
  319. if (endpoint.type == 0) // an interval 'begin' value
  320. {
  321. // In the 1D problem, the current interval overlaps with
  322. // all the active intervals. In 2D this we also need to
  323. // check for y-overlap.
  324. for (auto activeIndex : active)
  325. {
  326. // Rectangles activeIndex and index overlap in the
  327. // x-dimension. Test for overlap in the y-dimension.
  328. std::array<Real, 2> const& r0min = emin[activeIndex];
  329. std::array<Real, 2> const& r0max = emax[activeIndex];
  330. std::array<Real, 2> const& r1min = emin[index];
  331. std::array<Real, 2> const& r1max = emax[index];
  332. if (r0max[1] >= r1min[1] && r0min[1] <= r1max[1])
  333. {
  334. if (activeIndex < index)
  335. {
  336. overlappingRectangles.insert(OrderedEdge(activeIndex, index));
  337. }
  338. else
  339. {
  340. overlappingRectangles.insert(OrderedEdge(index, activeIndex));
  341. }
  342. }
  343. }
  344. active.insert(index);
  345. }
  346. else // an interval 'end' value
  347. {
  348. active.erase(index);
  349. }
  350. }
  351. }
  352. bool InvalidSegmentIntersection(
  353. std::array<Real, 2> const& p0, std::array<Real, 2> const& p1,
  354. std::array<Real, 2> const& q0, std::array<Real, 2> const& q1) const
  355. {
  356. // We must solve the two linear equations
  357. // p0 + t0 * (p1 - p0) = q0 + t1 * (q1 - q0)
  358. // for the unknown variables t0 and t1. These may be written as
  359. // t0 * (p1 - p0) - t1 * (q1 - q0) = q0 - p0
  360. // If denom = Dot(p1 - p0, Perp(q1 - q0)) is not zero, then
  361. // t0 = Dot(q0 - p0, Perp(q1 - q0)) / denom = numer0 / denom
  362. // t1 = Dot(q0 - p0, Perp(p1 - p0)) / denom = numer1 / denom
  363. // For an invalid intersection, we need (t0,t1) with:
  364. // ((0 < t0 < 1) and (0 <= t1 <= 1)) or ((0 <= t0 <= 1) and
  365. // (0 < t1 < 1).
  366. std::array<Real, 2> p1mp0, q1mq0, q0mp0;
  367. for (int j = 0; j < 2; ++j)
  368. {
  369. p1mp0[j] = p1[j] - p0[j];
  370. q1mq0[j] = q1[j] - q0[j];
  371. q0mp0[j] = q0[j] - p0[j];
  372. }
  373. Real denom = p1mp0[0] * q1mq0[1] - p1mp0[1] * q1mq0[0];
  374. Real numer0 = q0mp0[0] * q1mq0[1] - q0mp0[1] * q1mq0[0];
  375. Real numer1 = q0mp0[0] * p1mp0[1] - q0mp0[1] * p1mp0[0];
  376. if (denom != mZero)
  377. {
  378. // The lines of the segments are not parallel.
  379. if (denom > mZero)
  380. {
  381. if (mZero <= numer0 && numer0 <= denom && mZero <= numer1 && numer1 <= denom)
  382. {
  383. // The segments intersect.
  384. return (numer0 != mZero && numer0 != denom) || (numer1 != mZero && numer1 != denom);
  385. }
  386. else
  387. {
  388. return false;
  389. }
  390. }
  391. else // denom < mZero
  392. {
  393. if (mZero >= numer0 && numer0 >= denom && mZero >= numer1 && numer1 >= denom)
  394. {
  395. // The segments intersect.
  396. return (numer0 != mZero && numer0 != denom) || (numer1 != mZero && numer1 != denom);
  397. }
  398. else
  399. {
  400. return false;
  401. }
  402. }
  403. }
  404. else
  405. {
  406. // The lines of the segments are parallel.
  407. if (numer0 != mZero || numer1 != mZero)
  408. {
  409. // The lines of the segments are separated.
  410. return false;
  411. }
  412. else
  413. {
  414. // The segments lie on the same line. Compute the
  415. // parameter intervals for the segments in terms of the
  416. // t0-parameter and determine their overlap (if any).
  417. std::array<Real, 2> q1mp0;
  418. for (int j = 0; j < 2; ++j)
  419. {
  420. q1mp0[j] = q1[j] - p0[j];
  421. }
  422. Real sqrLenP1mP0 = p1mp0[0] * p1mp0[0] + p1mp0[1] * p1mp0[1];
  423. Real value0 = q0mp0[0] * p1mp0[0] + q0mp0[1] * p1mp0[1];
  424. Real value1 = q1mp0[0] * p1mp0[0] + q1mp0[1] * p1mp0[1];
  425. if ((value0 >= sqrLenP1mP0 && value1 >= sqrLenP1mP0)
  426. || (value0 <= mZero && value1 <= mZero))
  427. {
  428. // If the segments intersect, they must do so at
  429. // endpoints of the segments.
  430. return false;
  431. }
  432. else
  433. {
  434. // The segments overlap in a positive-length interval.
  435. return true;
  436. }
  437. }
  438. }
  439. }
  440. std::vector<std::vector<int>> mDuplicatedPositions;
  441. std::vector<std::vector<int>> mDuplicatedEdges;
  442. std::vector<int> mDegenerateEdges;
  443. std::vector<int> mEdgesWithInvalidVertices;
  444. std::vector<OrderedEdge> mInvalidIntersections;
  445. Real mZero, mOne;
  446. };
  447. }