OBBTreeOfPoints.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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/BitHacks.h>
  9. #include <Mathematics/ContOrientedBox3.h>
  10. // The depth of a node in a (nonempty) tree is the distance from the node to
  11. // the root of the tree. The height is the maximum depth. A tree with a
  12. // single node has height 0. The set of nodes of a tree with the same depth
  13. // is refered to as a level of a tree (corresponding to that depth). A
  14. // complete binary tree of height H has 2^{H+1}-1 nodes. The level
  15. // corresponding to depth D has 2^D nodes, in which case the number of
  16. // leaf nodes (depth H) is 2^H.
  17. namespace WwiseGTE
  18. {
  19. template <typename Real>
  20. class OBBTreeForPoints
  21. {
  22. public:
  23. struct Node
  24. {
  25. Node()
  26. :
  27. depth(0),
  28. minIndex(std::numeric_limits<uint32_t>::max()),
  29. maxIndex(std::numeric_limits<uint32_t>::max()),
  30. leftChild(std::numeric_limits<uint32_t>::max()),
  31. rightChild(std::numeric_limits<uint32_t>::max())
  32. {
  33. }
  34. OrientedBox3<Real> box;
  35. uint32_t depth;
  36. uint32_t minIndex, maxIndex;
  37. uint32_t leftChild, rightChild;
  38. };
  39. // The 'points' array is a collection of vertices, each occupying a
  40. // chunk of memory with 'stride' bytes. A vertex must start at the
  41. // first byte of this chunk but does not necessarily fill it. The
  42. // 'height' specifies the height of the tree and must be no larger
  43. // than 31. If it is set to std::numeric_limits<uint32_t>::max(),
  44. // then the entire tree is built and the actual height is computed
  45. // from 'numPoints'.
  46. OBBTreeForPoints(uint32_t numPoints, char const* points, size_t stride,
  47. uint32_t height = std::numeric_limits<uint32_t>::max())
  48. :
  49. mNumPoints(numPoints),
  50. mPoints(points),
  51. mStride(stride),
  52. mHeight(height),
  53. mPartition(numPoints)
  54. {
  55. // The tree nodes are indexed by 32-bit unsigned integers, so
  56. // the number of nodes can be at most 2^{32} - 1. This limits
  57. // the height to 31.
  58. uint32_t numNodes;
  59. if (mHeight == std::numeric_limits<uint32_t>::max())
  60. {
  61. uint32_t minPowerOfTwo =
  62. static_cast<uint32_t>(BitHacks::RoundUpToPowerOfTwo(mNumPoints));
  63. mHeight = BitHacks::Log2OfPowerOfTwo(minPowerOfTwo);
  64. numNodes = 2 * mNumPoints - 1;
  65. }
  66. else
  67. {
  68. // The maximum level cannot exceed 30 because we are storing
  69. // the indices into the node array as 32-bit unsigned
  70. // integers.
  71. if (mHeight < 32)
  72. {
  73. numNodes = (uint32_t)(1ULL << (mHeight + 1)) - 1;
  74. }
  75. else
  76. {
  77. // When the precondition is not met, return a tree of
  78. // height 0 (a single node).
  79. mHeight = 0;
  80. numNodes = 1;
  81. }
  82. }
  83. // The tree is built recursively. A reference to a Node is
  84. // passed to BuildTree and nodes are appended to a std::vector.
  85. // Because the references are on the stack, we must guarantee no
  86. // reallocations to avoid invalidating the references. TODO:
  87. // This design can be modified to pass indices to the nodes so
  88. // that reallocation is not a problem.
  89. mTree.reserve(numNodes);
  90. // Build the tree recursively. The array mPartition stores the
  91. // indices into the 'points' array so that at a node, the points
  92. // represented by the node are those indexed by the range
  93. // [node.minIndex, node.maxIndex].
  94. for (uint32_t i = 0; i < mNumPoints; ++i)
  95. {
  96. mPartition[i] = i;
  97. }
  98. mTree.push_back(Node());
  99. BuildTree(mTree.back(), 0, mNumPoints - 1);
  100. }
  101. // Member access.
  102. inline uint32_t GetNumPoints() const
  103. {
  104. return mNumPoints;
  105. }
  106. inline char const* GetPoints() const
  107. {
  108. return mPoints;
  109. }
  110. inline size_t GetStride() const
  111. {
  112. return mStride;
  113. }
  114. inline std::vector<Node> const& GetTree() const
  115. {
  116. return mTree;
  117. }
  118. inline uint32_t GetHeight() const
  119. {
  120. return mHeight;
  121. }
  122. inline std::vector<uint32_t> const& GetPartition() const
  123. {
  124. return mPartition;
  125. }
  126. private:
  127. inline Vector3<Real> GetPosition(uint32_t index) const
  128. {
  129. return *reinterpret_cast<Vector3<Real> const*>(mPoints + index * mStride);
  130. }
  131. void BuildTree(Node& node, uint32_t i0, uint32_t i1)
  132. {
  133. node.minIndex = i0;
  134. node.maxIndex = i1;
  135. if (i0 == i1)
  136. {
  137. // We are at a leaf node. The left and right child indices
  138. // were set to std::numeric_limits<uint32_t>::max() during
  139. // construction.
  140. // Create a degenerate box whose center is the point.
  141. node.box.center = GetPosition(mPartition[i0]);
  142. node.box.axis[0] = Vector3<Real>{ (Real)1, (Real)0, (Real)0 };
  143. node.box.axis[1] = Vector3<Real>{ (Real)0, (Real)1, (Real)0 };
  144. node.box.axis[2] = Vector3<Real>{ (Real)0, (Real)0, (Real)1 };
  145. node.box.extent = Vector3<Real>{ (Real)0, (Real)0, (Real)0 };
  146. }
  147. else // i0 < i1
  148. {
  149. // We are at an interior node. Compute an oriented bounding
  150. // box.
  151. ComputeOBB(i0, i1, node.box);
  152. if (node.depth == mHeight)
  153. {
  154. return;
  155. }
  156. // Use the box axis corresponding to largest extent for the
  157. // splitting axis. Partition the points into two subsets, one
  158. // for the left child and one for the right child. The subsets
  159. // have numbers of elements that differ by at most 1, so the
  160. // tree is balanced.
  161. Vector3<Real> axis2 = node.box.axis[2];
  162. uint32_t j0, j1;
  163. SplitPoints(i0, i1, j0, j1, node.box.center, axis2);
  164. node.leftChild = static_cast<uint32_t>(mTree.size());
  165. node.rightChild = node.leftChild + 1;
  166. mTree.push_back(Node());
  167. Node& leftTree = mTree.back();
  168. mTree.push_back(Node());
  169. Node& rightTree = mTree.back();
  170. leftTree.depth = node.depth + 1;
  171. rightTree.depth = node.depth + 1;
  172. BuildTree(leftTree, i0, j0);
  173. BuildTree(rightTree, j1, i1);
  174. }
  175. }
  176. void ComputeOBB(uint32_t i0, uint32_t i1, OrientedBox3<Real>& box)
  177. {
  178. // Compute the mean of the points.
  179. Vector3<Real> zero{ (Real)0, (Real)0, (Real)0 };
  180. box.center = zero;
  181. for (uint32_t i = i0; i <= i1; ++i)
  182. {
  183. box.center += GetPosition(mPartition[i]);
  184. }
  185. Real invSize = ((Real)1) / (Real)(i1 - i0 + 1);
  186. box.center *= invSize;
  187. // Compute the covariance matrix of the points.
  188. Real covar00 = (Real)0, covar01 = (Real)0, covar02 = (Real)0;
  189. Real covar11 = (Real)0, covar12 = (Real)0, covar22 = (Real)0;
  190. for (uint32_t i = i0; i <= i1; ++i)
  191. {
  192. Vector3<Real> diff = GetPosition(mPartition[i]) - box.center;
  193. covar00 += diff[0] * diff[0];
  194. covar01 += diff[0] * diff[1];
  195. covar02 += diff[0] * diff[2];
  196. covar11 += diff[1] * diff[1];
  197. covar12 += diff[1] * diff[2];
  198. covar22 += diff[2] * diff[2];
  199. }
  200. covar00 *= invSize;
  201. covar01 *= invSize;
  202. covar02 *= invSize;
  203. covar11 *= invSize;
  204. covar12 *= invSize;
  205. covar22 *= invSize;
  206. // Solve the eigensystem and use the eigenvectors for the box
  207. // axes.
  208. SymmetricEigensolver3x3<Real> es;
  209. std::array<Real, 3> eval;
  210. std::array<std::array<Real, 3>, 3> evec;
  211. es(covar00, covar01, covar02, covar11, covar12, covar22, false, +1, eval, evec);
  212. for (int i = 0; i < 3; ++i)
  213. {
  214. box.axis[i] = evec[i];
  215. }
  216. box.extent = eval;
  217. // Let C be the box center and let U0, U1, and U2 be the box axes.
  218. // Each input point is of the form X = C + y0*U0 + y1*U1 + y2*U2.
  219. // The following code computes min(y0), max(y0), min(y1), max(y1),
  220. // min(y2), and max(y2). The box center is then adjusted to be
  221. // C' = C + 0.5*(min(y0)+max(y0))*U0 + 0.5*(min(y1)+max(y1))*U1
  222. // + 0.5*(min(y2)+max(y2))*U2
  223. Vector3<Real> pmin = zero, pmax = zero;
  224. for (uint32_t i = i0; i <= i1; ++i)
  225. {
  226. Vector3<Real> diff = GetPosition(mPartition[i]) - box.center;
  227. for (int j = 0; j < 3; ++j)
  228. {
  229. Real dot = Dot(diff, box.axis[j]);
  230. if (dot < pmin[j])
  231. {
  232. pmin[j] = dot;
  233. }
  234. else if (dot > pmax[j])
  235. {
  236. pmax[j] = dot;
  237. }
  238. }
  239. }
  240. Real const half(0.5);
  241. for (int j = 0; j < 3; ++j)
  242. {
  243. box.center += (half * (pmin[j] + pmax[j])) * box.axis[j];
  244. box.extent[j] = half * (pmax[j] - pmin[j]);
  245. }
  246. }
  247. void SplitPoints(uint32_t i0, uint32_t i1, uint32_t& j0, uint32_t& j1,
  248. Vector3<Real> const& origin, Vector3<Real> const& direction)
  249. {
  250. // Project the points onto the splitting axis.
  251. uint32_t numProjections = i1 - i0 + 1;
  252. std::vector<ProjectionInfo> info(numProjections);
  253. uint32_t i, k;
  254. for (i = i0, k = 0; i <= i1; ++i, ++k)
  255. {
  256. Vector3<Real> diff = GetPosition(mPartition[i]) - origin;
  257. info[k].pointIndex = mPartition[i];
  258. info[k].projection = Dot(direction, diff);
  259. }
  260. // Partition the projections by the median.
  261. uint32_t medianIndex = (numProjections - 1) / 2;
  262. std::nth_element(info.begin(), info.begin() + medianIndex, info.end());
  263. // Partition the points by the median.
  264. for (k = 0, j0 = i0 - 1; k <= medianIndex; ++k)
  265. {
  266. mPartition[++j0] = info[k].pointIndex;
  267. }
  268. for (j1 = i1 + 1; k < numProjections; ++k)
  269. {
  270. mPartition[--j1] = info[k].pointIndex;
  271. }
  272. }
  273. struct ProjectionInfo
  274. {
  275. ProjectionInfo()
  276. :
  277. pointIndex(0),
  278. projection((Real)0)
  279. {
  280. }
  281. bool operator< (ProjectionInfo const& info) const
  282. {
  283. return projection < info.projection;
  284. }
  285. uint32_t pointIndex;
  286. Real projection;
  287. };
  288. uint32_t mNumPoints;
  289. char const* mPoints;
  290. size_t mStride;
  291. uint32_t mHeight;
  292. std::vector<Node> mTree;
  293. std::vector<uint32_t> mPartition;
  294. };
  295. }