Octree C++ General Component

Harrison Ainsworth

ΑRΤΙFΕΧ at ΗΧΑ7­24­1 dot ΟR­G
2005-05-22

Abstract

A technical article for programmers, with code and introductory documentation for a generalised octree data structure in C++. It allows storage of any object type, and application of various algorithms. (version 2) [800 words] [1000 code lines]

Keywords

Octree, Data structure, C++, Design, Implementation, Programming

Code archive

http://www.hxa7241.org/articles/content/octree-general-cpp_hxa7241_2005.zip

Contents

Introduction

The purpose was to make a reusable octree component in C++. First, that means holding objects of any type, and second, allowing manipulation by any algorithm. As supplementary requirements, it ought to be compact in active memory use, and code size, and be simple to use.

The result: It allows any object type, whilst maintaining type-safety. It allows a range of algorithmic applications, without handing over complete access. It is minimal in storage. It is moderately simple to use. It is purely an index, leaving storage management of the items to external means.

The represented octree is cubical and axis aligned, partitions are axis aligned, partitions divide in half, each level partitions the previous level in all three axises.

Algorithms implemented using the Octree include: selecting photons within a spherical shell region, and finding nearest object intersection.

Design

Principal structure

The principal design structure is a division into two halves: octree and agent/visitor. The octree is used as-is, the agent and visitor are overridden by a client-written subclasses. The secondary structure, perpendicular to the primary, is a layering into interface and implementation. The interface presents the three main classes as thin templates. The implementation handles containment and item access polymorphically.

Indirect virtual pattern

An octree requires its contained items to provide positional info. But requiring the item classes to implement an OctreeItem interface would impose a direct interface change on every prospective item type, and enlarge their instances with a vptr. Making the octree a simple template would expand the code size considerably.

Instead, the octree related interface/implementation of the item is transferred away from the item type into the separate agent class. The octree can now hold void pointers to items and call the agent to supply information about them. This is used in insertion and removal commands.

Also using this indirect virtual pattern is the visitor. This is like the conventional Visitor: defining an externalised operation on the main data structure. In this case however, the octree is constant and the visitor is the object modified. This provides callbacks to read tree nodes for visit queries.

The octree template wrapper ensures the items indexed by the octree and the agents and visitors used when accessing them are of matching types. All work is delegated to its Composite pattern implementation, which works with abstract base interfaces and void pointers.

Dimensions and traversal

Attention to the numerical nature of the data structure is needed: OO thinking might first suggest a cubelet class knowing its boundary. But separate cubelets share boundary faces, and this must be represented carefully numerically, otherwise gaps will appear between them. This leads to modelling divisions of eight cubelets, rather than individuals. Ultimately the dimensions were ‘factored’ into their minimal form: the size of the root. They are then passed through and divided at each level, in traversal. A further benefit is that this needs no storage in the tree.

During a visit, execution jumps back and forth between client and framework. First the client calls the octree to start. The octree calls back to the visitor, which can then call the framework again to continue further. This is repeated at each tree level, allowing the client visitor to collect state and steer the traversal.

Diagrams

UML class relations diagram

UML visit sequence diagram

Code

Description

The client interface is in one hpp-cpp file pair containing three class templates: Octree, OctreeAgent and OctreeVisitor. The implementation is in two hpp-cpp file pairs. One contains the classes for the Composite (relating to structure). The other contains the rest of the supporting classes (relating to manipulation).

Each class definition is in sections. The basic ones are: standard object services (constructors, copying...), commands, queries, and fields. Any inlines and method templates immediately follow the class definition. Three other modules are used, but not shown: Primitives, Array, Vector3f. Primitives merely collects a few aliases and limits for built-in types. Array is a simpler, compacter alternative to std::vector. Vector3f is an ordinary 3D vector.

The core component is 939 lines of code. The total, including the support classes, is 1742 lines.

Requirements

Some of the support classes depend on the standard C library through float.h and math.c, in a probably easily removable way. Exception handling is used for dealing with storage allocation exceptions. RTTI is not used. Only basic use is made of templates: just class templates. The component and support has been compiled with MinGW 3.1.0 GCC 3.4.2, and VC toolkit 2003.

Archive

Everything is available in normal text file form in this archive: http://www.hxa7241.org/articles/content/octree-general-cpp_hxa7241_2005.zip

Files and classes

Octree.hpp


#ifndef Octree_h
#define Octree_h


#include "OctreeAuxiliary.hpp"
#include "OctreeImplementation.hpp"




#include "hxa7241_graphics.hpp"
namespace hxa7241_graphics
{
    using hxa7241_graphics::Vector3f;


/**
 * agent abstract base, for client use with Octree.<br/><br/>
 *
 * client of Octree must define a concrete derivative of
 * OctreeAgent<ItemType>.<br/><br/>
 *
 * this is similar to a proxy: its an intermediary for an octree to query
 * its typeless subject items, when inserting or removing.<br/><br/>
 *
 * the overlap methods are to determine an items relation to a cell or cells,
 * for insertion or removal. the parameters supply the bounds of the cell.
 * <br/><br/>
 *
 * return value of getSubcellOverlaps is 8 bits, each bit is a bool
 * corresponding to a subcell, the high bit for subcell 7, the low bit for
 * subcell 0.<br/><br/>
 *
 * subcell numbering:
 * <pre>
 *    y z       6 7
 *    |/   2 3  4 5
 *     -x  0 1
 * </pre>
 * in binary:
 * <pre>
 *    y z           110 111
 *    |/   010 011  100 101
 *     -x  000 001
 * </pre>
 *
 * @implementation
 * the ___V methods simply apply a type cast to void*s and forward to their
 * abstract counterparts.<br/><br/>
 *
 * an octree requires its contained items to provide positional info. but
 * requiring the item classes to implement an OctreeItem interface would
 * impose a direct interface change on every prospective item type, and enlarge
 * their instances with a vptr.<br/><br/>
 *
 * instead, this agent transfers the octree related interface/implementation
 * away from the item type into a separate class. the octree can now hold void
 * pointers to items and call the agent to query them indirectly.<br/><br/>
 */
template<class TYPE>
class OctreeAgent
    : public OctreeAgentV
{
/// standard object services ---------------------------------------------------
protected:
             OctreeAgent() {}
public:
    virtual ~OctreeAgent() {}
private:
             OctreeAgent( const OctreeAgent& );
    OctreeAgent& operator=( const OctreeAgent& );


/// void-to-type forwarders
public:
/// queries --------------------------------------------------------------------
    virtual bool  isOverlappingCellV ( const void*     pItem,
                                       const Vector3f& lowerCorner,
                                       const Vector3f& upperCorner )      const;
    virtual dword getSubcellOverlapsV( const void*     pItem,
                                       const Vector3f& lower,
                                       const Vector3f& middle,
                                       const Vector3f& upper )            const;


/// abstract interface
protected:
/// queries --------------------------------------------------------------------
    virtual bool  isOverlappingCell ( const TYPE&     item,
                                      const Vector3f& lowerCorner,
                                      const Vector3f& upperCorner )    const =0;
    virtual dword getSubcellOverlaps( const TYPE&     item,
                                      const Vector3f& lower,
                                      const Vector3f& middle,
                                      const Vector3f& upper )          const =0;
};




/// void-to-type forwarders
template<class TYPE>
inline
bool OctreeAgent<TYPE>::isOverlappingCellV
(
    const void*     pItem,
    const Vector3f& lowerCorner,
    const Vector3f& upperCorner
) const
{
    bool is = false;

    if( pItem != 0 )
    {
        is = isOverlappingCell( *reinterpret_cast<const TYPE*>( pItem ),
                                lowerCorner, upperCorner );
    }

    return is;
}


template<class TYPE>
inline
dword OctreeAgent<TYPE>::getSubcellOverlapsV
(
    const void*     pItem,
    const Vector3f& lower,
    const Vector3f& middle,
    const Vector3f& upper
) const
{
    dword ov = ALL_OUTSIDE;

    if( pItem != 0 )
    {
        ov = getSubcellOverlaps( *reinterpret_cast<const TYPE*>( pItem ),
                                 lower, middle, upper );
    }

    return ov;
}




/**
 * visitor abstract base, for client use with Octree.<br/><br/>
 *
 * client of Octree must define a concrete derivative of
 * OctreeVisitor<ItemType>.<br/><br/>
 *
 * this is a reversal of the Visitor pattern: it allows an operation to be
 * performed with the octree, except the octree is merely read from and it is
 * the visitor that is modified.<br/><br/>
 *
 * the visit methods are called by the tree nodes during the visit operation.
 * the parameters supply the cell and boundary info. the implementation can
 * call visit on the supplied cell.<br/><br/>
 *
 * the implementation of visitBranch needs to make the OctreeData to be given
 * in each call of visit.
 *
 * subcell numbering:
 * <pre>
 *    y z       6 7
 *    |/   2 3  4 5
 *     -x  0 1
 * </pre>
 * in binary:
 * <pre>
 *    y z           110 111
 *    |/   010 011  100 101
 *     -x  000 001
 * </pre>
 *
 * @implementation
 * the ___V methods simply apply a type cast to void*s and forward to their
 * abstract counterparts.<br/><br/>
 */
template<class TYPE>
class OctreeVisitor
    : public OctreeVisitorV
{
/// standard object services ---------------------------------------------------
protected:
             OctreeVisitor() {}
public:
    virtual ~OctreeVisitor() {}
private:
             OctreeVisitor( const OctreeVisitor& );
    OctreeVisitor& operator=( const OctreeVisitor& );


/// void-to-type forwarders
public:
/// commands -------------------------------------------------------------------
    virtual void  visitRootV  ( const OctreeCell* pRootCell,
                                const OctreeData& octreeData );
    virtual void  visitBranchV( const OctreeCell* subCells[8],
                                const OctreeData& octreeData );
    virtual void  visitLeafV  ( const Array<const void*>& items,
                                const OctreeData&         octreeData );


/// abstract interface
protected:
/// commands -------------------------------------------------------------------
    virtual void  visitRoot  ( const OctreeCell* pRootCell,
                               const OctreeData& octreeData )                =0;
    virtual void  visitBranch( const OctreeCell* subCells[8],
                               const OctreeData& octreeData )                =0;
    virtual void  visitLeaf  ( const Array<const TYPE*>& items,
                               const OctreeData&         octreeData )        =0;
};




/// void-to-type forwarders
template<class TYPE>
inline
void OctreeVisitor<TYPE>::visitRootV
(
    const OctreeCell* pRootCell,
    const OctreeData& octreeData
)
{
    visitRoot( pRootCell, octreeData );
}


template<class TYPE>
inline
void OctreeVisitor<TYPE>::visitBranchV
(
    const OctreeCell* subCells[8],
    const OctreeData& octreeData
)
{
    visitBranch( subCells, octreeData );
}


template<class TYPE>
inline
void OctreeVisitor<TYPE>::visitLeafV
(
    const Array<const void*>& items,
    const OctreeData&         octreeData
)
{
    visitLeaf( reinterpret_cast<const Array<const TYPE*>&>( items ),
               octreeData );
}








/**
 * octree based spatial index.<br/><br/>
 *
 * client must define concrete derivatives of OctreeAgent<ItemType> and
 * OctreeVisitor<ItemType>.<br/><br/>
 *
 * maxItemCountPerCell is ignored where maxLevelCount is reached.<br/><br/>
 *
 * the octree is cubical and axis aligned, partitions are axis aligned,
 * partitions divide in half, each level partitions the previous level in all
 * three axiss.<br/><br/>
 *
 * storage is contracted or expanded as needed by item insertion and removal.
 * <br/><br/>
 *
 * (occupies, very approximately, 20 bytes per point item. maybe...)
 *
 * octree is only an index: it points to client items, it does not manage
 * storage of items themselves.<br/><br/>
 *
 * @see OctreeAgent
 * @see OctreeVisitor
 *
 * @implementation
 * the octree structure follows the Composite pattern.<br/><br/>
 *
 * this template wrapper ensures the items indexed by the octree and the agents
 * and visitors used when accessing them are of matching types. all algorithmic
 * work is delegated to OctreeRoot and OctreeCell derivatives in
 * OctreeImplementation, which work with abstract base interfaces and void
 * pointers.<br/><br/>
 *
 * for the insertion and removal commands, the agent provides an interface for
 * the octree to query the typeless item, and for the visit query, the visitor
 * provides callbacks to read tree nodes for carrying out the visit operation.
 */
template<class TYPE>
class Octree
{
/// standard object services ---------------------------------------------------
public:
             Octree( const Vector3f& positionOfLowerCorner,
                     float           sizeOfCube,
                     dword           maxItemCountPerCell,
                     dword           maxLevelCount );

    virtual ~Octree();
             Octree( const Octree& );
    Octree& operator=( const Octree& );


/// commands -------------------------------------------------------------------
    virtual bool  insertItem( const TYPE&              item,
                              const OctreeAgent<TYPE>& agent );
    virtual bool  removeItem( const TYPE&              item,
                              const OctreeAgent<TYPE>& agent );


/// queries --------------------------------------------------------------------
    virtual void  visit( OctreeVisitor<TYPE>& visitor )                   const;

    virtual bool  isEmpty()                                               const;
    virtual void  getInfo( dword& byteSize,
                           dword& leafCount,
                           dword& itemRefCount,
                           dword& maxDepth )                              const;

    virtual const Vector3f& getPosition()                                 const;
    virtual float           getSize()                                     const;
    virtual dword           getMaxItemCountPerCell()                      const;
    virtual dword           getMaxLevelCount()                            const;


/// fields ---------------------------------------------------------------------
private:
    OctreeRoot root_m;
};




/// templates ///

/// standard object services ---------------------------------------------------
template<class TYPE>
inline
Octree<TYPE>::Octree
(
    const Vector3f& position,
    const float     sizeOfCube,
    const dword     maxItemCountPerCell,
    const dword     maxLevelCount
)
 :  root_m( position, sizeOfCube, maxItemCountPerCell, maxLevelCount )
{
}


template<class TYPE>
inline
Octree<TYPE>::~Octree()
{
}


template<class TYPE>
inline
Octree<TYPE>::Octree
(
    const Octree& other
)
 :  root_m( other.root_m )
{
}


template<class TYPE>
inline
Octree<TYPE>& Octree<TYPE>::operator=
(
    const Octree& other
)
{
    root_m = other.root_m;

    return *this;
}




/// commands -------------------------------------------------------------------
template<class TYPE>
inline
bool Octree<TYPE>::insertItem
(
    const TYPE&              item,
    const OctreeAgent<TYPE>& agent
)
{
    return root_m.insertItem( &item, agent );
}


template<class TYPE>
inline
bool Octree<TYPE>::removeItem
(
    const TYPE&              item,
    const OctreeAgent<TYPE>& agent
)
{
    return root_m.removeItem( &item, agent );
}




/// queries --------------------------------------------------------------------
template<class TYPE>
inline
void Octree<TYPE>::visit
(
    OctreeVisitor<TYPE>& visitor
) const
{
    root_m.visit( visitor );
}


template<class TYPE>
inline
bool Octree<TYPE>::isEmpty() const
{
    return root_m.isEmpty();
}


template<class TYPE>
inline
void Octree<TYPE>::getInfo
(
    dword& byteSize,
    dword& leafCount,
    dword& itemRefCount,
    dword& maxDepth
) const
{
    root_m.getInfo( sizeof(*this), byteSize, leafCount,
                    itemRefCount, maxDepth );
}


template<class TYPE>
inline
const Vector3f& Octree<TYPE>::getPosition() const
{
    return root_m.getPosition();
}


template<class TYPE>
inline
float Octree<TYPE>::getSize() const
{
    return root_m.getSize();
}


template<class TYPE>
inline
dword Octree<TYPE>::getMaxItemCountPerCell() const
{
    return root_m.getMaxItemCountPerCell();
}


template<class TYPE>
inline
dword Octree<TYPE>::getMaxLevelCount() const
{
    return root_m.getMaxLevelCount();
}


}//namespace




#endif//Octree_h

OctreeAuxiliary.hpp


#ifndef OctreeAuxiliary_h
#define OctreeAuxiliary_h


#include "Vector3f.hpp"
#include "Array.hpp"




#include "hxa7241_graphics.hpp"
namespace hxa7241_graphics
{
    using hxa7241_graphics::Vector3f;
    using hxa7241_general::Array;

    class OctreeRoot;
    class OctreeCell;


/**
 * global octree data.<br/><br/>
 *
 * constant.
 */
class OctreeDimensions
{
/// standard object services ---------------------------------------------------
public:
             OctreeDimensions( const Vector3f& positionOfLowerCorner,
                               float           size,
                               dword           maxItemCountPerCell,
                               dword           maxLevelCount );

            ~OctreeDimensions();
             OctreeDimensions( const OctreeDimensions& );
    OctreeDimensions& operator=( const OctreeDimensions& );


/// queries --------------------------------------------------------------------
            const Vector3f& getPosition()                                 const;
            float           getSize()                                     const;
            dword           getMaxItemCountPerCell()                      const;
            dword           getMaxLevelCount()                            const;

            bool            isSubdivide( dword itemCount,
                                         dword level )                    const;


/// fields ---------------------------------------------------------------------
private:
    Vector3f positionOfLowerCorner_m;
    float    size_m;
    dword    maxItemsPerCell_m;
    dword    maxLevel_m;

    static const dword MAX_LEVEL;
};




/**
 * geometric data for the bound of an octree cell.<br/><br/>
 *
 * constant.<br/><br/>
 *
 * radius is that of the circumsphere.<br/><br/>
 *
 * subcell numbering:
 * <pre>
 *    y z       6 7
 *    |/   2 3  4 5
 *     -x  0 1
 * </pre>
 * in binary:
 * <pre>
 *    y z           110 111
 *    |/   010 011  100 101
 *     -x  000 001
 * </pre>
 */
class OctreeBound
{
/// standard object services ---------------------------------------------------
public:
             OctreeBound();
             OctreeBound( const Vector3f& positionOfLowerCorner,
                          float           size );
             OctreeBound( const OctreeBound& parentCellBound,
                          dword              subCellIndex );

            ~OctreeBound();
             OctreeBound( const OctreeBound& );
    OctreeBound& operator=( const OctreeBound& );


/// queries --------------------------------------------------------------------
            const Vector3f& getLowerCorner()                              const;
            const Vector3f& getUpperCorner()                              const;
            const Vector3f& getCenter()                                   const;
            float           getRadius()                                   const;


/// fields ---------------------------------------------------------------------
private:
    Vector3f positionOfLowerCorner_m;
    Vector3f positionOfUpperCorner_m;
    Vector3f center_m;
    float    circumSphereRadius_m;
};




/**
 * global and local octree cell data.<br/><br/>
 *
 * constant.<br/><br/>
 *
 * to be made during each level of tree descent, so storage is avoided, except
 * to hold one at the root.<br/><br/>
 *
 * subcell numbering:
 * <pre>
 *    y z       6 7
 *    |/   2 3  4 5
 *     -x  0 1
 * </pre>
 * in binary:
 * <pre>
 *    y z           110 111
 *    |/   010 011  100 101
 *     -x  000 001
 * </pre>
 */
class OctreeData
{
/// standard object services ---------------------------------------------------
public:
    explicit OctreeData( const OctreeDimensions& dimensions );
             OctreeData( const OctreeData& parentCellData,
                         dword             subCellIndex );
             OctreeData( const OctreeData&,
                         const OctreeDimensions& );

            ~OctreeData();
             OctreeData( const OctreeData& );
    OctreeData& operator=( const OctreeData& );


/// queries --------------------------------------------------------------------
            const OctreeBound&      getBound()                            const;
            dword                   getLevel()                            const;
            const OctreeDimensions& getDimensions()                       const;

            bool  isSubdivide( dword itemCount )                          const;


/// fields ---------------------------------------------------------------------
private:
    /// local to cell
    OctreeBound bound_m;
    dword       level_m;

    /// global for octree
    const OctreeDimensions* pDimensions_m;
};




/**
 * agent abstract base, for Octree implementation use.<br/><br/>
 *
 * return value of getSubcellOverlapsV is 8 bits, each bit is a bool
 * corresponding to a subcell, the high bit for subcell 7, the low bit for
 * subcell 0.<br/><br/>
 *
 * subcell numbering:
 * <pre>
 *    y z       6 7
 *    |/   2 3  4 5
 *     -x  0 1
 * </pre>
 * in binary:
 * <pre>
 *    y z           110 111
 *    |/   010 011  100 101
 *     -x  000 001
 * </pre>
 */
class OctreeAgentV
{
/// standard object services ---------------------------------------------------
protected:
             OctreeAgentV() {}
public:
    virtual ~OctreeAgentV() {}
private:
             OctreeAgentV( const OctreeAgentV& );
    OctreeAgentV& operator=( const OctreeAgentV& );


/// queries --------------------------------------------------------------------
public:
    virtual bool  isOverlappingCellV ( const void*     pItem,
                                       const Vector3f& lowerCorner,
                                       const Vector3f& upperCorner )   const =0;
    virtual dword getSubcellOverlapsV( const void*     pItem,
                                       const Vector3f& lower,
                                       const Vector3f& middle,
                                       const Vector3f& upper )         const =0;


/// constants ------------------------------------------------------------------
    static const dword ALL_INSIDE  = 0x0000FFFF;
    static const dword ALL_OUTSIDE = 0x00000000;
};




/**
 * visitor abstract base, for Octree implementation use.<br/><br/>
 *
 * subcell numbering:
 * <pre>
 *    y z       6 7
 *    |/   2 3  4 5
 *     -x  0 1
 * </pre>
 * in binary:
 * <pre>
 *    y z           110 111
 *    |/   010 011  100 101
 *     -x  000 001
 * </pre>
 *
 * @see OctreeCell
 * @see OctreeBranch
 * @see OctreeLeaf
 */
class OctreeVisitorV
{
/// standard object services ---------------------------------------------------
protected:
             OctreeVisitorV() {}
public:
    virtual ~OctreeVisitorV() {}
private:
             OctreeVisitorV( const OctreeVisitorV& );
    OctreeVisitorV& operator=( const OctreeVisitorV& );


/// commands -------------------------------------------------------------------
public:
    virtual void  visitRootV  ( const OctreeCell* pRootCell,
                                const OctreeData& octreeData )               =0;
    virtual void  visitBranchV( const OctreeCell* subCells[8],
                                const OctreeData& octreeData )               =0;
    virtual void  visitLeafV  ( const Array<const void*>& items,
                                const OctreeData&         octreeData )       =0;
};








/// inlines ///

/// OctreeDimensions -----------------------------------------------------------
inline
const Vector3f& OctreeDimensions::getPosition() const
{
    return positionOfLowerCorner_m;
}


inline
float OctreeDimensions::getSize() const
{
    return size_m;
}


inline
dword OctreeDimensions::getMaxItemCountPerCell() const
{
    return maxItemsPerCell_m;
}


inline
dword OctreeDimensions::getMaxLevelCount() const
{
    return maxLevel_m + 1;
}




/// OctreeBound ----------------------------------------------------------------
inline
const Vector3f& OctreeBound::getLowerCorner() const
{
    return positionOfLowerCorner_m;
}


inline
const Vector3f& OctreeBound::getUpperCorner() const
{
    return positionOfUpperCorner_m;
}


inline
const Vector3f& OctreeBound::getCenter() const
{
    return center_m;
}


inline
float OctreeBound::getRadius() const
{
    return circumSphereRadius_m;
}




/// OctreeData -----------------------------------------------------------------
inline
const OctreeBound& OctreeData::getBound() const
{
    return bound_m;
}


inline
dword OctreeData::getLevel() const
{
    return level_m;
}


inline
const OctreeDimensions& OctreeData::getDimensions() const
{
    return *pDimensions_m;
}


inline
bool OctreeData::isSubdivide
(
    const dword itemCount
) const
{
    return pDimensions_m->isSubdivide( itemCount, level_m );
}


}//namespace




#endif//OctreeAuxiliary_h

OctreeAuxiliary.cpp


#include "OctreeAuxiliary.hpp"   /// own header is included last


using namespace hxa7241_graphics;




/// OctreeDimensions ///////////////////////////////////////////////////////////


/// to fit within fp single precision
const dword OctreeDimensions::MAX_LEVEL = 23;


/// standard object services ---------------------------------------------------
OctreeDimensions::OctreeDimensions
(
    const Vector3f& positionOfLowerCorner,
    const float     size,
    const dword     maxItemsPerCell,
    const dword     maxLevelCount
)
 :  positionOfLowerCorner_m( positionOfLowerCorner )
 ,  size_m                 ( size            >= 0.0f ? size          : -size )
 ,  maxItemsPerCell_m      ( maxItemsPerCell >  0    ? maxItemsPerCell   : 1 )
 ,  maxLevel_m             ( maxLevelCount   >  0    ? maxLevelCount - 1 : 0 )
{
    if( maxLevel_m > MAX_LEVEL )
    {
        maxLevel_m = MAX_LEVEL;
    }
}


OctreeDimensions::~OctreeDimensions()
{
}


OctreeDimensions::OctreeDimensions
(
    const OctreeDimensions& other
)
// :  positionOfLowerCorner_m( other.positionOfLowerCorner_m )
// ,  size_m                 ( other.size_m )
// ,  maxItemsPerCell_m      ( other.maxItemsPerCell_m )
// ,  maxLevel_m             ( other.maxLevel_m )
{
    OctreeDimensions::operator=( other );
}


OctreeDimensions& OctreeDimensions::operator=
(
    const OctreeDimensions& other
)
{
    if( &other != this )
    {
        positionOfLowerCorner_m = other.positionOfLowerCorner_m;
        size_m                  = other.size_m;
        maxItemsPerCell_m       = other.maxItemsPerCell_m;
        maxLevel_m              = other.maxLevel_m;
    }

    return *this;
}




/// queries --------------------------------------------------------------------
bool OctreeDimensions::isSubdivide
(
    const dword itemCount,
    const dword level
) const
{
    return (itemCount > maxItemsPerCell_m) & (level < maxLevel_m);
}








/// OctreeBound ////////////////////////////////////////////////////////////////


/// standard object services ---------------------------------------------------
OctreeBound::OctreeBound()
 :  positionOfLowerCorner_m( Vector3f::ZERO() )
 ,  positionOfUpperCorner_m( Vector3f::ONE() )
 ,  center_m               ( Vector3f::HALF() )
 ,  circumSphereRadius_m   ( Vector3f::HALF().length() )
{
}


OctreeBound::OctreeBound
(
    const Vector3f& positionOfLowerCorner,
    const float     size
)
 :  positionOfLowerCorner_m( positionOfLowerCorner )
 ,  positionOfUpperCorner_m( positionOfLowerCorner +
                             Vector3f(size, size, size) )
 ,  center_m               ( (positionOfLowerCorner_m + positionOfUpperCorner_m)
                             *= 0.5f )
 ,  circumSphereRadius_m   ( (Vector3f::HALF() * size).length() )
{
}


OctreeBound::OctreeBound
(
    const OctreeBound& parentCellBound,
    const dword        subCellIndex
)
{
    {
        const Vector3f* lowMidHigh[] =
        {
            &(parentCellBound.positionOfLowerCorner_m),
            &(parentCellBound.center_m),
            &(parentCellBound.positionOfUpperCorner_m)
        };

        positionOfLowerCorner_m.setXYZ(
            lowMidHigh[ subCellIndex       & 1]->getX(),
            lowMidHigh[(subCellIndex >> 1) & 1]->getY(),
            lowMidHigh[(subCellIndex >> 2) & 1]->getZ() );
        positionOfUpperCorner_m.setXYZ(
            (lowMidHigh+1)[ subCellIndex       & 1]->getX(),
            (lowMidHigh+1)[(subCellIndex >> 1) & 1]->getY(),
            (lowMidHigh+1)[(subCellIndex >> 2) & 1]->getZ() );
    }

    ((center_m = positionOfLowerCorner_m) += positionOfUpperCorner_m) *= 0.5f;
    circumSphereRadius_m = parentCellBound.circumSphereRadius_m * 0.5f;
}


OctreeBound::~OctreeBound()
{
}


OctreeBound::OctreeBound
(
    const OctreeBound& other
)
 :  positionOfLowerCorner_m( other.positionOfLowerCorner_m ),
    positionOfUpperCorner_m( other.positionOfUpperCorner_m ),
    center_m               ( other.center_m ),
    circumSphereRadius_m   ( other.circumSphereRadius_m )
{
}


OctreeBound& OctreeBound::operator=
(
    const OctreeBound& other
)
{
    if( &other != this )
    {
        positionOfLowerCorner_m = other.positionOfLowerCorner_m;
        positionOfUpperCorner_m = other.positionOfUpperCorner_m;
        center_m                = other.center_m;
        circumSphereRadius_m    = other.circumSphereRadius_m;
    }

    return *this;
}








/// OctreeData /////////////////////////////////////////////////////////////////


/// standard object services ---------------------------------------------------
OctreeData::OctreeData
(
    const OctreeDimensions& dimensions
)
 :  bound_m      ( dimensions.getPosition(), dimensions.getSize() )
 ,  level_m      ( 0 )
 ,  pDimensions_m( &dimensions )
{
}


OctreeData::OctreeData
(
    const OctreeData& parentCellData,
    const dword       subCellIndex
)
 :  bound_m      ( parentCellData.bound_m, subCellIndex )
 ,  level_m      ( parentCellData.level_m + 1 )
 ,  pDimensions_m( parentCellData.pDimensions_m )
{
}


OctreeData::OctreeData
(
    const OctreeData&       other,
    const OctreeDimensions& dimensions
)
 :  bound_m      ( other.bound_m )
 ,  level_m      ( other.level_m )
 ,  pDimensions_m( &dimensions )
{
}


OctreeData::~OctreeData()
{
}


OctreeData::OctreeData
(
	const OctreeData& other
)
 :  bound_m      ( other.bound_m )
 ,  level_m      ( other.level_m )
 ,  pDimensions_m( other.pDimensions_m )
{
}


OctreeData& OctreeData::operator=
(
    const OctreeData& other
)
{
    if( &other != this )
    {
        bound_m       = other.bound_m;
        level_m       = other.level_m;
        pDimensions_m = other.pDimensions_m;
    }

    return *this;
}

OctreeImplementation.hpp


#ifndef OctreeImplementation_h
#define OctreeImplementation_h


#include "OctreeAuxiliary.hpp"
#include "Array.hpp"




#include "hxa7241_graphics.hpp"
namespace hxa7241_graphics
{
    using hxa7241_graphics::Vector3f;
    using hxa7241_general::Array;
    class OctreeCell;


/**
 * implementation class for the Octree template.
 *
 * @invariants
 * pRootCell_m can be null, or point to an OctreeCell instance.<br/><br/>
 *
 * at construction, pRootCell_m is set to a legal value.<br/>
 * at destruction, pRootCell_m is deleted.<br/>
 * whenever pRootCell_m is modified, it must be deleted then set to a legal
 * value.<br/>
 * a legal value is: either 0, or the value from invocation of 'new'.
 */
class OctreeRoot
{
/// standard object services ---------------------------------------------------
public:
             OctreeRoot( const Vector3f& position,
                         float           sizeOfCube,
                         dword           maxItemsPerCell,
                         dword           maxLevelCount );

            ~OctreeRoot();
             OctreeRoot( const OctreeRoot& );
    OctreeRoot& operator=( const OctreeRoot& );


/// commands -------------------------------------------------------------------
            bool  insertItem( const void*         pItem,
                              const OctreeAgentV& agent );
            bool  removeItem( const void*         pItem,
                              const OctreeAgentV& agent );


/// queries --------------------------------------------------------------------
            void  visit( OctreeVisitorV& visitor )                        const;

            bool  isEmpty()                                               const;
            void  getInfo( dword  rootWrapperByteSize,
                           dword& byteSize,
                           dword& leafCount,
                           dword& itemCount,
                           dword& maxDepth )                              const;

            const Vector3f& getPosition()                                 const;
            float           getSize()                                     const;
            dword           getMaxItemCountPerCell()                      const;
            dword           getMaxLevelCount()                            const;


/// fields ---------------------------------------------------------------------
private:
    OctreeDimensions dimensions_m;
    OctreeCell*      pRootCell_m;
};




/**
 * abstract base for Composite types, for implementing Octree nodes.
 *
 * @implementation
 * subcell numbering:
 * <pre>
 *    y z       6 7
 *    |/   2 3  4 5
 *     -x  0 1
 * </pre>
 * in binary:
 * <pre>
 *    y z           110 111
 *    |/   010 011  100 101
 *     -x  000 001
 * </pre>
 */
class OctreeCell
{
/// standard object services ---------------------------------------------------
protected:
             OctreeCell() {}
public:
    virtual ~OctreeCell() {}
private:
             OctreeCell( const OctreeCell& );
    OctreeCell& operator=( const OctreeCell& );


/// commands -------------------------------------------------------------------
public:
    virtual void  insertItem( const OctreeData&   thisData,
                              OctreeCell*&        pThis,
                              const void*         pItem,
                              const OctreeAgentV& agent )                    =0;
    virtual bool  removeItem( OctreeCell*&        pThis,
                              const void*         pItem,
                              const dword         maxItemsPerCell,
                              dword&              itemCount )                =0;


/// queries --------------------------------------------------------------------
    virtual void  visit( const OctreeData& thisData,
                         OctreeVisitorV&   visitor )                   const =0;

    virtual OctreeCell* clone()                                        const =0;

    virtual void  getInfo( dword& byteSize,
                           dword& leafCount,
                           dword& itemCount,
                           dword& maxDepth )                           const =0;


/// statics --------------------------------------------------------------------
    static  OctreeCell* cloneNonZero( const OctreeCell* );
};




/**
 * inner node implementation of an octree cell.<br/><br/>
 *
 * stores pointers to eight child cells.
 *
 * @invariants
 * subCells_m elements can be null, or point to an OctreeCell instance.
 */
class OctreeBranch
    : public OctreeCell
{
/// standard object services ---------------------------------------------------
public:
             OctreeBranch();
             OctreeBranch( const OctreeData&         thisData,
                           const Array<const void*>& items,
                           const void* const         pItem,
                           const OctreeAgentV&       agent );

    virtual ~OctreeBranch();
             OctreeBranch( const OctreeBranch& );
    OctreeBranch& operator=( const OctreeBranch& );


/// commands -------------------------------------------------------------------
    virtual void  insertItem( const OctreeData&   thisData,
                              OctreeCell*&        pThis,
                              const void*         pItem,
                              const OctreeAgentV& agent );
    virtual bool  removeItem( OctreeCell*&        pThis,
                              const void*         pItem,
                              const dword         maxItemsPerCell,
                              dword&              itemCount );


/// queries --------------------------------------------------------------------
    virtual void  visit( const OctreeData& thisData,
                         OctreeVisitorV&   visitor )                      const;

    virtual OctreeCell* clone()                                           const;

    virtual void  getInfo( dword& byteSize,
                           dword& leafCount,
                           dword& itemCount,
                           dword& maxDepth )                              const;


/// implementation -------------------------------------------------------------
protected:
    virtual void  zeroSubCells();


/// fields ---------------------------------------------------------------------
private:
    OctreeCell* subCells_m[8];
};




/**
 * outer node implementation of an octree cell.<br/><br/>
 *
 * stores pointers to items.
 */
class OctreeLeaf
    : public OctreeCell
{
/// standard object services ---------------------------------------------------
public:
             OctreeLeaf();
             OctreeLeaf( const OctreeLeaf*const leafs[8] );
private:
    explicit OctreeLeaf( const void* pItem );

public:
    virtual ~OctreeLeaf();
             OctreeLeaf( const OctreeLeaf& );
    OctreeLeaf& operator=( const OctreeLeaf& );


/// commands -------------------------------------------------------------------
    virtual void  insertItem( const OctreeData&   thisData,
                              OctreeCell*&        pThis,
                              const void*         pItem,
                              const OctreeAgentV& agent );
    virtual bool  removeItem( OctreeCell*&        pThis,
                              const void*         pItem,
                              const dword         maxItemsPerCell,
                              dword&              itemCount );


/// queries --------------------------------------------------------------------
    virtual void  visit( const OctreeData& thisData,
                         OctreeVisitorV&   visitor )                      const;

    virtual OctreeCell* clone()                                           const;

    virtual void  getInfo( dword& byteSize,
                           dword& leafCount,
                           dword& itemCount,
                           dword& maxDepth )                              const;


/// statics --------------------------------------------------------------------
    static  void  insertItemMaybeCreate( const OctreeData&   cellData,
                                         OctreeCell*&        pCell,
                                         const void*         pItem,
                                         const OctreeAgentV& agent );


/// fields ---------------------------------------------------------------------
private:
    Array<const void*> items_m;
};


}//namespace




#endif//OctreeImplementation_h

OctreeImplementation.cpp


#include "Vector3f.hpp"

#include "OctreeImplementation.hpp"   /// own header is included last


using namespace hxa7241_graphics;




/// OctreeRoot /////////////////////////////////////////////////////////////////


/// standard object services ---------------------------------------------------
OctreeRoot::OctreeRoot
(
    const Vector3f& position,
    const float     sizeOfCube,
    const dword     maxItemsPerCell,
    const dword     maxLevelCount
)
 :  dimensions_m( position, sizeOfCube, maxItemsPerCell, maxLevelCount )
 ,  pRootCell_m ( 0 )
{
}


OctreeRoot::~OctreeRoot()
{
    delete pRootCell_m;
}


OctreeRoot::OctreeRoot
(
    const OctreeRoot& other
)
 :  dimensions_m( other.dimensions_m )
 ,  pRootCell_m ( OctreeCell::cloneNonZero( other.pRootCell_m ) )
{
}


OctreeRoot& OctreeRoot::operator=
(
    const OctreeRoot& other
)
{
    if( &other != this )
    {
        delete pRootCell_m;
        pRootCell_m = 0;
        pRootCell_m = OctreeCell::cloneNonZero( other.pRootCell_m );

        dimensions_m = other.dimensions_m;
    }

    return *this;
}




/// commands -------------------------------------------------------------------
bool OctreeRoot::insertItem
(
    const void* const   pItem,
    const OctreeAgentV& agent
)
{
    bool isInserted = false;

    /// make data
    const OctreeData data( dimensions_m );

    /// check if item overlaps root cell
    if( agent.isOverlappingCellV( pItem, data.getBound().getLowerCorner(),
                                  data.getBound().getUpperCorner() ) )
    {
        OctreeLeaf::insertItemMaybeCreate( data, pRootCell_m, pItem, agent );

        isInserted = true;
    }

    return isInserted;
}


bool OctreeRoot::removeItem
(
    const void* const   pItem,
    const OctreeAgentV& //agent
)
{
    bool isRemoved = false;

    if( pRootCell_m != 0 )
    {
        dword unusedBranchItemCount = 0;
        isRemoved = pRootCell_m->removeItem( pRootCell_m, pItem,
            dimensions_m.getMaxItemCountPerCell(), unusedBranchItemCount );
    }

    return isRemoved;
}




/// queries --------------------------------------------------------------------
void OctreeRoot::visit
(
    OctreeVisitorV& visitor
) const
{
    /// make data
    const OctreeData data( dimensions_m );

    visitor.visitRootV( pRootCell_m, data );
}


bool OctreeRoot::isEmpty() const
{
    return pRootCell_m == 0;
}


void OctreeRoot::getInfo
(
    const dword rootWrapperByteSize,
    dword&      byteSize,
    dword&      leafCount,
    dword&      itemCount,
    dword&      maxDepth
) const
{
    byteSize  = 0;
    leafCount = 0;
    itemCount = 0;
    maxDepth  = 0;

    if( pRootCell_m != 0 )
    {
        pRootCell_m->getInfo( byteSize, leafCount, itemCount, maxDepth );
    }

    byteSize += rootWrapperByteSize;
}


const Vector3f& OctreeRoot::getPosition() const
{
    return dimensions_m.getPosition();
}


float OctreeRoot::getSize() const
{
    return dimensions_m.getSize();
}


dword OctreeRoot::getMaxItemCountPerCell() const
{
    return dimensions_m.getMaxItemCountPerCell();
}


dword OctreeRoot::getMaxLevelCount() const
{
    return dimensions_m.getMaxLevelCount();
}








/// OctreeCell /////////////////////////////////////////////////////////////////


/// statics --------------------------------------------------------------------
OctreeCell* OctreeCell::cloneNonZero
(
    const OctreeCell* pOriginal
)
{
    return (pOriginal != 0) ? pOriginal->clone() : 0;
}








/// OctreeBranch ///////////////////////////////////////////////////////////////


/// standard object services ---------------------------------------------------
OctreeBranch::OctreeBranch()
{
    OctreeBranch::zeroSubCells();
}


OctreeBranch::OctreeBranch
(
    const OctreeData&         thisData,
    const Array<const void*>& items,
    const void* const         pItem,
    const OctreeAgentV&       agent
)
{
    OctreeBranch::zeroSubCells();

    try
    {
        OctreeCell* pNotUsed = 0;

        /// insert items
        for( int j = items.getLength();  j-- > 0; )
        {
            OctreeBranch::insertItem( thisData, pNotUsed, items[j], agent );
        }

        OctreeBranch::insertItem( thisData, pNotUsed, pItem, agent );
    }
    catch( ... )
    {
        /// delete any allocated cells
        this->~OctreeBranch();

        throw;
    }
}


OctreeBranch::~OctreeBranch()
{
    for( int i = 8;  i-- > 0; )
    {
        delete subCells_m[i];
    }
}


OctreeBranch::OctreeBranch
(
    const OctreeBranch& other
)
 :  OctreeCell()
{
    OctreeBranch::zeroSubCells();

    try
    {
        for( int i = 8;  i-- > 0; )
        {
            subCells_m[i] = OctreeCell::cloneNonZero( other.subCells_m[i] );
        }
    }
    catch( ... )
    {
        /// delete any allocated cells
        this->~OctreeBranch();

        throw;
    }
}


OctreeBranch& OctreeBranch::operator=
(
    const OctreeBranch& other
)
{
    if( &other != this )
    {
        for( int i = 8;  i-- > 0; )
        {
            delete subCells_m[i];
            subCells_m[i] = 0;
            subCells_m[i] = OctreeCell::cloneNonZero( other.subCells_m[i] );
        }
    }

    return *this;
}




/// commands -------------------------------------------------------------------
void OctreeBranch::insertItem
(
    const OctreeData&   thisData,
    OctreeCell*&        ,//pThis,
    const void* const   pItem,
    const OctreeAgentV& agent
)
{
    /// get subcell-item overlaps flags
    const OctreeBound& bound    = thisData.getBound();
    const dword        overlaps = agent.getSubcellOverlapsV( pItem,
        bound.getLowerCorner(), bound.getCenter(), bound.getUpperCorner() );

    /// loop through sub cells
    for( int i = 8;  i-- > 0; )
    {
        /// check if sub cell is overlapped by item
        if( (overlaps >> i) & 1 )
        {
            /// make sub cell data
            const OctreeData subCellData( thisData, i );

            /// add item to sub cell
            OctreeLeaf::insertItemMaybeCreate( subCellData, subCells_m[i],
                                               pItem, agent );
        }
    }
}


bool OctreeBranch::removeItem
(
    OctreeCell*&      pThis,
    const void* const pItem,
    const dword       maxItemsPerCell,
    dword&            itemCount
)
{
    bool  isRemoved       = false;
    dword branchItemCount = 0;

    /// loop through sub cells
    for( int i = 8;  i-- > 0; )
    {
        /// remove item from non-null sub cell
        OctreeCell*& pSubCell = subCells_m[i];
        if( pSubCell != 0 )
        {
            isRemoved |= pSubCell->removeItem( pSubCell, pItem, maxItemsPerCell,
                                               branchItemCount );
        }
    }

    itemCount += branchItemCount;

    /// decide whether to collapse this branch
    if( branchItemCount > 0 )
    {
        /// collapse to leaf
        if( branchItemCount <= maxItemsPerCell )
        {
            /// all subcells *will* be leafs!
            /// because:
            /// a) if a branch has below it less item refs than the threshold,
            ///    it collapses to a leaf (this function!)
            /// b) the total of item refs below this branch in the tree is less
            ///    than the threshold
            /// c) therefore the total of item refs in any branch below this
            ///    cell will be less than the threshold
            /// d) branchs below this cell will be collapsed before this branch
            ///    (because the recursive 'removeItem' call is before the
            ///    collapsing code)
            /// so: if this branch will collapse to a leaf, then all its sub
            /// branchs (direct and indirect) will collapse to leafs, and that
            /// will happen before this branch.
            OctreeCell*const pLeaf = new OctreeLeaf(
                reinterpret_cast<OctreeLeaf**>( subCells_m ) );

            delete pThis;
            pThis = pLeaf;
        }
    }
    else
    {
        /// delete
        delete pThis;
        pThis = 0;
    }

    return isRemoved;
}




/// queries --------------------------------------------------------------------
void OctreeBranch::visit
(
    const OctreeData& thisData,
    OctreeVisitorV&   visitor
) const
{
    visitor.visitBranchV( const_cast<const OctreeCell**>(subCells_m),
                          thisData );
}


OctreeCell* OctreeBranch::clone() const
{
    return new OctreeBranch( *this );
}


void OctreeBranch::getInfo
(
    dword& byteSize,
    dword& leafCount,
    dword& itemCount,
    dword& maxDepth
) const
{
    byteSize += sizeof(*this);

    const dword thisDepth = maxDepth + 1;

    for( int i = 8;  i-- > 0; )
    {
        const OctreeCell*const pSubCell = subCells_m[i];
        if( pSubCell != 0 )
        {
            dword depth = thisDepth;
            pSubCell->getInfo( byteSize, leafCount, itemCount, depth );

            if( maxDepth < depth )
            {
                maxDepth = depth;
            }
        }
    }
}




/// implementation -------------------------------------------------------------
void OctreeBranch::zeroSubCells()
{
    for( int i = 8;  i-- > 0; )
    {
        subCells_m[i] = 0;
    }
}








/// OctreeLeaf /////////////////////////////////////////////////////////////////


/// standard object services ---------------------------------------------------
OctreeLeaf::OctreeLeaf()
 :  items_m()
{
}


OctreeLeaf::OctreeLeaf
(
    const void* pItem
)
 :  items_m()
{
    items_m.append( pItem );
}


OctreeLeaf::OctreeLeaf
(
    const OctreeLeaf*const leafs[8]
)
 :  items_m()
{
    /// sum all items lengths
    dword totalLength = 0;
    for( int i = 8;  i-- > 0; )
    {
        const OctreeLeaf*const pLeaf = leafs[i];
        if( 0 != pLeaf )
        {
            totalLength += pLeaf->items_m.getLength();
        }
    }

    /// prepare items array to hold all other items
    items_m.setLength( totalLength );

    /// copy items arrays
    const void** pElement = items_m.getMemory();
    for( int i = 0;  i < 8;  ++i )
    {
        const OctreeLeaf*const pLeaf = leafs[i];
        if( 0 != pLeaf )
        {
            const void** pOtherElement = pLeaf->items_m.getMemory();
            const void** pOtherEnd = pOtherElement + pLeaf->items_m.getLength();
            for( ;  pOtherElement < pOtherEnd;  ++pOtherElement, ++pElement )
            {
                *pElement = *pOtherElement;
            }
        }
    }
}


OctreeLeaf::~OctreeLeaf()
{
}


OctreeLeaf::OctreeLeaf
(
    const OctreeLeaf& other
)
 :  OctreeCell()
 ,  items_m( other.items_m )
{
}


OctreeLeaf& OctreeLeaf::operator=
(
    const OctreeLeaf& other
)
{
    items_m = other.items_m;

    return *this;
}




/// commands -------------------------------------------------------------------
void OctreeLeaf::insertItem
(
    const OctreeData&   thisData,
    OctreeCell*&        pThis,
    const void* const   pItem,
    const OctreeAgentV& agent
)
{
    /// check if item already present
    bool isAlreadyPresent = false;
    for( int i = items_m.getLength();  (i-- > 0) & !isAlreadyPresent; )
    {
        isAlreadyPresent |= (items_m[i] == pItem);
    }

    /// only insert if item not already present
    if( !isAlreadyPresent )
    {
        /// check if leaf should be subdivided
        if( !thisData.isSubdivide( items_m.getLength() + 1 ) )
        {
            /// append item to collection
            items_m.append( pItem );
        }
        else
        {
            /// subdivide by making branch and adding items to it
            OctreeCell*const pBranch = new OctreeBranch( thisData, items_m,
                                                         pItem, agent );

            /// replace this with branch
            delete pThis;
            pThis = pBranch;
        }
    }
}


bool OctreeLeaf::removeItem
(
    OctreeCell*&      pThis,
    const void* const pItem,
    const dword       ,//maxItemsPerCell,
    dword&            itemCount
)
{
    bool isRemoved = false;

    /// loop through items
    for( int i = 0;  i < items_m.getLength(); )
    {
        /// check if item is present
        if( items_m[i] == pItem )
        {
            /// remove item
            items_m.remove( i );
            isRemoved = true;
        }
        else
        {
            ++i;
        }
    }

    itemCount += items_m.getLength();

    /// check if leaf is now empty
    if( items_m.isEmpty() )
    {
        /// remove this leaf
        delete pThis;
        pThis = 0;
    }

    return isRemoved;
}




/// queries --------------------------------------------------------------------
void OctreeLeaf::visit
(
    const OctreeData& thisData,
    OctreeVisitorV&   visitor
) const
{
    visitor.visitLeafV( items_m, thisData );
}


OctreeCell* OctreeLeaf::clone() const
{
    return new OctreeLeaf( *this );
}


void OctreeLeaf::getInfo
(
    dword& byteSize,
    dword& leafCount,
    dword& itemCount,
    dword& maxDepth
) const
{
    byteSize  += sizeof(*this) + (items_m.getLength() * sizeof(void*));
    ++leafCount;
    itemCount += items_m.getLength();
    ++maxDepth;
}




/// statics --------------------------------------------------------------------
void OctreeLeaf::insertItemMaybeCreate
(
    const OctreeData&   cellData,
    OctreeCell*&        pCell,
    const void* const   pItem,
    const OctreeAgentV& agent
)
{
    /// check cell exists
    if( 0 == pCell )
    {
        /// make leaf, adding item
        OctreeCell*const pLeaf = new OctreeLeaf( pItem );

        /// replace cell with leaf
        delete pCell;
        pCell = pLeaf;
    }
    else
    {
        /// forward to existing cell
        pCell->insertItem( cellData, pCell, pItem, agent );
    }
}

References

License

The source code is available according to the following license:

———

Copyright (c) 2004-2005, Harrison Ainsworth / HXA7241.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder.