//////////////////////////////////////////////////////////////////// // Octree.h // // Copyright 2007 cDc@seacave // Distributed under the Boost Software License, Version 1.0 // (See http://www.boost.org/LICENSE_1_0.txt) #ifndef __SEACAVE_OCTREE_H__ #define __SEACAVE_OCTREE_H__ // I N C L U D E S ///////////////////////////////////////////////// #include "AABB.h" #include "Ray.h" // D E F I N E S /////////////////////////////////////////////////// namespace SEACAVE { // S T R U C T S /////////////////////////////////////////////////// // basic octree class // each item should define the operator const POINT_TYPE& returning its center; // at build time, a functor must be supplied that returns true as long as // the current cell should be split farther, given its number of items and radius, ex: // [](Octree::IDX_TYPE size, Octree::Type radius) { // return size > SIZE && radius > RADIUS; // } // where: // SIZE is the minimum number of items contained by the cell so that this to be divided further // RADIUS is the minimum size of the cell allowed to be divided further // both conditions represent exclusive limits and both should be true for the division to take place template class TOctree { STATIC_ASSERT(DIMS > 0 && DIMS <= 3); public: typedef TYPE Type; typedef typename ITEMARR_TYPE::Type ITEM_TYPE; typedef typename ITEMARR_TYPE::IDX IDX_TYPE; typedef SEACAVE::cList IDXARR_TYPE; typedef Eigen::Matrix POINT_TYPE; typedef SEACAVE::TAABB AABB_TYPE; typedef uint32_t SIZE_TYPE; class CELL_TYPE { public: typedef struct { POINT_TYPE center; // center of the current cell } NODE_TYPE; typedef struct { IDX_TYPE idxBegin; // index in the global array of the first item contained by this cell SIZE_TYPE size; // number of items contained by this cell in the global array DATA_TYPE data; // user data associated with this leaf } LEAF_TYPE; enum { numChildren = (2<<(DIMS-1)) }; public: inline CELL_TYPE(); inline ~CELL_TYPE(); inline void Release(); inline void Swap(CELL_TYPE&); inline unsigned ComputeChild(const POINT_TYPE& item) const; static void ComputeCenter(POINT_TYPE []); static inline POINT_TYPE ComputeChildCenter(const POINT_TYPE&, TYPE, unsigned); inline bool IsLeaf() const { return (m_child==NULL); } inline const CELL_TYPE& GetChild(int i) const { ASSERT(!IsLeaf() && i CELLPTRARR_TYPE; struct IndexInserter { IDXARR_TYPE& indices; IndexInserter(IDXARR_TYPE& _indices) : indices(_indices) {} void operator()(IDX_TYPE idx) { indices.Insert(idx); } void operator()(const IDX_TYPE* idices, SIZE_TYPE size) { indices.Join(idices, size); } }; struct CellInserter { CELLPTRARR_TYPE& cells; CellInserter(CELLPTRARR_TYPE& _cells) : cells(_cells) {} void operator()(CELL_TYPE& cell) { cells.Insert(&cell); } }; public: inline TOctree() {} template inline TOctree(const ITEMARR_TYPE&, Functor split); template inline TOctree(const ITEMARR_TYPE&, const AABB_TYPE&, Functor split); inline void Release(); inline void Swap(TOctree&); template void Insert(const ITEMARR_TYPE&, Functor split); template void Insert(const ITEMARR_TYPE&, const AABB_TYPE&, Functor split); template inline void CollectCells(INSERTER&) const; template void CollectCells(const CELL_TYPE&, INSERTER&) const; template inline void ParseCells(PARSER&); template inline void Collect(INSERTER& inserter, const AABB_TYPE& aabb) const; inline void Collect(IDXARR_TYPE& indices, const AABB_TYPE& aabb) const; inline void Collect(IDX_TYPE maxNeighbors, IDXARR_TYPE& indices, const AABB_TYPE& aabb) const; template inline void Collect(INSERTER& inserter, const POINT_TYPE& center, TYPE radius) const; inline void Collect(IDXARR_TYPE& indices, const POINT_TYPE& center, TYPE radius) const; inline void Collect(IDX_TYPE maxNeighbors, IDXARR_TYPE& indices, const POINT_TYPE& center, TYPE radius) const; template inline void Collect(INSERTER& inserter, const COLLECTOR& collector) const; template inline void Collect(IDXARR_TYPE& indices, const COLLECTOR& collector) const; template inline void Traverse(const TFrustum&, INSERTER&) const; template inline void Traverse(const TFrustum&, IDXARR_TYPE&) const; template inline void TraverseCells(const TFrustum&, PARSER&); template inline void TraverseCells(const TFrustum&, CELLPTRARR_TYPE&); template void SplitVolume(float maxArea, AREAESTIMATOR& areaEstimator, CHUNKINSERTER& chunkInserter); inline const CELL_TYPE& GetRoot() const { return m_root; } inline TYPE GetRadius() const { return m_radius; } inline AABB_TYPE GetAabb() const { return m_root.GetAabb(m_radius); } inline bool IsEmpty() const { return m_indices.IsEmpty(); } inline size_t GetNumItems() const { return m_indices.GetSize(); } inline const IDXARR_TYPE& GetIndexArr() const { return m_indices; } inline const ITEM_TYPE* GetItems() const { return m_items; } inline const POINT_TYPE& GetItem(IDX_TYPE idx) const { ASSERT(m_items != NULL); return m_items[idx]; } inline void ResetItems() { m_items = NULL; } protected: template struct _InsertData { enum : IDX_TYPE { NO_INDEX = DECLARE_NO_INDEX(IDX_TYPE) }; IDXARR_TYPE successors; // single connected list of next item indices Functor split; // used to decide if a cell needs to be split farther }; template void _Insert(CELL_TYPE&, const POINT_TYPE& center, TYPE radius, IDX_TYPE start, IDX_TYPE size, _InsertData&); template void _ParseCells(CELL_TYPE&, TYPE, PARSER&); template void _Collect(const CELL_TYPE&, const AABB_TYPE&, INSERTER&) const; template void _Collect(const CELL_TYPE&, TYPE, const COLLECTOR&, INSERTER&) const; template void _Traverse(const CELL_TYPE&, TYPE, const TFrustum&, INSERTER&) const; template void _TraverseCells(CELL_TYPE&, TYPE, const TFrustum&, PARSER&); template void _SplitVolume(const CELL_TYPE& parentCell, TYPE parentRadius, unsigned idxChild, float maxArea, AREAESTIMATOR& areaEstimator, CHUNKINSERTER& chunkInserter, const UnsignedArr& indices=UnsignedArr{0,1,2,3,4,5,6,7}); protected: const ITEM_TYPE* m_items; // original input items (the only condition is that every item to resolve to a position) IDXARR_TYPE m_indices; // indices to input items re-arranged spatially (as dictated by the octree) CELL_TYPE m_root; // first cell of the tree (always of Node type) TYPE m_radius; // size of the sphere containing all cells public: typedef struct DEBUGINFO_TYPE { size_t memSize; // total memory used size_t memStruct; // memory used for the tree structure size_t memItems; // memory used for the contained items size_t numItems; // number of contained items size_t numNodes; // total nodes... size_t numLeaves; // ... from which this number of leaves size_t minDepth; // minimum tree depth size_t maxDepth; // maximum tree depth float avgDepth; // average tree depth void Init() { memset(this, 0, sizeof(DEBUGINFO_TYPE)); } void operator += (const DEBUGINFO_TYPE& r) { avgDepth = avgDepth*numNodes + r.avgDepth*r.numNodes; memSize += r.memSize; memStruct += r.memStruct; memItems += r.memItems; numItems += r.numItems; numNodes += r.numNodes; numLeaves += r.numLeaves; if (minDepth > r.minDepth) minDepth = r.minDepth; if (maxDepth < r.maxDepth) maxDepth = r.maxDepth; avgDepth /= numNodes; } } DEBUGINFO; void GetDebugInfo(DEBUGINFO* =NULL, bool bPrintStats=false) const; static void LogDebugInfo(const DEBUGINFO&); protected: void _GetDebugInfo(const CELL_TYPE&, unsigned, DEBUGINFO&) const; }; // class TOctree /*----------------------------------------------------------------*/ #include "Octree.inl" /*----------------------------------------------------------------*/ } // namespace SEACAVE #endif // __SEACAVE_OCTREE_H__