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.
237 lines
9.7 KiB
237 lines
9.7 KiB
//////////////////////////////////////////////////////////////////// |
|
// 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 <typename ITEMARR_TYPE, typename TYPE, int DIMS, typename DATA_TYPE=uint32_t> |
|
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<IDX_TYPE,IDX_TYPE,0,1024,IDX_TYPE> IDXARR_TYPE; |
|
typedef Eigen::Matrix<TYPE,DIMS,1> POINT_TYPE; |
|
typedef SEACAVE::TAABB<TYPE,DIMS> 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<numChildren); return m_child[i]; } |
|
inline const NODE_TYPE& Node() const { ASSERT(!IsLeaf()); return m_node; } |
|
inline NODE_TYPE& Node() { ASSERT(!IsLeaf()); return m_node; } |
|
inline const LEAF_TYPE& Leaf() const { ASSERT(IsLeaf()); return m_leaf; } |
|
inline LEAF_TYPE& Leaf() { ASSERT(IsLeaf()); return m_leaf; } |
|
inline const POINT_TYPE& GetCenter() const { return Node().center; } |
|
inline AABB_TYPE GetAabb(TYPE radius) const { return AABB_TYPE(Node().center, radius); } |
|
inline AABB_TYPE GetChildAabb(unsigned idxChild, TYPE radius) const { const TYPE childRadius(radius / TYPE(2)); return AABB_TYPE(ComputeChildCenter(Node().center, childRadius, idxChild), childRadius); } |
|
inline IDX_TYPE GetFirstItemIdx() const { return Leaf().idxBegin; } |
|
inline IDX_TYPE GetLastItemIdx() const { return Leaf().idxBegin + Leaf().size; } |
|
inline SIZE_TYPE GetNumItems() const { return Leaf().size; } |
|
inline const DATA_TYPE& GetUserData() const { return Leaf().data; } |
|
inline DATA_TYPE& GetUserData() { return Leaf().data; } |
|
size_t GetNumItemsHeld() const; |
|
|
|
public: |
|
CELL_TYPE* m_child; // if not a leaf, 2^DIMS child objects |
|
union { // a LEAF_TYPE or NODE_TYPE object, if it is a leaf or not respectively |
|
NODE_TYPE m_node; |
|
LEAF_TYPE m_leaf; |
|
}; |
|
}; |
|
typedef SEACAVE::cList<CELL_TYPE*,CELL_TYPE*,0,256,IDX_TYPE> 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 <typename Functor> |
|
inline TOctree(const ITEMARR_TYPE&, Functor split); |
|
template <typename Functor> |
|
inline TOctree(const ITEMARR_TYPE&, const AABB_TYPE&, Functor split); |
|
|
|
inline void Release(); |
|
inline void Swap(TOctree&); |
|
|
|
template <typename Functor> |
|
void Insert(const ITEMARR_TYPE&, Functor split); |
|
template <typename Functor> |
|
void Insert(const ITEMARR_TYPE&, const AABB_TYPE&, Functor split); |
|
|
|
template <typename INSERTER> |
|
inline void CollectCells(INSERTER&) const; |
|
template <typename INSERTER> |
|
void CollectCells(const CELL_TYPE&, INSERTER&) const; |
|
template <typename PARSER> |
|
inline void ParseCells(PARSER&); |
|
|
|
template <typename INSERTER> |
|
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 <typename INSERTER> |
|
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 <typename INSERTER, typename COLLECTOR> |
|
inline void Collect(INSERTER& inserter, const COLLECTOR& collector) const; |
|
template <typename COLLECTOR> |
|
inline void Collect(IDXARR_TYPE& indices, const COLLECTOR& collector) const; |
|
|
|
template <typename FTYPE, int FDIMS, typename INSERTER> |
|
inline void Traverse(const TFrustum<FTYPE,FDIMS>&, INSERTER&) const; |
|
template <typename FTYPE, int FDIMS> |
|
inline void Traverse(const TFrustum<FTYPE,FDIMS>&, IDXARR_TYPE&) const; |
|
template <typename FTYPE, int FDIMS, typename PARSER> |
|
inline void TraverseCells(const TFrustum<FTYPE,FDIMS>&, PARSER&); |
|
template <typename FTYPE, int FDIMS> |
|
inline void TraverseCells(const TFrustum<FTYPE,FDIMS>&, CELLPTRARR_TYPE&); |
|
|
|
template <typename AREAESTIMATOR, typename CHUNKINSERTER> |
|
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.empty(); } |
|
inline size_t GetNumItems() const { return m_indices.size(); } |
|
inline const IDXARR_TYPE& GetIndexArr() const { return m_indices; } |
|
inline const ITEM_TYPE* GetItems() const { return m_items; } |
|
inline void ResetItems() { m_items = NULL; } |
|
|
|
protected: |
|
template <typename Functor> |
|
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 <typename Functor, bool bForceSplit> |
|
void _Insert(CELL_TYPE&, const POINT_TYPE& center, TYPE radius, IDX_TYPE start, IDX_TYPE size, _InsertData<Functor>&); |
|
|
|
template <typename PARSER> |
|
void _ParseCells(CELL_TYPE&, TYPE, PARSER&); |
|
|
|
template <typename INSERTER> |
|
void _Collect(const CELL_TYPE&, const AABB_TYPE&, INSERTER&) const; |
|
template <typename INSERTER, typename COLLECTOR> |
|
void _Collect(const CELL_TYPE&, TYPE, const COLLECTOR&, INSERTER&) const; |
|
|
|
template <typename FTYPE, int FDIMS, typename INSERTER> |
|
void _Traverse(const CELL_TYPE&, TYPE, const TFrustum<FTYPE,FDIMS>&, INSERTER&) const; |
|
template <typename FTYPE, int FDIMS, typename PARSER> |
|
void _TraverseCells(CELL_TYPE&, TYPE, const TFrustum<FTYPE,FDIMS>&, PARSER&); |
|
|
|
template <typename AREAESTIMATOR, typename CHUNKINSERTER> |
|
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__
|
|
|