Helios++
Helios software for LiDAR simulations
|
Class providing building methods for simple k-dimensional trees. More...
#include <SimpleKDTreeFactory.h>
Public Member Functions | |
SimpleKDTreeFactory () | |
SimpleKDTreeFactory default constructor. More... | |
KDTreeFactory * | clone () const override |
virtual void | _clone (KDTreeFactory *kdtf) const |
Assign attributes from soruce SimpleKDTreeFactory to its clone. | |
KDTreeNodeRoot * | makeFromPrimitivesUnsafe (vector< Primitive * > &primitives, bool const computeStats=false, bool const reportStats=false) override |
Build a simple KDTree from given primitives. More... | |
![]() | |
KDTreeFactory () | |
K dimensional tree factory default constructor. | |
virtual KDTreeNodeRoot * | makeFromPrimitives (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 KDTreeNode * | buildRecursive (KDTreeNode *parent, bool const left, vector< Primitive * > &primitives, int const depth, int const index) |
Recursively build a KDTree for given primitives. More... | |
virtual KDTreeNode * | 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) |
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... | |
![]() | |
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... | |
![]() | |
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 |
SimpleKDTreeFactory::SimpleKDTreeFactory | ( | ) |
SimpleKDTreeFactory default constructor.
The buildRecursive member function is assigned to the _buildRecursive function as member attribute
|
protectedvirtual |
Build children nodes for given node. If no children nodes must be built, then the node is configured as a leaf node.
[out] | node | Node which children will be built if possible and, if not, then will be configured as leaf node |
parent | The parent node if any. For root nodes, it will be a nullptr | |
primitives | Primitives of the node itself | |
depth | Depth of current node | |
index | Index of current node at current depth | |
leftPrimitives | Primitives for left child node | |
rightPrimitives | Primitives for right child node |
Reimplemented in SAHKDTreeFactory.
|
protectedvirtual |
Recursively build a KDTree for given primitives.
parent | The parent node if any. For root nodes, it must be a nullptr |
left | True 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 |
primitives | Primitives to build KDTree splitting them |
depth | Current depth at build process. Useful for tracking recursion level |
index | The 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. |
Reimplemented in MultiThreadKDTreeFactory.
|
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.
f_computeNodeBoundaries | The function to compute node boundaries. For the base case it is SimpleKDTreeFactory::buildRecursive |
f_defineSplit | The function to define split axis and position. For the base case it is SimpleKDTreeFactory::computeNodeBoundaries |
f_populateSplits | The function to populate left and right splits with corresponding primitives. For the base case it is SimpleKDTreeFactory::populateSplits |
f_buildChildrenNodes | The function to build the children nodes (left and right). For the base case it is SimpleKDTreeFactory::buildChildrenNodes |
|
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.
Reimplemented in SAHKDTreeFactory.
|
overridevirtual |
Implements KDTreeFactory.
|
protectedvirtual |
Analyze KDTree computing its max depth and the minimum and maximum number of primitives considering all nodes.
root | Root node to compute stats for given KDTreeNodeRoot |
Reimplemented in SAHKDTreeFactory, and MultiThreadKDTreeFactory.
|
protectedvirtual |
Function to assist SimpleKDTreeFactory::computeNodeBoundaries when computing surface area heuristic and minimum and maximum positions for child nodes.
node | The child node itself |
|
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. \]
node | Root node which surface area must be computed |
parent | The parent node if any. For root nodes, it will be a nullptr |
left | True 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 |
primitives | Vector of primitives inside given root node |
|
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\)
[out] | node | Node which split axis and split position are going to be defined |
parent | The parent node if any. For root nodes, it will be a nullptr | |
primitives | Primitives of node which split must be defined | |
depth | Depth of node which split must be defined |
Reimplemented in SAHKDTreeFactory, and AxisSAHKDTreeFactory.
|
overridevirtual |
Build a simple KDTree from given primitives.
primitives | Primitives to build simple KDTree splitting them |
Implements KDTreeFactory.
|
protectedvirtual |
Make given node a leaf one.
[out] | node | Node to be made a leaf |
primitives | Primitives for the leaf node |
|
protectedvirtual |
Function to assist SimpleKDTreeFactory::computeNodeBoundaries when computing the SAH for a node.
[out] | node | Node which surface area and bound is going to be calculated (and setted) |
|
protectedvirtual |
Function to assist SimpleKDTreeFactory::populateSplits by providing the logic of digesting a primitive.
|
protectedvirtual |
Function to assist SimpleKDTreeFactory::computeNodeBoundaries by providing the logic of digesting a primitive.
p | Primitive to be digested |
|
protectedvirtual |
Populate list of primitives for left and right splits from given primitives of node being splitted.
primitives | Primitives of node being splitted | |
splitAxis | Index of axis defining the split | |
splitPos | Position on given axis of the split point | |
[out] | leftPrimitives | Where primitives of left split must be stored |
[out] | rightPrimitives | Where primitives of right split must be stored |
|
protectedvirtual |
Report KDTree stats of given root node at INFO logging level.
root | Root node which stats must be reported |
Reimplemented in MultiThreadKDTreeFactory.
|
inlineprivate |
Serialize a simple KDTree factory to a stream of bytes.
Archive | Type of rendering |
ar | Specific rendering for the stream of bytes |
version | Version number for the simple KDTree factory |
|
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.
|
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.