BoxManager.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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/IntrAlignedBox3AlignedBox3.h>
  9. #include <Mathematics/EdgeKey.h>
  10. #include <set>
  11. #include <vector>
  12. namespace WwiseGTE
  13. {
  14. template <typename Real>
  15. class BoxManager
  16. {
  17. public:
  18. // Construction.
  19. BoxManager(std::vector<AlignedBox3<Real>>& boxes)
  20. :
  21. mBoxes(boxes)
  22. {
  23. Initialize();
  24. }
  25. // No default construction, copy construction, or assignment are
  26. // allowed.
  27. BoxManager() = delete;
  28. BoxManager(BoxManager const&) = delete;
  29. BoxManager& operator=(BoxManager const&) = delete;
  30. // This function is called by the constructor and does the
  31. // sort-and-sweep to initialize the update system. However, if you
  32. // add or remove items from the array of boxes after the constructor
  33. // call, you will need to call this function once before you start the
  34. // multiple calls of the update function.
  35. void Initialize()
  36. {
  37. // Get the box endpoints.
  38. int intrSize = static_cast<int>(mBoxes.size()), endpSize = 2 * intrSize;
  39. mXEndpoints.resize(endpSize);
  40. mYEndpoints.resize(endpSize);
  41. mZEndpoints.resize(endpSize);
  42. for (int i = 0, j = 0; i < intrSize; ++i)
  43. {
  44. mXEndpoints[j].type = 0;
  45. mXEndpoints[j].value = mBoxes[i].min[0];
  46. mXEndpoints[j].index = i;
  47. mYEndpoints[j].type = 0;
  48. mYEndpoints[j].value = mBoxes[i].min[1];
  49. mYEndpoints[j].index = i;
  50. mZEndpoints[j].type = 0;
  51. mZEndpoints[j].value = mBoxes[i].min[2];
  52. mZEndpoints[j].index = i;
  53. ++j;
  54. mXEndpoints[j].type = 1;
  55. mXEndpoints[j].value = mBoxes[i].max[0];
  56. mXEndpoints[j].index = i;
  57. mYEndpoints[j].type = 1;
  58. mYEndpoints[j].value = mBoxes[i].max[1];
  59. mYEndpoints[j].index = i;
  60. mZEndpoints[j].type = 1;
  61. mZEndpoints[j].value = mBoxes[i].max[2];
  62. mZEndpoints[j].index = i;
  63. ++j;
  64. }
  65. // Sort the rectangle endpoints.
  66. std::sort(mXEndpoints.begin(), mXEndpoints.end());
  67. std::sort(mYEndpoints.begin(), mYEndpoints.end());
  68. std::sort(mZEndpoints.begin(), mZEndpoints.end());
  69. // Create the interval-to-endpoint lookup tables.
  70. mXLookup.resize(endpSize);
  71. mYLookup.resize(endpSize);
  72. mZLookup.resize(endpSize);
  73. for (int j = 0; j < endpSize; ++j)
  74. {
  75. mXLookup[2 * mXEndpoints[j].index + mXEndpoints[j].type] = j;
  76. mYLookup[2 * mYEndpoints[j].index + mYEndpoints[j].type] = j;
  77. mZLookup[2 * mZEndpoints[j].index + mZEndpoints[j].type] = j;
  78. }
  79. // Active set of rectangles (stored by index in array).
  80. std::set<int> active;
  81. // Set of overlapping rectangles (stored by pairs of indices in
  82. // array).
  83. mOverlap.clear();
  84. // Sweep through the endpoints to determine overlapping
  85. // x-intervals.
  86. for (int i = 0; i < endpSize; ++i)
  87. {
  88. Endpoint& endpoint = mXEndpoints[i];
  89. int index = endpoint.index;
  90. if (endpoint.type == 0) // an interval 'begin' value
  91. {
  92. // In the 1D problem, the current interval overlaps with
  93. // all the active intervals. In 3D we also need to check
  94. // for y-overlap and z-overlap.
  95. for (auto activeIndex : active)
  96. {
  97. // Rectangles activeIndex and index overlap in the
  98. // x-dimension. Test for overlap in the y-dimension
  99. // and z-dimension.
  100. AlignedBox3<Real> const& b0 = mBoxes[activeIndex];
  101. AlignedBox3<Real> const& b1 = mBoxes[index];
  102. if (b0.max[1] >= b1.min[1] && b0.min[1] <= b1.max[1]
  103. && b0.max[2] >= b1.min[2] && b0.min[2] <= b1.max[2])
  104. {
  105. if (activeIndex < index)
  106. {
  107. mOverlap.insert(EdgeKey<false>(activeIndex, index));
  108. }
  109. else
  110. {
  111. mOverlap.insert(EdgeKey<false>(index, activeIndex));
  112. }
  113. }
  114. }
  115. active.insert(index);
  116. }
  117. else // an interval 'end' value
  118. {
  119. active.erase(index);
  120. }
  121. }
  122. }
  123. // After the system is initialized, you can move the boxes using this
  124. // function. It is not enough to modify the input array of boxes
  125. // because the endpoint values stored internally by this class must
  126. // also change. You can also retrieve the current rectangles
  127. // information.
  128. void SetBox(int i, AlignedBox3<Real> const& box)
  129. {
  130. mBoxes[i] = box;
  131. mXEndpoints[mXLookup[2 * i]].value = box.min[0];
  132. mXEndpoints[mXLookup[2 * i + 1]].value = box.max[0];
  133. mYEndpoints[mYLookup[2 * i]].value = box.min[1];
  134. mYEndpoints[mYLookup[2 * i + 1]].value = box.max[1];
  135. mZEndpoints[mZLookup[2 * i]].value = box.min[2];
  136. mZEndpoints[mZLookup[2 * i + 1]].value = box.max[2];
  137. }
  138. inline void GetBox(int i, AlignedBox3<Real>& box) const
  139. {
  140. box = mBoxes[i];
  141. }
  142. // When you are finished moving boxes, call this function to determine
  143. // the overlapping boxes. An incremental update is applied to
  144. // determine the new set of overlapping boxes.
  145. void Update()
  146. {
  147. InsertionSort(mXEndpoints, mXLookup);
  148. InsertionSort(mYEndpoints, mYLookup);
  149. InsertionSort(mZEndpoints, mZLookup);
  150. }
  151. // If (i,j) is in the overlap set, then box i and box j are
  152. // overlapping. The indices are those for the the input array. The
  153. // set elements (i,j) are stored so that i < j.
  154. inline std::set<EdgeKey<false>> const& GetOverlap() const
  155. {
  156. return mOverlap;
  157. }
  158. private:
  159. class Endpoint
  160. {
  161. public:
  162. Real value; // endpoint value
  163. int type; // '0' if interval min, '1' if interval max.
  164. int index; // index of interval containing this endpoint
  165. // Support for sorting of endpoints.
  166. bool operator<(Endpoint const& endpoint) const
  167. {
  168. if (value < endpoint.value)
  169. {
  170. return true;
  171. }
  172. if (value > endpoint.value)
  173. {
  174. return false;
  175. }
  176. return type < endpoint.type;
  177. }
  178. };
  179. void InsertionSort(std::vector<Endpoint>& endpoint, std::vector<int>& lookup)
  180. {
  181. // Apply an insertion sort. Under the assumption that the
  182. // rectangles have not changed much since the last call, the
  183. // endpoints are nearly sorted. The insertion sort should be very
  184. // fast in this case.
  185. TIQuery<Real, AlignedBox3<Real>, AlignedBox3<Real>> query;
  186. int endpSize = static_cast<int>(endpoint.size());
  187. for (int j = 1; j < endpSize; ++j)
  188. {
  189. Endpoint key = endpoint[j];
  190. int i = j - 1;
  191. while (i >= 0 && key < endpoint[i])
  192. {
  193. Endpoint e0 = endpoint[i];
  194. Endpoint e1 = endpoint[i + 1];
  195. // Update the overlap status.
  196. if (e0.type == 0)
  197. {
  198. if (e1.type == 1)
  199. {
  200. // The 'b' of interval E0.mIndex was smaller than
  201. // the 'e' of interval E1.mIndex, and the
  202. // intervals *might have been* overlapping. Now
  203. // 'b' and 'e' are swapped, and the intervals
  204. // cannot overlap. Remove the pair from the
  205. // overlap set. The removal operation needs to
  206. // find the pair and erase it if it exists.
  207. // Finding the pair is the expensive part of the
  208. // operation, so there is no real time savings in
  209. // testing for existence first, then deleting if
  210. // it does.
  211. mOverlap.erase(EdgeKey<false>(e0.index, e1.index));
  212. }
  213. }
  214. else
  215. {
  216. if (e1.type == 0)
  217. {
  218. // The 'b' of interval E1.index was larger than
  219. // the 'e' of interval E0.index, and the intervals
  220. // were not overlapping. Now 'b' and 'e' are
  221. // swapped, and the intervals *might be*
  222. // overlapping. Determine if they are overlapping
  223. // and then insert.
  224. if (query(mBoxes[e0.index], mBoxes[e1.index]).intersect)
  225. {
  226. mOverlap.insert(EdgeKey<false>(e0.index, e1.index));
  227. }
  228. }
  229. }
  230. // Reorder the items to maintain the sorted list.
  231. endpoint[i] = e1;
  232. endpoint[i + 1] = e0;
  233. lookup[2 * e1.index + e1.type] = i;
  234. lookup[2 * e0.index + e0.type] = i + 1;
  235. --i;
  236. }
  237. endpoint[i + 1] = key;
  238. lookup[2 * key.index + key.type] = i + 1;
  239. }
  240. }
  241. std::vector<AlignedBox3<Real>>& mBoxes;
  242. std::vector<Endpoint> mXEndpoints, mYEndpoints, mZEndpoints;
  243. std::set<EdgeKey<false>> mOverlap;
  244. // The intervals are indexed 0 <= i < n. The endpoint array has 2*n
  245. // entries. The original 2*n interval values are ordered as
  246. // b[0], e[0], b[1], e[1], ..., b[n-1], e[n-1]
  247. // When the endpoint array is sorted, the mapping between interval
  248. // values and endpoints is lost. In order to modify interval values
  249. // that are stored in the endpoint array, we need to maintain the
  250. // mapping. This is done by the following lookup table of 2*n
  251. // entries. The value mLookup[2*i] is the index of b[i] in the
  252. // endpoint array. The value mLookup[2*i+1] is the index of e[i]
  253. // in the endpoint array.
  254. std::vector<int> mXLookup, mYLookup, mZLookup;
  255. };
  256. }