Support Forum       G3D Web Page     
Classes | Public Member Functions | Protected Types | Protected Member Functions | Static Protected Member Functions | Protected Attributes | List of all members
G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc > Class Template Reference


A set that supports spatial queries using a KD tree (axis-aligned BSP tree) for speed. More...

Classes

class  BoundsComparator
 Compares bounds for strict >, <, or overlap. More...
 
class  BoxIntersectionIterator
 
C++ STL style iterator variable. More...
 
class  CenterComparator
 Compares centers. More...
 
class  Comparator
 Compares bounds to the sort location. More...
 
class  Handle
 Wrapper for a value that includes a cache of its bounds. More...
 
class  Iterator
 
C++ STL style iterator variable. More...
 
class  Node
 

Public Member Functions

 KDTree ()
 To construct a balanced tree, insert the elements and then call KDTree::balance(). More...
 
 KDTree (const KDTree &src)
 
 ~KDTree ()
 
void balance (int valuesPerNode=5, int numMeanSplits=3)
 
Rebalances the tree (slow). More...
 
Iterator begin () const
 
C++ STL style iterator method. More...
 
BoxIntersectionIterator beginBoxIntersection (const AABox &box) const
 
Iterates through the members that intersect the box More...
 
void clear ()
 
Throws out all elements of the set. More...
 
bool contains (const T &value)
 
Returns true if this object is in the set, otherwise returns false. More...
 
void deserializeStructure (BinaryInput &bi)
 Clears the member table. More...
 
Iterator end () const
 
C++ STL style iterator method. More...
 
BoxIntersectionIterator endBoxIntersection () const
 
void getIntersectingMembers (const Array< Plane > &plane, Array< T *> &members) const
 
Returns all members inside the set of planes. More...
 
void getIntersectingMembers (const Array< Plane > &plane, Array< T > &members) const
 
void getIntersectingMembers (const Frustum &frustum, Array< T *> &members) const
 
Typically used to find all visible objects inside the view frustum (see also Camera::getClipPlanes)... More...
 
void getIntersectingMembers (const Frustum &frustum, Array< T > &members) const
 
void getIntersectingMembers (const AABox &box, Array< T *> &members) const
 
Appends all members whose bounds intersect the box. More...
 
void getIntersectingMembers (const AABox &box, Array< T > &members) const
 
void getIntersectingMembers (const Sphere &sphere, Array< T *> &members) const
 Finds all members whose bounding boxes intersect the sphere. More...
 
void getIntersectingMembers (const Sphere &sphere, Array< T > &members) const
 
void getMembers (Array< T > &members) const
 
Returns an array of all members of the set. More...
 
const T * getPointer (const T &value) const
 If a value that is EqualsFunc to value is present, returns a pointer to the version stored in the data structure, otherwise returns nullptr. More...
 
void insert (const T &value)
 
Inserts an object into the set if it is not already present. More...
 
void insert (const Array< T > &valueArray)
 Inserts each elements in the array in turn. More...
 
template<typename RayCallback >
void intersectRay (const Ray &ray, RayCallback &intersectCallback, float &distance, bool intersectCallbackIsFast=false) const
 
Invoke a callback for every member along a ray until the closest intersection is found. More...
 
KDTreeoperator= (const KDTree &src)
 
void remove (const T &value)
 
Removes an object from the set in O(1) time. More...
 
void serializeStructure (BinaryOutput &bo) const
 Stores the locations of the splitting planes (the structure but not the content) so that the tree can be quickly rebuilt from a previous configuration without calling balance. More...
 
void setContents (const Array< T > &array, int valuesPerNode=5, int numMeanSplits=3)
 Clear, set the contents to the values in the array, and then balance. More...
 
int size () const
 
void update (const T &value)
 
If the element is in the set, it is removed. More...
 

Protected Types

typedef _internal::Indirector< HandleMember
 
Wrapper for a Handle; used to create a memberTable that acts like Table<Handle, Node*> but stores only Handle* internally to avoid memory copies. More...
 
typedef Table< Member, Node * > MemberTable
 

Protected Member Functions

NodecloneTree (Node *src)
 
Recursively clone the passed in node tree, setting pointers for members in the memberTable as appropriate. More...
 
NodemakeNode (Array< Handle *> &source, int valuesPerNode, int numMeanSplits, Array< Handle *> &temp)
 
Recursively subdivides the subarray. More...
 

Static Protected Member Functions

static AABox computeBounds (const Array< Handle *> &point, int beginIndex, int endIndex)
 Returns the bounds of the sub array. More...
 
static void getIntersectingMembers (const Array< Plane > &plane, Array< T *> &members, Node *node, uint32 parentMask)
 
More...
 

Protected Attributes

MemberTable memberTable
 Maps members to the node containing them. More...
 
Noderoot
 

Detailed Description

template<class T, class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
class G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >


A set that supports spatial queries using a KD tree (axis-aligned BSP tree) for speed.

KDTree allows you to quickly find objects in 3D that lie within a box or along a ray. For large sets of objects it is much faster than testing each object for a collision.

KDTree is as powerful as but more general than a Quad Tree, Oct Tree, or regular KD tree that cycles through axes, but less general than an unconstrained BSP tree (which is much slower to create).

Internally, objects are arranged into a tree according to their axis-aligned bounds. This increases the cost of insertion to O(log n) but allows fast overlap queries.

Template Parameters

The template parameter T must be one for which the following functions are all overloaded:

 T::T(); // public constructor of no arguments
 template <> struct HashTrait<T> { static size_t hashCode(int key); };
 template<> struct BoundsTrait<T> { static void getBounds(const T& obj, G3D::AABox& out); };

G3D provides these for common classes like G3D::Vector3 and G3D::Sphere. If you use a custom class, or a pointer to a custom class, you will need to define those functions.

Moving Set Members

It is important that objects do not move without updating the KDTree. If the axis-aligned bounds of an object are about to change, KDTree::remove it before they change and KDTree::insert it again afterward. For objects where the hashCode and == operator are invariant with respect to the 3D position, you can use the KDTree::update method as a shortcut to insert/remove an object in one step after it has moved.

Note: Do not mutate any value once it has been inserted into KDTree. Values are copied interally. All KDTree iterators convert to pointers to constant values to reinforce this.

If you want to mutate the objects you intend to store in a KDTree simply insert pointers to your objects instead of the objects themselves, and ensure that the above operations are defined. (And actually, because values are copied, if your values are large you may want to insert pointers anyway, to save space and make the balance operation faster.)

Dimensions Although designed as a 3D-data structure, you can use the KDTree for data distributed along 2 or 1 axes by simply returning bounds that are always zero along one or more dimensions.

Member Typedef Documentation

◆ Member

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
typedef _internal::Indirector<Handle> G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::Member
protected


Wrapper for a Handle; used to create a memberTable that acts like Table<Handle, Node*> but stores only Handle* internally to avoid memory copies.

◆ MemberTable

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
typedef Table<Member, Node*> G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::MemberTable
protected

Constructor & Destructor Documentation

◆ KDTree() [1/2]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::KDTree ( )
inline

To construct a balanced tree, insert the elements and then call KDTree::balance().

◆ KDTree() [2/2]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::KDTree ( const KDTree< T, BoundsFunc, HashFunc, EqualsFunc > &  src)
inline

◆ ~KDTree()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::~KDTree ( )
inline

Member Function Documentation

◆ balance()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::balance ( int  valuesPerNode = 5,
int  numMeanSplits = 3 
)
inline


Rebalances the tree (slow).

Call when objects have moved substantially from their original positions (which unbalances the tree and causes the spatial queries to be slow).

Parameters
valuesPerNodeMaximum number of elements to put at a node.
numMeanSplitsnumMeanSplits = 0 gives a fully axis aligned BSP-tree, where the balance operation attempts to balance the tree so that every splitting plane has an equal number of left and right children (i.e. it is a median split along that axis).
This tends to maximize average performance.
You can override this behavior by setting a number of mean (average) splits. numMeanSplits = MAX_INT creates a full oct-tree, which tends to optimize peak performance at the expense of average performance. It tends to have better clustering behavior when members are not uniformly distributed.

Referenced by G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::setContents().

◆ begin()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
Iterator G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::begin ( ) const
inline


C++ STL style iterator method.

Returns the first member.
Use preincrement (++entry) to get to the next element (iteration order is arbitrary).
Do not modify the set while iterating.

◆ beginBoxIntersection()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
BoxIntersectionIterator G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::beginBoxIntersection ( const AABox box) const
inline


Iterates through the members that intersect the box

◆ clear()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::clear ( )
inline

◆ cloneTree()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
Node* G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::cloneTree ( Node src)
inlineprotected


Recursively clone the passed in node tree, setting pointers for members in the memberTable as appropriate.

called by the assignment operator.

Referenced by G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::operator=().

◆ computeBounds()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
static AABox G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::computeBounds ( const Array< Handle *> &  point,
int  beginIndex,
int  endIndex 
)
inlinestaticprotected

Returns the bounds of the sub array.

Used by makeNode.

Referenced by G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::makeNode().

◆ contains()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
bool G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::contains ( const T &  value)
inline

◆ deserializeStructure()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::deserializeStructure ( BinaryInput bi)
inline

Clears the member table.

◆ end()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
Iterator G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::end ( ) const
inline


C++ STL style iterator method.

Returns one after the last iterator element.

Referenced by G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::clear().

◆ endBoxIntersection()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
BoxIntersectionIterator G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::endBoxIntersection ( ) const
inline

◆ getIntersectingMembers() [1/9]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
static void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::getIntersectingMembers ( const Array< Plane > &  plane,
Array< T *> &  members,
Node node,
uint32  parentMask 
)
inlinestaticprotected


Parameters
parentMaskThe mask that this node returned from culledBy.

Referenced by G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::getIntersectingMembers().

◆ getIntersectingMembers() [2/9]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::getIntersectingMembers ( const Array< Plane > &  plane,
Array< T *> &  members 
) const
inline


Returns all members inside the set of planes.

Parameters
membersThe results are appended to this array.

◆ getIntersectingMembers() [3/9]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::getIntersectingMembers ( const Array< Plane > &  plane,
Array< T > &  members 
) const
inline

◆ getIntersectingMembers() [4/9]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::getIntersectingMembers ( const Frustum frustum,
Array< T *> &  members 
) const
inline


Typically used to find all visible objects inside the view frustum (see also Camera::getClipPlanes)...

i.e. all objects not culled by frustum.

Example:

   Array<Object*>  visible;
   tree.getIntersectingMembers(camera.frustum(), visible);
   // ... Draw all objects in the visible array.
 
Parameters
membersThe results are appended to this array.

◆ getIntersectingMembers() [5/9]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::getIntersectingMembers ( const Frustum frustum,
Array< T > &  members 
) const
inline

◆ getIntersectingMembers() [6/9]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::getIntersectingMembers ( const AABox box,
Array< T *> &  members 
) const
inline


Appends all members whose bounds intersect the box.

See also KDTree::beginBoxIntersection.

◆ getIntersectingMembers() [7/9]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::getIntersectingMembers ( const AABox box,
Array< T > &  members 
) const
inline

◆ getIntersectingMembers() [8/9]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::getIntersectingMembers ( const Sphere sphere,
Array< T *> &  members 
) const
inline

Finds all members whose bounding boxes intersect the sphere.

The actual elements may not intersect the sphere.

Parameters
membersThe results are appended to this array.

◆ getIntersectingMembers() [9/9]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::getIntersectingMembers ( const Sphere sphere,
Array< T > &  members 
) const
inline

◆ getMembers()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::getMembers ( Array< T > &  members) const
inline


Returns an array of all members of the set.

See also KDTree::begin.

◆ getPointer()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
const T* G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::getPointer ( const T &  value) const
inline

If a value that is EqualsFunc to value is present, returns a pointer to the version stored in the data structure, otherwise returns nullptr.

◆ insert() [1/2]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::insert ( const T &  value)
inline


Inserts an object into the set if it is not already present.

O(log n) time. Does not cause the tree to be balanced.

Referenced by G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::insert(), G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::setContents(), and G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::update().

◆ insert() [2/2]

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::insert ( const Array< T > &  valueArray)
inline

Inserts each elements in the array in turn.

If the tree begins empty (no structure and no elements), this is faster than inserting each element in turn. You still need to balance the tree at the end.

◆ intersectRay()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
template<typename RayCallback >
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::intersectRay ( const Ray ray,
RayCallback &  intersectCallback,
float &  distance,
bool  intersectCallbackIsFast = false 
) const
inline


Invoke a callback for every member along a ray until the closest intersection is found.

Parameters
intersectCallbackEither a function or an instance of a class with an overloaded operator() of the form:
    void callback(const Ray& ray, const T& object, float& distance).
If the ray hits the object before travelling distance distance, updates distance with the new distance to the intersection, otherwise leaves it unmodified. A common example is:
class Entity {
public:
    void intersect(const Ray& ray, float& maxDist, Vector3& outLocation, Vector3& outNormal) {
        float d = maxDist;

        // ... search for intersection distance d

        if ((d > 0) && (d < maxDist)) {
            // Intersection occured
            maxDist = d;
            outLocation = ...;
            outNormal = ...;
        }
    }
};

// Finds the surface normal and location of the first intersection with the scene
class Intersection {
public:
    Entity*     closestEntity;
    Vector3     hitLocation;
    Vector3     hitNormal;

    void operator()(const Ray& ray, const Entity* entity, float& distance) {
        entity->intersect(ray, distance, hitLocation, hitNormal);
    }
};

KDTree scene;

Intersection intersection;
float distance = finf();
scene.intersectRay(camera.worldRay(x, y), intersection, distance);
distanceWhen the method is invoked, this is the maximum distance that the tree should search for an intersection. On return, this is set to the distance to the first intersection encountered.
intersectCallbackIsFastIf false, each object's bounds are tested before the intersectCallback is invoked. If the intersect callback runs at the same speed or faster than AABox-ray intersection, set this to true.

◆ makeNode()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
Node* G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::makeNode ( Array< Handle *> &  source,
int  valuesPerNode,
int  numMeanSplits,
Array< Handle *> &  temp 
)
inlineprotected


Recursively subdivides the subarray.

Clears the source array as soon as it is no longer needed.

Call assignSplitBounds() on the root node after making a tree.

Referenced by G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::balance().

◆ operator=()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
KDTree& G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::operator= ( const KDTree< T, BoundsFunc, HashFunc, EqualsFunc > &  src)
inline

◆ remove()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::remove ( const T &  value)
inline


Removes an object from the set in O(1) time.

It is an error to remove members that are not already present. May unbalance the tree.
Removing an element never causes a node (split plane) to be removed... nodes are only changed when the tree is rebalanced. This behavior is desirable because it allows the split planes to be serialized, and then deserialized into an empty tree which can be repopulated.

◆ serializeStructure()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::serializeStructure ( BinaryOutput bo) const
inline

Stores the locations of the splitting planes (the structure but not the content) so that the tree can be quickly rebuilt from a previous configuration without calling balance.

◆ setContents()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::setContents ( const Array< T > &  array,
int  valuesPerNode = 5,
int  numMeanSplits = 3 
)
inline

Clear, set the contents to the values in the array, and then balance.

◆ size()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
int G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::size ( ) const
inline

◆ update()

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
void G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::update ( const T &  value)
inline


If the element is in the set, it is removed.

The element is then inserted.

This is useful when the == and hashCode methods on T are independent of the bounds. In that case, you may call update(v) to insert an element for the first time and call update(v) again every time it moves to keep the tree up to date.

Member Data Documentation

◆ memberTable

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
MemberTable G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::memberTable
protected

◆ root

template<class T , class BoundsFunc = BoundsTrait<T>, class HashFunc = HashTrait<T>, class EqualsFunc = EqualsTrait<T>>
Node* G3D::KDTree< T, BoundsFunc, HashFunc, EqualsFunc >::root
protected

documentation generated on Wed Nov 24 2021 08:01:57 using doxygen 1.8.15