DisjointRectangles.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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/DisjointIntervals.h>
  9. #include <functional>
  10. namespace WwiseGTE
  11. {
  12. // Compute Boolean operations of disjoint sets of half-open rectangles of
  13. // the form [xmin,xmax)x[ymin,ymax) with xmin < xmax and ymin < ymax.
  14. template <typename Scalar>
  15. class DisjointRectangles
  16. {
  17. public:
  18. // Convenient type definition.
  19. typedef DisjointIntervals<Scalar> ISet;
  20. // Construction and destruction. The non-default constructor requires
  21. // that xmin < xmax and ymin < ymax.
  22. DisjointRectangles()
  23. :
  24. mNumRectangles(0)
  25. {
  26. }
  27. DisjointRectangles(Scalar const& xmin, Scalar const& xmax, Scalar const& ymin, Scalar const& ymax)
  28. {
  29. if (xmin < xmax && ymin < ymax)
  30. {
  31. mNumRectangles = 1;
  32. mStrips.push_back(Strip(ymin, ymax, ISet(xmin, xmax)));
  33. }
  34. else
  35. {
  36. mNumRectangles = 0;
  37. }
  38. }
  39. ~DisjointRectangles()
  40. {
  41. }
  42. // Copy operations.
  43. DisjointRectangles(DisjointRectangles const& other)
  44. {
  45. *this = other;
  46. }
  47. DisjointRectangles& operator=(DisjointRectangles const& other)
  48. {
  49. mNumRectangles = other.mNumRectangles;
  50. mStrips = other.mStrips;
  51. return *this;
  52. }
  53. // Move operations.
  54. DisjointRectangles(DisjointRectangles&& other)
  55. {
  56. *this = std::move(other);
  57. }
  58. DisjointRectangles& operator=(DisjointRectangles&& other)
  59. {
  60. mNumRectangles = other.mNumRectangles;
  61. mStrips = std::move(other.mStrips);
  62. return *this;
  63. }
  64. // The rectangle set consists of y-strips of interval sets.
  65. class Strip
  66. {
  67. public:
  68. // Construction and destruction.
  69. Strip()
  70. :
  71. ymin((Scalar)0),
  72. ymax((Scalar)0)
  73. {
  74. }
  75. Strip(Scalar const& inYMin, Scalar const& inYMax, ISet const& inIntervalSet)
  76. :
  77. ymin(inYMin),
  78. ymax(inYMax),
  79. intervalSet(inIntervalSet)
  80. {
  81. }
  82. ~Strip()
  83. {
  84. }
  85. // Copy operations.
  86. Strip(Strip const& other)
  87. {
  88. *this = other;
  89. }
  90. Strip& operator=(Strip const& other)
  91. {
  92. ymin = other.ymin;
  93. ymax = other.ymax;
  94. intervalSet = other.intervalSet;
  95. return *this;
  96. }
  97. // Move operations.
  98. Strip(Strip&& other)
  99. {
  100. *this = std::move(other);
  101. }
  102. Strip& operator=(Strip&& other)
  103. {
  104. ymin = other.ymin;
  105. ymax = other.ymax;
  106. intervalSet = std::move(other.intervalSet);
  107. other.ymin = (Scalar)0;
  108. other.ymax = (Scalar)0;
  109. return *this;
  110. }
  111. // Member access.
  112. Scalar ymin, ymax;
  113. ISet intervalSet;
  114. };
  115. // The number of rectangles in the set.
  116. inline int GetNumRectangles() const
  117. {
  118. return mNumRectangles;
  119. }
  120. // The i-th rectangle is [xmin,xmax)x[ymin,ymax). The values xmin,
  121. // xmax, ymin and ymax are valid when 0 <= i < GetNumRectangles().
  122. bool GetRectangle(int i, Scalar& xmin, Scalar& xmax, Scalar& ymin, Scalar& ymax) const
  123. {
  124. int totalQuantity = 0;
  125. for (auto const& strip : mStrips)
  126. {
  127. ISet const& intervalSet = strip.intervalSet;
  128. int xQuantity = intervalSet.GetNumIntervals();
  129. int nextTotalQuantity = totalQuantity + xQuantity;
  130. if (i < nextTotalQuantity)
  131. {
  132. i -= totalQuantity;
  133. intervalSet.GetInterval(i, xmin, xmax);
  134. ymin = strip.ymin;
  135. ymax = strip.ymax;
  136. return true;
  137. }
  138. totalQuantity = nextTotalQuantity;
  139. }
  140. return false;
  141. }
  142. // Make this set empty.
  143. inline void Clear()
  144. {
  145. mNumRectangles = 0;
  146. mStrips.clear();
  147. }
  148. // The number of y-strips in the set.
  149. inline int GetNumStrips() const
  150. {
  151. return static_cast<int>(mStrips.size());
  152. }
  153. // The i-th strip. The returned values are valid when
  154. // 0 <= i < GetStripQuantity().
  155. bool GetStrip(int i, Scalar& ymin, Scalar& ymax, ISet& xIntervalSet) const
  156. {
  157. if (0 <= i && i < GetNumStrips())
  158. {
  159. Strip const& strip = mStrips[i];
  160. ymin = strip.ymin;
  161. ymax = strip.ymax;
  162. xIntervalSet = strip.intervalSet;
  163. return true;
  164. }
  165. return false;
  166. }
  167. // Insert [xmin,xmax)x[ymin,ymax) into the set. This is a Boolean
  168. // union operation. The operation is successful only when xmin < xmax
  169. // and ymin < ymax.
  170. bool Insert(Scalar const& xmin, Scalar const& xmax, Scalar const& ymin, Scalar const& ymax)
  171. {
  172. if (xmin < xmax && ymin < ymax)
  173. {
  174. DisjointRectangles input(xmin, xmax, ymin, ymax);
  175. DisjointRectangles output = *this | input;
  176. *this = std::move(output);
  177. return true;
  178. }
  179. return false;
  180. }
  181. // Remove [xmin,xmax)x[ymin,ymax) from the set. This is a Boolean
  182. // difference operation. The operation is successful only when
  183. // xmin < xmax and ymin < ymax.
  184. bool Remove(Scalar const& xmin, Scalar const& xmax, Scalar const& ymin, Scalar const& ymax)
  185. {
  186. if (xmin < xmax && ymin < ymax)
  187. {
  188. DisjointRectangles input(xmin, xmax, ymin, ymax);
  189. DisjointRectangles output = *this - input;
  190. *this = std::move(output);
  191. return true;
  192. }
  193. return false;
  194. }
  195. // Get the union of the rectangle sets sets, input0 union input1.
  196. friend DisjointRectangles operator|(DisjointRectangles const& input0, DisjointRectangles const& input1)
  197. {
  198. return Execute(
  199. [](ISet const& i0, ISet const& i1) { return i0 | i1; },
  200. true, true, input0, input1);
  201. }
  202. // Get the intersection of the rectangle sets, input0 intersect is1.
  203. friend DisjointRectangles operator&(DisjointRectangles const& input0, DisjointRectangles const& input1)
  204. {
  205. return Execute(
  206. [](ISet const& i0, ISet const& i1) { return i0 & i1; },
  207. false, false, input0, input1);
  208. }
  209. // Get the differences of the rectangle sets, input0 minus input1.
  210. friend DisjointRectangles operator-(DisjointRectangles const& input0, DisjointRectangles const& input1)
  211. {
  212. return Execute(
  213. [](ISet const& i0, ISet const& i1) { return i0 - i1; },
  214. false, true, input0, input1);
  215. }
  216. // Get the exclusive or of the rectangle sets, input0 xor input1 =
  217. // (input0 minus input1) or (input1 minus input0).
  218. friend DisjointRectangles operator^(DisjointRectangles const& input0, DisjointRectangles const& input1)
  219. {
  220. return Execute(
  221. [](ISet const& i0, ISet const& i1) { return i0 ^ i1; },
  222. true, true, input0, input1);
  223. }
  224. private:
  225. static DisjointRectangles Execute(
  226. std::function<ISet(ISet const&, ISet const&)> const& operation,
  227. bool unionExclusiveOr, bool unionExclusiveOrDifference,
  228. DisjointRectangles const& input0, DisjointRectangles const& input1)
  229. {
  230. DisjointRectangles output;
  231. size_t const numStrips0 = input0.GetNumStrips();
  232. size_t const numStrips1 = input1.GetNumStrips();
  233. size_t i0 = 0, i1 = 0;
  234. bool getOriginal0 = true, getOriginal1 = true;
  235. Scalar ymin0 = (Scalar)0;
  236. Scalar ymax0 = (Scalar)0;
  237. Scalar ymin1 = (Scalar)0;
  238. Scalar ymax1 = (Scalar)0;
  239. while (i0 < numStrips0 && i1 < numStrips1)
  240. {
  241. ISet const& intr0 = input0.mStrips[i0].intervalSet;
  242. if (getOriginal0)
  243. {
  244. ymin0 = input0.mStrips[i0].ymin;
  245. ymax0 = input0.mStrips[i0].ymax;
  246. }
  247. ISet const& intr1 = input1.mStrips[i1].intervalSet;
  248. if (getOriginal1)
  249. {
  250. ymin1 = input1.mStrips[i1].ymin;
  251. ymax1 = input1.mStrips[i1].ymax;
  252. }
  253. // Case 1.
  254. if (ymax1 <= ymin0)
  255. {
  256. // operator(empty,strip1)
  257. if (unionExclusiveOr)
  258. {
  259. output.mStrips.push_back(Strip(ymin1, ymax1, intr1));
  260. }
  261. ++i1;
  262. getOriginal0 = false;
  263. getOriginal1 = true;
  264. continue; // using next ymin1/ymax1
  265. }
  266. // Case 11.
  267. if (ymin1 >= ymax0)
  268. {
  269. // operator(strip0,empty)
  270. if (unionExclusiveOrDifference)
  271. {
  272. output.mStrips.push_back(Strip(ymin0, ymax0, intr0));
  273. }
  274. ++i0;
  275. getOriginal0 = true;
  276. getOriginal1 = false;
  277. continue; // using next ymin0/ymax0
  278. }
  279. // Reduce cases 2, 3, 4 to cases 5, 6, 7.
  280. if (ymin1 < ymin0)
  281. {
  282. // operator(empty,[ymin1,ymin0))
  283. if (unionExclusiveOr)
  284. {
  285. output.mStrips.push_back(Strip(ymin1, ymin0, intr1));
  286. }
  287. ymin1 = ymin0;
  288. getOriginal1 = false;
  289. }
  290. // Reduce cases 8, 9, 10 to cases 5, 6, 7.
  291. if (ymin1 > ymin0)
  292. {
  293. // operator([ymin0,ymin1),empty)
  294. if (unionExclusiveOrDifference)
  295. {
  296. output.mStrips.push_back(Strip(ymin0, ymin1, intr0));
  297. }
  298. ymin0 = ymin1;
  299. getOriginal0 = false;
  300. }
  301. // Case 5.
  302. if (ymax1 < ymax0)
  303. {
  304. // operator(strip0,[ymin1,ymax1))
  305. auto result = operation(intr0, intr1);
  306. output.mStrips.push_back(Strip(ymin1, ymax1, result));
  307. ymin0 = ymax1;
  308. ++i1;
  309. getOriginal0 = false;
  310. getOriginal1 = true;
  311. continue; // using next ymin1/ymax1
  312. }
  313. // Case 6.
  314. if (ymax1 == ymax0)
  315. {
  316. // operator(strip0,[ymin1,ymax1))
  317. auto result = operation(intr0, intr1);
  318. output.mStrips.push_back(Strip(ymin1, ymax1, result));
  319. ++i0;
  320. ++i1;
  321. getOriginal0 = true;
  322. getOriginal1 = true;
  323. continue; // using next ymin0/ymax0 and ymin1/ymax1
  324. }
  325. // Case 7.
  326. if (ymax1 > ymax0)
  327. {
  328. // operator(strip0,[ymin1,ymax0))
  329. auto result = operation(intr0, intr1);
  330. output.mStrips.push_back(Strip(ymin1, ymax0, result));
  331. ymin1 = ymax0;
  332. ++i0;
  333. getOriginal0 = true;
  334. getOriginal1 = false;
  335. // continue; using current ymin1/ymax1
  336. }
  337. }
  338. if (unionExclusiveOrDifference)
  339. {
  340. while (i0 < numStrips0)
  341. {
  342. if (getOriginal0)
  343. {
  344. ymin0 = input0.mStrips[i0].ymin;
  345. ymax0 = input0.mStrips[i0].ymax;
  346. }
  347. else
  348. {
  349. getOriginal0 = true;
  350. }
  351. // operator(strip0,empty)
  352. output.mStrips.push_back(Strip(ymin0, ymax0,
  353. input0.mStrips[i0].intervalSet));
  354. ++i0;
  355. }
  356. }
  357. if (unionExclusiveOr)
  358. {
  359. while (i1 < numStrips1)
  360. {
  361. if (getOriginal1)
  362. {
  363. ymin1 = input1.mStrips[i1].ymin;
  364. ymax1 = input1.mStrips[i1].ymax;
  365. }
  366. else
  367. {
  368. getOriginal1 = true;
  369. }
  370. // operator(empty,strip1)
  371. output.mStrips.push_back(Strip(ymin1, ymax1,
  372. input1.mStrips[i1].intervalSet));
  373. ++i1;
  374. }
  375. }
  376. output.ComputeRectangleQuantity();
  377. return output;
  378. }
  379. void ComputeRectangleQuantity()
  380. {
  381. mNumRectangles = 0;
  382. for (auto strip : mStrips)
  383. {
  384. mNumRectangles += strip.intervalSet.GetNumIntervals();
  385. }
  386. }
  387. // The number of rectangles in the set.
  388. int mNumRectangles;
  389. // The y-strips of the set, each containing an x-interval set.
  390. std::vector<Strip> mStrips;
  391. };
  392. }