Helios++
Helios software for LiDAR simulations
SimpleKDTreeFactory Class Reference

Class providing building methods for simple k-dimensional trees. More...

#include <SimpleKDTreeFactory.h>

Inheritance diagram for SimpleKDTreeFactory:
Collaboration diagram for SimpleKDTreeFactory:

Public Member Functions

 SimpleKDTreeFactory ()
 SimpleKDTreeFactory default constructor. More...
 
KDTreeFactoryclone () const override
 
virtual void _clone (KDTreeFactory *kdtf) const
 Assign attributes from soruce SimpleKDTreeFactory to its clone.
 
KDTreeNodeRootmakeFromPrimitivesUnsafe (vector< Primitive * > &primitives, bool const computeStats=false, bool const reportStats=false) override
 Build a simple KDTree from given primitives. More...
 
- Public Member Functions inherited from KDTreeFactory
 KDTreeFactory ()
 K dimensional tree factory default constructor.
 
virtual KDTreeNodeRootmakeFromPrimitives (vector< Primitive * > const &primitives, bool const computeStats=false, bool const reportStats=false)
 Safe wrapper from makeFromPrimitivesUnsafe which handles a copy to make from primitives by default. This function behavior might be overridden by any derived/child class. It is expected that any implementation of makeFromPrimitives provides a way to implement the makeFromPrimitivesUnsafe method without modifying vector of input primitives. Notice this does not mean primitives themselves cannot be modified, that depends on the type of KDTreeFactory. It only means that the vector itself will not be modified, for instance due to sorting purposes. More...
 
virtual bool isBuildingLightNodes ()
 Check if KDTreeFactory is building light nodes. More...
 
virtual void setBuildingLightNodes (bool const buildLightNodes)
 Set KDTreeFactory so it build light nodes (true) or not (false) More...
 
virtual void setChild (LightKDTreeNode *&child, KDTreeNode *node)
 Set child to given node if and only if node is not null. It must be used to assign children nodes in a thread-safe way. More...
 

Protected Member Functions

virtual KDTreeNodebuildRecursive (KDTreeNode *parent, bool const left, vector< Primitive * > &primitives, int const depth, int const index)
 Recursively build a KDTree for given primitives. More...
 
virtual KDTreeNodebuildRecursiveRecipe (KDTreeNode *parent, bool const left, vector< Primitive * > &primitives, int const depth, int const index, std::function< void(KDTreeNode *node, KDTreeNode *parent, bool const left, vector< Primitive * > const &primitives)> f_computeNodeBoundaries, std::function< void(KDTreeNode *node, KDTreeNode *parent, vector< Primitive * > &primitives, int const depth)> f_defineSplit, std::function< void(vector< Primitive * > const &primitives, int const splitAxis, double const splitPos, vector< Primitive * > &leftPrimitives, vector< Primitive * > &rightPrimitives)> f_populateSplits, std::function< void(KDTreeNode *node, KDTreeNode *parent, vector< Primitive * > const &primitives, int const depth, int const index, vector< Primitive * > &leftPrimitives, vector< Primitive * > &rightPrimitives)> f_buildChildrenNodes)
 The recipe of the recursive building algorithm. It is meant to be used by the SimpleKDTreeFactory::buildRecursive but also by any alternative implementation which shares the same recipe (global logic) but changes the way some parts are computed. For instance, it is used by the MultiThreadKDTreeFactory to handle geometry-level parallelization. More...
 
virtual void computeKDTreeStats (KDTreeNodeRoot *root) const
 Analyze KDTree computing its max depth and the minimum and maximum number of primitives considering all nodes. More...
 
virtual void reportKDTreeStats (KDTreeNodeRoot *root, vector< Primitive * > const &primitives) const
 Report KDTree stats of given root node at INFO logging level. More...
 
virtual void defineSplit (KDTreeNode *node, KDTreeNode *parent, vector< Primitive * > &primitives, int const depth) const
 Define the split axis and position for current node. More...
 
virtual void populateSplits (vector< Primitive * > const &primitives, int const splitAxis, double const splitPos, vector< Primitive * > &leftPrimitives, vector< Primitive * > &rightPrimitives) const
 Populate list of primitives for left and right splits from given primitives of node being splitted. More...
 
virtual void buildChildrenNodes (KDTreeNode *node, KDTreeNode *parent, vector< Primitive * > const &primitives, int const depth, int const index, vector< Primitive * > &leftPrimitives, vector< Primitive * > &rightPrimitives)
 Build children nodes for given node. If no children nodes must be built, then the node is configured as a leaf node. More...
 
virtual void computeNodeBoundaries (KDTreeNode *node, KDTreeNode *parent, bool const left, vector< Primitive * > const &primitives) const
 Compute min and max position and surface area of bounding cuboid for given node. More...
 
virtual void onPopulateSplitsDigestPrimitive (Primitive *p, int const splitAxis, double const splitPos, vector< Primitive * > &leftPrimitives, vector< Primitive * > &rightPrimitives) const
 Function to assist SimpleKDTreeFactory::populateSplits by providing the logic of digesting a primitive. More...
 
virtual void computeMinMaxSAHForChild (KDTreeNode *node, KDTreeNode *parent, bool const left, vector< Primitive * > const &primitives) const
 Function to assist SimpleKDTreeFactory::computeNodeBoundaries when computing surface area heuristic and minimum and maximum positions for child nodes. More...
 
virtual void onRootBoundariesDigestPrimitive (Primitive *primitive, double &ax, double &ay, double &az, double &bx, double &by, double &bz) const
 Function to assist SimpleKDTreeFactory::computeNodeBoundaries by providing the logic of digesting a primitive. More...
 
virtual void onComputeNodeBoundariesCalcSAH (KDTreeNode *node, double const ax, double const ay, double const az, double const bx, double const by, double const bz) const
 Function to assist SimpleKDTreeFactory::computeNodeBoundaries when computing the SAH for a node. More...
 
virtual bool checkNodeMustSplit (vector< Primitive * > const &primitives, vector< Primitive * > const &leftPrimitives, vector< Primitive * > const &rightPrimitives) const
 Check wheter the node must be splitted (true) or not (false) depending on its total primitives and the ones that would be assigned to left and right children. More...
 
virtual void makeLeaf (KDTreeNode *node, vector< Primitive * > const &primitives) const
 Make given node a leaf one. More...
 
- Protected Member Functions inherited from KDTreeFactory
virtual void lighten (KDTreeNodeRoot *root)
 Rebuild all children of given root KDTree node as LightKDTeeeNode nodes. More...
 
virtual LightKDTreeNode_lighten (KDTreeNode *node)
 Assist KDTreeFactory::lighten function by handling the lighten of a given non-root node. More...
 

Protected Attributes

std::function< KDTreeNode *(KDTreeNode *, bool const, vector< Primitive * > &, int const, int const)> _buildRecursive
 The member function as attribute used to recursively build KDTree nodes. By default it will be assigned to the buildRecursive member function but it might be overridden by other implementations. For instance, to wrap the buildRecursive behavior to handle parallel building of KDTrees. More...
 
size_t minSplitPrimitives
 How many primitives are required for a node to be splitted. More...
 
- Protected Attributes inherited from KDTreeFactory
bool buildLightNodes = true
 When it is true, the KDTreeFactory is expected to build light nodes. It is, built KDTree must have a KDTreeRootNode which children are all LightKDTreeNode. When it is false, KDTreeFactory is allowed to build KDTree with KDTreeNode children, which might require more memory. More...
 
LightKDTreeNodeBlockAllocator lkdtnBlockAllocator
 The block allocator to speed-up lighten of KDTree by reducing allocation calls when instantiating multiple LightKDTreeNode. More...
 

Private Member Functions

template<typename Archive >
void serialize (Archive &ar, const unsigned int version)
 Serialize a simple KDTree factory to a stream of bytes. More...
 

Friends

class MultiThreadKDTreeFactory
 
class SimpleKDTreeGeometricStrategy
 
class boost::serialization::access
 

Detailed Description

Class providing building methods for simple k-dimensional trees.

Author
Alberto M. Esmoris Pena
Version
1.0
See also
KDTreeFactory

Constructor & Destructor Documentation

◆ SimpleKDTreeFactory()

SimpleKDTreeFactory::SimpleKDTreeFactory ( )

SimpleKDTreeFactory default constructor.

The buildRecursive member function is assigned to the _buildRecursive function as member attribute

Member Function Documentation

◆ buildChildrenNodes()

void SimpleKDTreeFactory::buildChildrenNodes ( KDTreeNode node,
KDTreeNode parent,
vector< Primitive * > const &  primitives,
int const  depth,
int const  index,
vector< Primitive * > &  leftPrimitives,
vector< Primitive * > &  rightPrimitives 
)
protectedvirtual

Build children nodes for given node. If no children nodes must be built, then the node is configured as a leaf node.

Parameters
[out]nodeNode which children will be built if possible and, if not, then will be configured as leaf node
parentThe parent node if any. For root nodes, it will be a nullptr
primitivesPrimitives of the node itself
depthDepth of current node
indexIndex of current node at current depth
leftPrimitivesPrimitives for left child node
rightPrimitivesPrimitives for right child node

Reimplemented in SAHKDTreeFactory.

◆ buildRecursive()

KDTreeNode * SimpleKDTreeFactory::buildRecursive ( KDTreeNode parent,
bool const  left,
vector< Primitive * > &  primitives,
int const  depth,
int const  index 
)
protectedvirtual

Recursively build a KDTree for given primitives.

Parameters
parentThe parent node if any. For root nodes, it must be a nullptr
leftTrue if given node is a left child, false otherwise. If the node is a root node, it should be false. If node is not a root node and left is true, it means it is a left child. If node is not a root node and left is false, it means it is a right child
primitivesPrimitives to build KDTree splitting them
depthCurrent depth at build process. Useful for tracking recursion level
indexThe node index inside current depth. Each node can be univocally identified by the ordered pair \((d, i)\) where \(d\) stands for the depth level and \(i\) for the index. The root node is identified by \((0, 0)\). Any left child node will be \((d+1, 2i)\) and any right child node will be \((d+1, 2i+1)\), where \(d\) and \(i\) are the depth and index for the parent node. In consequence, all left nodes will have an even index while all right nodes will have an odd one. However, notice that for performance reasons it could preferable to check the left flag argument, as it is faster than checking if index is even or odd.
Returns
Built KDTree node

Reimplemented in MultiThreadKDTreeFactory.

◆ buildRecursiveRecipe()

KDTreeNode * SimpleKDTreeFactory::buildRecursiveRecipe ( KDTreeNode parent,
bool const  left,
vector< Primitive * > &  primitives,
int const  depth,
int const  index,
std::function< void(KDTreeNode *node, KDTreeNode *parent, bool const left, vector< Primitive * > const &primitives)>  f_computeNodeBoundaries,
std::function< void(KDTreeNode *node, KDTreeNode *parent, vector< Primitive * > &primitives, int const depth)>  f_defineSplit,
std::function< void(vector< Primitive * > const &primitives, int const splitAxis, double const splitPos, vector< Primitive * > &leftPrimitives, vector< Primitive * > &rightPrimitives)>  f_populateSplits,
std::function< void(KDTreeNode *node, KDTreeNode *parent, vector< Primitive * > const &primitives, int const depth, int const index, vector< Primitive * > &leftPrimitives, vector< Primitive * > &rightPrimitives)>  f_buildChildrenNodes 
)
protectedvirtual

The recipe of the recursive building algorithm. It is meant to be used by the SimpleKDTreeFactory::buildRecursive but also by any alternative implementation which shares the same recipe (global logic) but changes the way some parts are computed. For instance, it is used by the MultiThreadKDTreeFactory to handle geometry-level parallelization.

Parameters
f_computeNodeBoundariesThe function to compute node boundaries. For the base case it is SimpleKDTreeFactory::buildRecursive
f_defineSplitThe function to define split axis and position. For the base case it is SimpleKDTreeFactory::computeNodeBoundaries
f_populateSplitsThe function to populate left and right splits with corresponding primitives. For the base case it is SimpleKDTreeFactory::populateSplits
f_buildChildrenNodesThe function to build the children nodes (left and right). For the base case it is SimpleKDTreeFactory::buildChildrenNodes
See also
SimpleKDTreeFactory::buildRecursive
SimpleKDTreeFactory::computeNodeBoundaries
SimpleKDTreeFactory::defineSplit
SimpleKDTreeFactory::populateSplits
SimpleKDTreeFactory::buildChildrenNodes
MultiThreadKDTreeFactory
Returns
Built KDTree node

◆ checkNodeMustSplit()

bool SimpleKDTreeFactory::checkNodeMustSplit ( vector< Primitive * > const &  primitives,
vector< Primitive * > const &  leftPrimitives,
vector< Primitive * > const &  rightPrimitives 
) const
protectedvirtual

Check wheter the node must be splitted (true) or not (false) depending on its total primitives and the ones that would be assigned to left and right children.

For a simple KDT a node must be splitted if there are enough primitives and not all of them are contained neither in left nor in right children nodes.

Returns
True if node must be splitted, false otherwise
See also
SimpleKDTreeFactory::minSplitPrimitives

Reimplemented in SAHKDTreeFactory.

◆ clone()

KDTreeFactory * SimpleKDTreeFactory::clone ( ) const
overridevirtual
See also
KDTreeFactory::clone

Implements KDTreeFactory.

◆ computeKDTreeStats()

void SimpleKDTreeFactory::computeKDTreeStats ( KDTreeNodeRoot root) const
protectedvirtual

Analyze KDTree computing its max depth and the minimum and maximum number of primitives considering all nodes.

Parameters
rootRoot node to compute stats for given KDTreeNodeRoot

Reimplemented in SAHKDTreeFactory, and MultiThreadKDTreeFactory.

◆ computeMinMaxSAHForChild()

void SimpleKDTreeFactory::computeMinMaxSAHForChild ( KDTreeNode node,
KDTreeNode parent,
bool const  left,
vector< Primitive * > const &  primitives 
) const
protectedvirtual

Function to assist SimpleKDTreeFactory::computeNodeBoundaries when computing surface area heuristic and minimum and maximum positions for child nodes.

Parameters
nodeThe child node itself
See also
SimpleKDTreeFactory::computeNodeBoundaries
SimpleKDTreeFactory::onRootBoundariesDigestPrimitive
SimpleKDTreeFactory::onComputeNodeBoundariesCalcSAH

◆ computeNodeBoundaries()

void SimpleKDTreeFactory::computeNodeBoundaries ( KDTreeNode node,
KDTreeNode parent,
bool const  left,
vector< Primitive * > const &  primitives 
) const
protectedvirtual

Compute min and max position and surface area of bounding cuboid for given node.

Surface area for a cuboid can be computed considering \(l_i\) is the length of \(i-th\) axis.

For instance, surface area of root node \(R\) in \(\mathbb{R}^2\) can be computed as follows:

\[ S_A(R) = l_x l_y \]

Analogously, the surface area of root node \(R\) in \(\mathbb{R}^3\) can be computed as follows:

\[ S_A(R) = 2(l_x l_y + l_x l_z + l_y l_z) \]

The boundaries for the root node are taken from min and max vertex of given set of primitives. Surface area and min and max boundaries for children nodes are just taken proportionally to \(r\) where \(p\) is the split position and \(a\) and \(b\) are the min and max positions respectively:

\[ r = \frac{p-a}{b-a} \]

For the sake of understanding, surface area for children nodes is explained in detail. For this purpose, notice that \(p \in [a, b]\). Now lets define left and right children surface area respectively, namely \(S_A(L_b)\) and \(S_A(R_b)\) where \(S_A(P)\) is the surface area of the parent node itself:

\[ \left\{\begin{array}{lllll} S_A(L_b) &=& r S_A(P) &=& \frac{p-a}{b-a} S_A(P) \\ S_A(R_b) &=& (1-r) S_A(P) &=& \left(1 - \frac{p-a}{b-a}\right) S_A(P) \end{array}\right. \]

Parameters
nodeRoot node which surface area must be computed
parentThe parent node if any. For root nodes, it will be a nullptr
leftTrue if given node is a left child, false otherwise. If the node is a root node, it should be false. If node is not a root node and left is true, it means it is a left child. If node is not a root node and left is false, it means it is a right child
primitivesVector of primitives inside given root node
See also
SimpleKDTreeFactory::computeMinMaxSAHForChild
SimpleKDTreeFactory::onRootBoundariesDigestPrimitive
SimpleKDTreeFactory::onComputeNodeBoundariesCalcSAH

◆ defineSplit()

void SimpleKDTreeFactory::defineSplit ( KDTreeNode node,
KDTreeNode parent,
vector< Primitive * > &  primitives,
int const  depth 
) const
protectedvirtual

Define the split axis and position for current node.

The simple KDTree factory defines the split point as the position of the median which splits primitives along split axis into two nodes which tend to have the same number of primitives. To illustrate this, let \(d\) be the depth of the node and \(n\) be the space dimensionality. Therefore, the split axis can be defined as \(a = d \mod n\). If \(P=\left\{p_1, \ldots, p_n\right\}\) is the set of all primitives contained in the node where \(\forall i, p_i=(p_{i1}, \ldots, p_{in})\), the split position \(s\) can be used to define following sets:

\[ \alpha = \left\{ p_i : p_{ia} \leq s \right\} \\ \beta = \left\{ p_i : p_{ia} > s \right\} \]

But if \(s\) is the median of primitives distribution along \(a\)-axis, then if there are no equal primitives it will be satisfied that \(0 \leq |\alpha| - |\beta| \leq 1\)

Parameters
[out]nodeNode which split axis and split position are going to be defined
parentThe parent node if any. For root nodes, it will be a nullptr
primitivesPrimitives of node which split must be defined
depthDepth of node which split must be defined

Reimplemented in SAHKDTreeFactory, and AxisSAHKDTreeFactory.

◆ makeFromPrimitivesUnsafe()

KDTreeNodeRoot * SimpleKDTreeFactory::makeFromPrimitivesUnsafe ( vector< Primitive * > &  primitives,
bool const  computeStats = false,
bool const  reportStats = false 
)
overridevirtual

Build a simple KDTree from given primitives.

Parameters
primitivesPrimitives to build simple KDTree splitting them
Returns
Pointer to root node of built simple KDTree

Implements KDTreeFactory.

◆ makeLeaf()

void SimpleKDTreeFactory::makeLeaf ( KDTreeNode node,
vector< Primitive * > const &  primitives 
) const
protectedvirtual

Make given node a leaf one.

Parameters
[out]nodeNode to be made a leaf
primitivesPrimitives for the leaf node

◆ onComputeNodeBoundariesCalcSAH()

void SimpleKDTreeFactory::onComputeNodeBoundariesCalcSAH ( KDTreeNode node,
double const  ax,
double const  ay,
double const  az,
double const  bx,
double const  by,
double const  bz 
) const
protectedvirtual

Function to assist SimpleKDTreeFactory::computeNodeBoundaries when computing the SAH for a node.

Parameters
[out]nodeNode which surface area and bound is going to be calculated (and setted)
See also
SimpleKDTreeFactory::computeNodeBoundaries
SimpleKDTreeFactory::computeMinMaxSAHForChild
SimpleKDTreeFactory::onRootBoundariesDigestPrimitive

◆ onPopulateSplitsDigestPrimitive()

void SimpleKDTreeFactory::onPopulateSplitsDigestPrimitive ( Primitive p,
int const  splitAxis,
double const  splitPos,
vector< Primitive * > &  leftPrimitives,
vector< Primitive * > &  rightPrimitives 
) const
protectedvirtual

Function to assist SimpleKDTreeFactory::populateSplits by providing the logic of digesting a primitive.

See also
SimpleKDTreeFactory::populateSplits

◆ onRootBoundariesDigestPrimitive()

void SimpleKDTreeFactory::onRootBoundariesDigestPrimitive ( Primitive primitive,
double &  ax,
double &  ay,
double &  az,
double &  bx,
double &  by,
double &  bz 
) const
protectedvirtual

◆ populateSplits()

void SimpleKDTreeFactory::populateSplits ( vector< Primitive * > const &  primitives,
int const  splitAxis,
double const  splitPos,
vector< Primitive * > &  leftPrimitives,
vector< Primitive * > &  rightPrimitives 
) const
protectedvirtual

Populate list of primitives for left and right splits from given primitives of node being splitted.

Parameters
primitivesPrimitives of node being splitted
splitAxisIndex of axis defining the split
splitPosPosition on given axis of the split point
[out]leftPrimitivesWhere primitives of left split must be stored
[out]rightPrimitivesWhere primitives of right split must be stored
See also
SimpleKDTreeFactory::onPopulateSplitsDigestPrimitive

◆ reportKDTreeStats()

void SimpleKDTreeFactory::reportKDTreeStats ( KDTreeNodeRoot root,
vector< Primitive * > const &  primitives 
) const
protectedvirtual

Report KDTree stats of given root node at INFO logging level.

Parameters
rootRoot node which stats must be reported

Reimplemented in MultiThreadKDTreeFactory.

◆ serialize()

template<typename Archive >
void SimpleKDTreeFactory::serialize ( Archive &  ar,
const unsigned int  version 
)
inlineprivate

Serialize a simple KDTree factory to a stream of bytes.

Template Parameters
ArchiveType of rendering
Parameters
arSpecific rendering for the stream of bytes
versionVersion number for the simple KDTree factory

Member Data Documentation

◆ _buildRecursive

std::function<KDTreeNode *( KDTreeNode *, bool const, vector<Primitive *> &, int const, int const )> SimpleKDTreeFactory::_buildRecursive
protected

The member function as attribute used to recursively build KDTree nodes. By default it will be assigned to the buildRecursive member function but it might be overridden by other implementations. For instance, to wrap the buildRecursive behavior to handle parallel building of KDTrees.

See also
SimpleKDTreeFactory::buildRecursive

◆ minSplitPrimitives

size_t SimpleKDTreeFactory::minSplitPrimitives
protected

How many primitives are required for a node to be splitted.

If number of primitives is equal or greater than, then node might be splitted if necessary criterion is satisfied. Otherwise, no matter if other splitting criterion is satisfied, node will never be splitted. It is mainly useful to prevent too deep KDTrees which might lead to consuming a high amount of memory without significant performance improvement.


The documentation for this class was generated from the following files: