💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

444 lines
14 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_GEOM_HYPEROCTREE_HPP
  20. #define ANTKEEPER_GEOM_HYPEROCTREE_HPP
  21. #include "math/compile.hpp"
  22. #include <bit>
  23. #include <cstdint>
  24. #include <limits>
  25. #include <type_traits>
  26. #include <unordered_set>
  27. #include <stack>
  28. namespace geom {
  29. /**
  30. * Hashed linear hyperoctree.
  31. *
  32. * @tparam T Integer node type.
  33. * @tparam N Number of dimensions.
  34. * @tparam D Max depth.
  35. *
  36. * Max depth can likely be determined by a generalized formula. 2D and 3D cases are given below:
  37. *
  38. * 2D:
  39. * 8 bit ( 1 byte) = max depth 1 ( 4 loc bits, 1 depth bits, 1 divider bit) = 6 bits
  40. * 16 bit ( 2 byte) = max depth 5 ( 12 loc bits, 3 depth bits, 1 divider bit) = 16 bits
  41. * 32 bit ( 4 byte) = max depth 12 ( 26 loc bits, 4 depth bits, 1 divider bit) = 31 bits
  42. * 64 bit ( 8 byte) = max depth 28 ( 58 loc bits, 5 depth bits, 1 divider bit) = 64 bits
  43. * 128 bit (16 byte) = max depth 59 (120 loc bits, 6 depth bits, 1 divider bit) = 127 bits
  44. * 256 bit (32 byte) = max depth 123 (248 loc bits, 7 depth bits, 1 divider bit) = 256 bits
  45. * @see https://oeis.org/A173009
  46. *
  47. * 3D:
  48. * 8 bit ( 1 byte) = max depth 1 ( 6 loc bits, 1 depth bits, 1 divider bit) = 8 bits
  49. * 16 bit ( 2 byte) = max depth 3 ( 12 loc bits, 2 depth bits, 1 divider bit) = 15 bits
  50. * 32 bit ( 4 byte) = max depth 8 ( 27 loc bits, 4 depth bits, 1 divider bit) = 32 bits
  51. * 64 bit ( 8 byte) = max depth 18 ( 57 loc bits, 5 depth bits, 1 divider bit) = 63 bits
  52. * 128 bit (16 byte) = max depth 39 (120 loc bits, 6 depth bits, 1 divider bit) = 127 bits
  53. * 256 bit (32 byte) = max depth 81 (243 loc bits, 7 depth bits, 1 divider bit) = 251 bits
  54. * @see https://oeis.org/A178420
  55. *
  56. * @see http://codervil.blogspot.com/2015/10/octree-node-identifiers.html
  57. * @see https://geidav.wordpress.com/2014/08/18/advanced-octrees-2-node-representations/
  58. */
  59. template <class T, std::size_t N, std::size_t D>
  60. class hyperoctree
  61. {
  62. public:
  63. /// Integral node type.
  64. typedef T node_type;
  65. /// Ensure the node type is integral
  66. static_assert(std::is_integral<T>::value, "Node type must be integral.");
  67. /// Maximum node depth.
  68. static constexpr std::size_t max_depth = D;
  69. /// Number of bits required to encode the depth of a node.
  70. static constexpr T depth_bits = math::compile::ceil_log2(max_depth + 1);
  71. /// Number of bits required to encode the location of a node.
  72. static constexpr T location_bits = (max_depth + 1) * N;
  73. /// Number of bits in the node type.
  74. static constexpr T node_bits = sizeof(node_type) * 8;
  75. // Ensure the node type has enough bits
  76. static_assert(depth_bits + location_bits + 1 <= node_bits, "Size of hyperoctree node type is insufficient to encode the maximum depth");
  77. /// Number of children per node.
  78. static constexpr T children_per_node = (N) ? (2 << (N - 1)) : 1;
  79. /// Number of siblings per node.
  80. static constexpr T siblings_per_node = children_per_node - 1;
  81. /// Root node which is always guaranteed to exist.
  82. static constexpr node_type root = 0;
  83. /**
  84. * Accesses nodes in their internal hashmap order.
  85. */
  86. struct unordered_iterator
  87. {
  88. inline unordered_iterator(const unordered_iterator& other): set_iterator(other.set_iterator) {};
  89. inline unordered_iterator& operator=(const unordered_iterator& other) { this->set_iterator = other.set_iterator; return *this; };
  90. inline unordered_iterator& operator++() { ++(this->set_iterator); return *this; };
  91. inline unordered_iterator& operator--() { --(this->set_iterator); return *this; };
  92. inline bool operator==(const unordered_iterator& other) const { return this->set_iterator == other.set_iterator; };
  93. inline bool operator!=(const unordered_iterator& other) const { return this->set_iterator != other.set_iterator; };
  94. inline node_type operator*() const { return *this->set_iterator; };
  95. private:
  96. friend class hyperoctree;
  97. inline explicit unordered_iterator(const typename std::unordered_set<node_type>::const_iterator& it): set_iterator(it) {};
  98. typename std::unordered_set<node_type>::const_iterator set_iterator;
  99. };
  100. /**
  101. * Accesses nodes in z-order.
  102. *
  103. * @TODO Can this be implemented without a stack?
  104. */
  105. struct iterator
  106. {
  107. inline iterator(const iterator& other): hyperoctree(other.hyperoctree), stack(other.stack) {};
  108. inline iterator& operator=(const iterator& other) { this->hyperoctree = other.hyperoctree; this->stack = other.stack; return *this; };
  109. iterator& operator++();
  110. inline bool operator==(const iterator& other) const { return **this == *other; };
  111. inline bool operator!=(const iterator& other) const { return **this != *other; };
  112. inline node_type operator*() const { return stack.top(); };
  113. private:
  114. friend class hyperoctree;
  115. inline explicit iterator(const hyperoctree* hyperoctree, node_type node): hyperoctree(hyperoctree), stack({node}) {};
  116. const hyperoctree* hyperoctree;
  117. std::stack<node_type> stack;
  118. };
  119. /**
  120. * Returns the depth of a node.
  121. *
  122. * @param node Node.
  123. * @return Depth of the node.
  124. */
  125. static T depth(node_type node);
  126. /**
  127. * Returns the Morton code location of a node.
  128. *
  129. * @param node Node.
  130. * @return Morton code location of the node.
  131. */
  132. static T location(node_type node);
  133. /**
  134. * Returns the node at the given depth and location.
  135. *
  136. * @param depth Node depth.
  137. * @param location Node Morton code location.
  138. */
  139. static node_type node(T depth, T location);
  140. /**
  141. * Returns the ancestor of a node at the specified depth.
  142. *
  143. * @param node Node whose ancestor will be located.
  144. * @param depth Absolute depth of the ancestors.
  145. * @return Ancestral node.
  146. */
  147. static node_type ancestor(node_type node, T depth);
  148. /**
  149. * Returns the parent of a node.
  150. *
  151. * @param node Node.
  152. * @return Parent node.
  153. */
  154. static node_type parent(node_type node);
  155. /**
  156. * Returns the nth sibling of a node.
  157. *
  158. * @param node Node.
  159. * @param n Offset to next sibling. (Automatically wraps to `[0, siblings_per_node]`)
  160. * @return Next sibling node.
  161. */
  162. static node_type sibling(node_type node, T n);
  163. /**
  164. * Returns the nth child of a node.
  165. *
  166. * @param node Parent node.
  167. * @param n Offset to the nth sibling of the first child node. (Automatically wraps to 0..children_per_node-1)
  168. * @return nth child node.
  169. */
  170. static node_type child(node_type node, T n);
  171. /**
  172. * Calculates the first common ancestor of two nodes.
  173. *
  174. * @param a First node.
  175. * @param b Second node.
  176. * @return First common ancestor of the two nodes.
  177. */
  178. static node_type common_ancestor(node_type a, node_type b);
  179. /// Creates an hyperoctree with a single root node.
  180. hyperoctree();
  181. /// Returns a z-order iterator to the root node.
  182. iterator begin() const;
  183. /// Returns a z-order iterator indicating the end of a traversal.
  184. iterator end() const;
  185. /// Returns an iterator to the specified node.
  186. iterator find(node_type node) const;
  187. /// Returns an unordered iterator indicating the beginning of a traversal.
  188. unordered_iterator unordered_begin() const;
  189. /// Returns an unordered iterator indicating the end of a traversal.
  190. unordered_iterator unordered_end() const;
  191. /**
  192. * Inserts a node and its siblings into the hyperoctree, creating its ancestors as necessary. Note: The root node is persistent and cannot be inserted.
  193. *
  194. * @param node Node to insert.
  195. */
  196. void insert(node_type node);
  197. /**
  198. * Erases a node along with its siblings and descendants. Note: The root node is persistent and cannot be erased.
  199. *
  200. * @param node Node to erase.
  201. */
  202. void erase(node_type node);
  203. /**
  204. * Erases all nodes except the root.
  205. */
  206. void clear();
  207. /// Returns `true` if the node is contained within the hyperoctree, and `false` otherwise.
  208. bool contains(node_type node) const;
  209. /// Returns `true` if the node has no children, and `false` otherwise.
  210. bool is_leaf(node_type node) const;
  211. /// Returns the number of nodes in the hyperoctree.
  212. std::size_t size() const;
  213. /// Returns the total number of nodes the hyperoctree is capable of containing.
  214. static consteval std::size_t max_size() noexcept
  215. {
  216. return (math::compile::pow<std::size_t>(children_per_node, max_depth + 1) - 1) / (children_per_node - 1);
  217. }
  218. private:
  219. std::unordered_set<node_type> nodes;
  220. };
  221. template <class T, std::size_t N, std::size_t D>
  222. typename hyperoctree<T, N, D>::iterator& hyperoctree<T, N, D>::iterator::operator++()
  223. {
  224. // Get next node from top of stack
  225. node_type node = stack.top();
  226. stack.pop();
  227. // If the node has children
  228. if (!hyperoctree->is_leaf(node))
  229. {
  230. // Push first child onto the stack
  231. for (T i = 0; i < children_per_node; ++i)
  232. stack.push(child(node, siblings_per_node - i));
  233. }
  234. if (stack.empty())
  235. stack.push(std::numeric_limits<T>::max());
  236. return *this;
  237. }
  238. template <class T, std::size_t N, std::size_t D>
  239. inline T hyperoctree<T, N, D>::depth(node_type node)
  240. {
  241. // Extract depth using a bit mask
  242. constexpr T mask = math::compile::pow<node_type>(2, depth_bits) - 1;
  243. return node & mask;
  244. }
  245. template <class T, std::size_t N, std::size_t D>
  246. inline T hyperoctree<T, N, D>::location(node_type node)
  247. {
  248. return node >> ((node_bits - 1) - depth(node) * N);
  249. }
  250. template <class T, std::size_t N, std::size_t D>
  251. inline typename hyperoctree<T, N, D>::node_type hyperoctree<T, N, D>::node(T depth, T location)
  252. {
  253. return (location << ((node_bits - 1) - depth * N)) | depth;
  254. }
  255. template <class T, std::size_t N, std::size_t D>
  256. inline typename hyperoctree<T, N, D>::node_type hyperoctree<T, N, D>::ancestor(node_type node, T depth)
  257. {
  258. const T mask = std::numeric_limits<T>::max() << ((node_bits - 1) - depth * N);
  259. return (node & mask) | depth;
  260. }
  261. template <class T, std::size_t N, std::size_t D>
  262. inline typename hyperoctree<T, N, D>::node_type hyperoctree<T, N, D>::parent(node_type node)
  263. {
  264. return ancestor(node, depth(node) - 1);
  265. }
  266. template <class T, std::size_t N, std::size_t D>
  267. inline typename hyperoctree<T, N, D>::node_type hyperoctree<T, N, D>::sibling(node_type node, T n)
  268. {
  269. constexpr T mask = (1 << N) - 1;
  270. T depth = hyperoctree::depth(node);
  271. T location = node >> ((node_bits - 1) - depth * N);
  272. return hyperoctree::node(depth, (location & (~mask)) | ((location + n) & mask));
  273. }
  274. template <class T, std::size_t N, std::size_t D>
  275. inline typename hyperoctree<T, N, D>::node_type hyperoctree<T, N, D>::child(node_type node, T n)
  276. {
  277. return sibling(node + 1, n);
  278. }
  279. template <class T, std::size_t N, std::size_t D>
  280. inline typename hyperoctree<T, N, D>::node_type hyperoctree<T, N, D>::common_ancestor(node_type a, node_type b)
  281. {
  282. T bits = std::min<T>(depth(a), depth(b)) * N;
  283. T marker = (T(1) << (node_bits - 1)) >> bits;
  284. T depth = T(std::countl_zero((a ^ b) | marker) / N);
  285. return ancestor(a, depth);
  286. }
  287. template <class T, std::size_t N, std::size_t D>
  288. inline hyperoctree<T, N, D>::hyperoctree():
  289. nodes({0})
  290. {}
  291. template <class T, std::size_t N, std::size_t D>
  292. void hyperoctree<T, N, D>::insert(node_type node)
  293. {
  294. if (contains(node))
  295. return;
  296. // Insert node
  297. nodes.emplace(node);
  298. // Insert siblings
  299. for (T i = 1; i < children_per_node; ++i)
  300. nodes.emplace(sibling(node, i));
  301. // Insert parent as necessary
  302. node_type parent = hyperoctree::parent(node);
  303. if (!contains(parent))
  304. insert(parent);
  305. }
  306. template <class T, std::size_t N, std::size_t D>
  307. void hyperoctree<T, N, D>::erase(node_type node)
  308. {
  309. // Don't erase the root!
  310. if (node == root)
  311. return;
  312. for (T i = 0; i < children_per_node; ++i)
  313. {
  314. // Erase node
  315. nodes.erase(node);
  316. // Erase descendants
  317. if (!is_leaf(node))
  318. {
  319. for (T j = 0; j < children_per_node; ++j)
  320. erase(child(node, j));
  321. }
  322. // Go to next sibling
  323. if (i < siblings_per_node)
  324. node = sibling(node, i);
  325. }
  326. }
  327. template <class T, std::size_t N, std::size_t D>
  328. void hyperoctree<T, N, D>::clear()
  329. {
  330. nodes = {0};
  331. }
  332. template <class T, std::size_t N, std::size_t D>
  333. inline bool hyperoctree<T, N, D>::contains(node_type node) const
  334. {
  335. return nodes.count(node);
  336. }
  337. template <class T, std::size_t N, std::size_t D>
  338. inline bool hyperoctree<T, N, D>::is_leaf(node_type node) const
  339. {
  340. return !contains(child(node, 0));
  341. }
  342. template <class T, std::size_t N, std::size_t D>
  343. inline std::size_t hyperoctree<T, N, D>::size() const
  344. {
  345. return nodes.size();
  346. }
  347. template <class T, std::size_t N, std::size_t D>
  348. typename hyperoctree<T, N, D>::iterator hyperoctree<T, N, D>::begin() const
  349. {
  350. return iterator(this, hyperoctree::root);
  351. }
  352. template <class T, std::size_t N, std::size_t D>
  353. typename hyperoctree<T, N, D>::iterator hyperoctree<T, N, D>::end() const
  354. {
  355. return iterator(this, std::numeric_limits<T>::max());
  356. }
  357. template <class T, std::size_t N, std::size_t D>
  358. typename hyperoctree<T, N, D>::iterator hyperoctree<T, N, D>::find(node_type node) const
  359. {
  360. return contains(node) ? iterator(node) : end();
  361. }
  362. template <class T, std::size_t N, std::size_t D>
  363. typename hyperoctree<T, N, D>::unordered_iterator hyperoctree<T, N, D>::unordered_begin() const
  364. {
  365. return unordered_iterator(nodes.begin());
  366. }
  367. template <class T, std::size_t N, std::size_t D>
  368. typename hyperoctree<T, N, D>::unordered_iterator hyperoctree<T, N, D>::unordered_end() const
  369. {
  370. return unordered_iterator(nodes.end());
  371. }
  372. } // namespace geom
  373. #endif // ANTKEEPER_GEOM_HYPEROCTREE_HPP