iMSTK
Interactive Medical Simulation Toolkit
imstkLooseOctree.h
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #pragma once
8 
9 #include "imstkMath.h"
10 #include "imstkParallelUtils.h"
11 
12 #include <array>
13 #include <unordered_set>
14 
15 #ifdef WIN32
16 #pragma warning(disable : 4201)
17 #endif
18 namespace imstk
19 {
20 class OctreeNode;
21 class LooseOctree;
22 class Geometry;
23 class PointSet;
24 class SurfaceMesh;
25 
32 {
33  Point = 0,
34  Triangle,
35  Analytical,
36  NumPrimitiveTypes
37 };
38 
44 {
45  OctreePrimitive(const OctreePrimitive&) = delete;
46  OctreePrimitive& operator=(const OctreePrimitive&) = delete;
47 
48  OctreePrimitive() : m_pGeometry(nullptr), m_GeomIdx(0), m_Idx(0) {}
49  OctreePrimitive(Geometry* const pGeometry, const uint32_t geomIdx, const uint32_t idx = 0) :
50  m_pGeometry(pGeometry), m_GeomIdx(geomIdx), m_Idx(idx) {}
51 
53  const uint32_t m_GeomIdx;
54  const uint32_t m_Idx;
55 
56  OctreeNode* m_pNode = nullptr;
57  OctreePrimitive* m_pNext = nullptr;
58 
59  union
60  {
61  std::array<double, 3> m_Position;
62  struct
63  {
64  std::array<double, 3> m_LowerCorner;
65  std::array<double, 3> m_UpperCorner;
66  };
67  };
68 
74  bool m_bValid = true;
75 };
76 
78 struct OctreeNodeBlock;
79 
84 {
85 friend class LooseOctree;
86 friend class OctreeBasedCD;
87 friend class LooseOctreeTest;
88 public:
89  OctreeNode(const OctreeNode&) = delete;
90  OctreeNode& operator=(const OctreeNode&) = delete;
91 
96  m_pTree(nullptr),
97  m_pParent(nullptr),
98  m_Center(Vec3d::Zero()),
99  m_HalfWidth(0.0),
100  m_Depth(0),
101  m_MaxDepth(0),
102  m_bIsLeaf(true) {}
103 
107  explicit OctreeNode(LooseOctree* const tree, OctreeNode* const pParent, const Vec3d& nodeCenter,
108  const double halfWidth, const uint32_t depth);
109 
113  bool isLeaf() const { return m_bIsLeaf; }
114 
119  OctreeNode* getChildNode(const uint32_t childIdx) const;
120 
124  OctreePrimitive* getPrimitiveList(const OctreePrimitiveType type) const { return m_pPrimitiveListHeads[type]; }
125 
129  uint32_t getPrimitiveCount(const OctreePrimitiveType type) const { return m_PrimitiveCounts[type]; }
130 
134  const Vec6d getBounds()
135  {
136  Vec6d bounds;
137  bounds << m_LowerBound[0], m_UpperBound[0], m_LowerBound[1], m_UpperBound[1], m_LowerBound[2], m_UpperBound[2];
138  return bounds;
139  }
140 
144  const Vec6d getLooseBounds()
145  {
146  Vec6d bounds;
147  bounds << m_LowerExtendedBound[0], m_UpperExtendedBound[0], m_LowerExtendedBound[1], m_UpperExtendedBound[1], m_LowerExtendedBound[2], m_UpperExtendedBound[2];
148  return bounds;
149  }
150 
156  void clearPrimitiveData(const OctreePrimitiveType type);
157 
161  void split();
162 
167  void removeAllDescendants();
168 
172  void removeEmptyDescendants();
173 
177  void keepPrimitive(OctreePrimitive* const pPrimitive, const OctreePrimitiveType type);
178 
182  void insertPoint(OctreePrimitive* const pPrimitive);
183 
187  void insertNonPointPrimitive(OctreePrimitive* const pPrimitive, const OctreePrimitiveType type);
188 
192  bool contains(const Vec3d& point) { return contains(point[0], point[1], point[2]); }
193  bool contains(const std::array<double, 3>& point) { return contains(point[0], point[1], point[2]); }
194  bool contains(const double x, const double y, const double z)
195  {
196  return x >= m_LowerBound[0]
197  && y >= m_LowerBound[1]
198  && z >= m_LowerBound[2]
199  && x <= m_UpperBound[0]
200  && y <= m_UpperBound[1]
201  && z <= m_UpperBound[2];
202  }
203 
209  bool contains(const std::array<double, 3>& lowerCorner, const std::array<double, 3>& upperCorner)
210  {
211  return lowerCorner[0] >= m_LowerBound[0]
212  && lowerCorner[1] >= m_LowerBound[1]
213  && lowerCorner[2] >= m_LowerBound[2]
214  && upperCorner[0] <= m_UpperBound[0]
215  && upperCorner[1] <= m_UpperBound[1]
216  && upperCorner[2] <= m_UpperBound[2];
217  }
218 
222  bool looselyContains(const Vec3d& point) { return looselyContains(point[0], point[1], point[2]); }
223  bool looselyContains(const std::array<double, 3>& point) { return looselyContains(point[0], point[1], point[2]); }
224  bool looselyContains(const double x, const double y, const double z)
225  {
226  return x >= m_LowerExtendedBound[0]
227  && y >= m_LowerExtendedBound[1]
228  && z >= m_LowerExtendedBound[2]
229  && x <= m_UpperExtendedBound[0]
230  && y <= m_UpperExtendedBound[1]
231  && z <= m_UpperExtendedBound[2];
232  }
233 
240  bool looselyContains(const std::array<double, 3>& lowerCorner, const std::array<double, 3>& upperCorner)
241  {
242  return lowerCorner[0] >= m_LowerExtendedBound[0]
243  && lowerCorner[1] >= m_LowerExtendedBound[1]
244  && lowerCorner[2] >= m_LowerExtendedBound[2]
245  && upperCorner[0] <= m_UpperExtendedBound[0]
246  && upperCorner[1] <= m_UpperExtendedBound[1]
247  && upperCorner[2] <= m_UpperExtendedBound[2];
248  }
249 
256  bool looselyOverlaps(const std::array<double, 3>& lowerCorner, const std::array<double, 3>& upperCorner)
257  {
258  return upperCorner[0] >= m_LowerExtendedBound[0]
259  && upperCorner[1] >= m_LowerExtendedBound[1]
260  && upperCorner[2] >= m_LowerExtendedBound[2]
261  && lowerCorner[0] <= m_UpperExtendedBound[0]
262  && lowerCorner[1] <= m_UpperExtendedBound[1]
263  && lowerCorner[2] <= m_UpperExtendedBound[2];
264  }
265 
266 // \todo: Make private or protected once a proper public element iteration structure is implemented
267 public:
270  OctreeNodeBlock* m_pChildren = nullptr;
271 
272  const Vec3d m_Center;
273  const Vec3d m_LowerBound;
274  const Vec3d m_UpperBound;
275  const Vec3d m_LowerExtendedBound;
276  const Vec3d m_UpperExtendedBound;
277  const double m_HalfWidth;
278  const uint32_t m_Depth;
279  uint32_t m_MaxDepth;
280  bool m_bIsLeaf = true;
281 
283  OctreePrimitive* m_pPrimitiveListHeads[OctreePrimitiveType::NumPrimitiveTypes];
284 
286  uint32_t m_PrimitiveCounts[OctreePrimitiveType::NumPrimitiveTypes];
287 
289  ParallelUtils::SpinLock m_PrimitiveLock[OctreePrimitiveType::NumPrimitiveTypes];
290 
293 };
294 
301 {
302  OctreeNode m_Nodes[8];
303  OctreeNodeBlock* m_NextBlock = nullptr;
304 };
305 
314 {
315 friend class OctreeNode;
316 friend class LooseOctreeTest;
317 public:
326  explicit LooseOctree(const Vec3d& center, const double width, const double minWidth,
327  const double minWidthRatio = 1.0, const std::string name = "LooseOctree");
328 
332  virtual ~LooseOctree();
333 
337  virtual void clear();
338 
342  void clearPrimitive(const OctreePrimitiveType type);
343 
347  const Vec3d getCenter() const { return m_Center; }
348 
352  double getWidth() const { return m_Width; }
353 
357  double getMinWidth() const { return m_MinWidth; }
358 
362  uint32_t getMaxDepth() const { return m_MaxDepth; }
363 
367  uint32_t getNumAllocatedNodes() const { return m_NumAllocatedNodes; }
368 
372  uint32_t getNumActiveNodes() const { return m_NumAllocatedNodes - m_NumAvaiableBlocksInPool * 8u; }
373 
377  OctreeNode* getRootNode() const { return m_pRootNode; }
378 
382  size_t getPrimitiveCount(const OctreePrimitiveType type) const { return m_vPrimitivePtrs[type].size(); }
383 
387  uint32_t getMaxNumPrimitivesInNodes() const;
388 
392  size_t getNumGeometries() const { return m_sGeometryIndices.size(); }
393 
397  bool hasGeometry(uint32_t geomIdx) const { return m_sGeometryIndices.find(geomIdx) != m_sGeometryIndices.end(); }
398 
403  uint32_t addPointSet(const std::shared_ptr<PointSet>& pointset);
404 
409  uint32_t addTriangleMesh(const std::shared_ptr<SurfaceMesh>& surfMesh);
410 
415  uint32_t addAnalyticalGeometry(const std::shared_ptr<Geometry>& geometry);
416 
420  void setAlwaysRebuild(const bool bAlwaysRebuild) { m_bAlwaysRebuild = bAlwaysRebuild; }
421 
425  void build();
426 
430  void update();
431 
432 protected:
436  void addGeometry(const uint32_t geomIdx);
437 
441  void removeGeometry(const uint32_t geomIdx);
442 
446  void rebuild();
447 
451  void populatePointPrimitives();
452 
457  void populateNonPointPrimitives(const OctreePrimitiveType type);
458 
462  void incrementalUpdate();
463 
468  void updatePositionAndCheckValidity();
469 
474  void updateBoundingBoxAndCheckValidity(const OctreePrimitiveType type);
475 
479  void removeInvalidPrimitivesFromNodes();
480 
485  void reinsertInvalidPrimitives(const OctreePrimitiveType type);
486 
490  void computePrimitiveBoundingBox(OctreePrimitive* const pPrimitive, const OctreePrimitiveType type);
491 
496  OctreeNodeBlock* requestChildrenFromPool();
497 
501  void returnChildrenToPool(OctreeNodeBlock* const pNodeBlock);
502 
506  void allocateMoreNodeBlock(const uint32_t numBlocks);
507 
511  void deallocateMemoryPool();
512 
513  const std::string m_Name;
514  const Vec3d m_Center;
515  const double m_Width;
516 
518  const double m_MinWidthRatio;
519 
520  double m_MinWidth;
521  uint32_t m_MaxDepth;
523 
525  OctreeNodeBlock* m_pNodeBlockPoolHead = nullptr;
526  uint32_t m_NumAvaiableBlocksInPool = 0;
529 
531  tbb::concurrent_unordered_set<OctreeNodeBlock*> m_sActiveTreeNodeBlocks;
532 
535  std::vector<OctreeNodeBlock*> m_pNodeBigBlocks;
536 
538  std::vector<OctreePrimitive*> m_vPrimitivePtrs[OctreePrimitiveType::NumPrimitiveTypes];
539 
542  std::vector<OctreePrimitive*> m_pPrimitiveBlocks[OctreePrimitiveType::NumPrimitiveTypes];
543 
545  std::unordered_set<uint32_t> m_sGeometryIndices;
546 
547  bool m_bAlwaysRebuild = false;
548  bool m_bCompleteBuild = false;
549 
552  bool m_bDrawNonEmptyParent = true;
553 };
554 } // namespace imstk
555 #ifdef WIN32
556 #pragma warning(default : 4201)
557 #endif
The SpinLock class.
Definition: imstkSpinLock.h:20
std::array< double, 3 > m_Position
For a point primitive, store its position.
bool m_useMaxDepth
If on max depth specified by user will be used, otherwise maxdepth is based of minwidth.
size_t getPrimitiveCount(const OctreePrimitiveType type) const
Get the number of primitives of the given type.
const uint32_t m_Idx
Index of the primitive in the parent geometry (such as index of the triangle in a mesh) ...
OctreeNode *const m_pRootNode
Root node, should not be reassigned throughout the existence of the tree.
uint32_t getMaxDepth() const
Get the maximum depth in this tree, which is computed based on the minWidth value.
LooseOctree * m_pTree
Pointer to the octree, used to request children from memory pool during splitting node...
tbb::concurrent_unordered_set< OctreeNodeBlock * > m_sActiveTreeNodeBlocks
Set of node blocks that are in use (node blocks that have been taken from memory pool) ...
const double m_Width
Width of the tree bounding box.
bool contains(const std::array< double, 3 > &lowerCorner, const std::array< double, 3 > &upperCorner)
Check if the given non-point primitive (triangle/analytical geometry) is exactly contained in the nod...
OctreePrimitiveType
The OctreePrimitiveType enum Type of primitive stored in the octree.
uint32_t getNumActiveNodes() const
Get the number of active nodes in the tree (the non-leaf nodes or leaf nodes that contain primitives)...
double getWidth() const
Return width of the tree.
bool contains(const Vec3d &point)
Check if the given point is contained exactly in the node boundary (bounding box) ...
const uint32_t m_Depth
Depth of this node (depth > 0, depth = 1 starting at the root node)
uint32_t getNumAllocatedNodes() const
Get the total number of tree nodes that have been allocated in memory.
Compound Geometry.
bool looselyContains(const std::array< double, 3 > &lowerCorner, const std::array< double, 3 > &upperCorner)
Check if the given non-point primitive (triangle/analytical geometry) is contained in the node loose ...
std::array< double, 3 > m_LowerCorner
For a non-point primitive, store its AABB&#39;s lower corner.
std::array< double, 3 > m_UpperCorner
For a non-point primitive, store its AABB&#39;s upper corner.
const Vec3d m_LowerBound
The AABB&#39;s lower corner of the node.
ParallelUtils::SpinLock m_PoolLock
Atomic lock for multi-threading modification of the memory pool.
double getMinWidth() const
Return width of the lowest level tree nodes.
Geometry *const m_pGeometry
Pointer to the parent geometry that the primitive belong to.
const uint32_t m_GeomIdx
Global index of the parent geometry.
ParallelUtils::SpinLock m_NodeSplitingLock
Mutex lock for thread-safe splitting node.
OctreeNode()
Dummy constructor, called only during memory allocation in memory pool.
uint32_t m_MaxDepth
Cache the max depth of the tree (maximum depth level possible)
size_t getNumGeometries() const
Get number of geometries that have been added to the octree.
const Vec3d m_UpperExtendedBound
The extended AABB&#39;s upper corner of the node, which is 2X bigger than the exact AABB.
The OctreeNode class.
void setAlwaysRebuild(const bool bAlwaysRebuild)
Set the alwaysRebuild flag (true: rebuilt the tree from scratch in every update, false: incrementally...
const Vec3d m_UpperBound
The AABB&#39;s upper corner of the node.
const Vec3d m_Center
Center of the tree.
const Vec3d m_Center
Center of this node.
bool looselyOverlaps(const std::array< double, 3 > &lowerCorner, const std::array< double, 3 > &upperCorner)
Check if the bounding box of the given primitive (triangle/analytical geometry) overlaps with the loo...
uint32_t getPrimitiveCount(const OctreePrimitiveType type) const
Get the number of primitives of the given type in this node.
Base class for any geometrical representation.
Definition: imstkGeometry.h:22
const Vec3d m_LowerExtendedBound
The extended AABB&#39;s lower corner of the node, which is 2X bigger than the exact AABB.
double m_MinWidth
Minimum width allowed for the tree nodes.
uint32_t m_MaxDepth
Max depth of the tree, which is computed based on m_MinWidth.
const double m_HalfWidth
Half width of the node AABB.
const Vec3d getCenter() const
Return center of the tree.
The OctreePrimitive struct For each octree primitive (point/triangle/analytical geometry), store its relevant data.
OctreeNode * getRootNode() const
Get the root node.
const double m_MinWidthRatio
If there is no point primitive, minWidth will be recomputed as minWidth = min(width of all non-point ...
uint32_t m_NumAllocatedNodes
Count the total number of allocated nodes so far.
const std::string m_Name
Name of the tree.
std::vector< OctreeNodeBlock * > m_pNodeBigBlocks
Class LooseOctree, where each tree node has a loose boundary which is exactly twice big as its exact...
bool looselyContains(const Vec3d &point)
Check if the given point is contained in the node loose boundary (which is 2X bigger than the boundin...
OctreeNode * m_pParent
Pointer to the parent node.
bool isLeaf() const
Check if this node is a leaf node.
OctreePrimitive * getPrimitiveList(const OctreePrimitiveType type) const
For the given primitive type, return the head node of the primitive list of that type.
The OctreeNodeBlock struct This is a data structure to store a memory block of 8 tree node at a time ...
const Vec6d getBounds()
Get the bounds of the node.
OctreeNode * m_pNode
Pointer to the octree node containing the primitive.
bool hasGeometry(uint32_t geomIdx) const
Check if a geometry with the given geometry index has been added to the octree before.
std::unordered_set< uint32_t > m_sGeometryIndices
List of all indices of the added geometries, to check for duplication such that one geometry cannot b...
const Vec6d getLooseBounds()
Get the loose bounds of the node.
OctreePrimitive * m_pNext
Pointer to the next node in the primitive list of the octree node.