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

////////////////////////////////////////////////////////////////////
// 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__