11#ifndef PBAT_GEOMETRY_KDTREE_H
12#define PBAT_GEOMETRY_KDTREE_H
32 enum { kLeafNodeLeftChild = -2 };
42 [[maybe_unused]]
bool IsLeaf()
const {
return c == -2; }
52 [[maybe_unused]]
auto Left()
const {
return c; }
57 [[maybe_unused]]
auto Right()
const {
return c + 1; }
76 template <
class TDerivedP>
77 KdTree(Eigen::DenseBase<TDerivedP>
const& P,
Index maxPointsInLeaf = 8);
103 template <
class TDerivedP>
113 template <
class FVisit>
120 std::vector<KdTreeNode>
const&
Nodes()
const {
return mNodes; }
152 std::vector<KdTreeNode> mNodes;
156template <
class TDerivedP>
157inline KdTree<Dims>::KdTree(Eigen::DenseBase<TDerivedP>
const& P,
Index maxPointsInLeaf)
163template <
class TDerivedP>
166 PBAT_PROFILE_NAMED_SCOPE(
"pbat.geometry.KdTree.Construct");
171 Index const nPoints = P.cols();
172 Scalar constexpr kEstimatedLeafOccupancy = 0.8;
173 auto const nEstimatedNodesPerLeaf =
174 (maxPointsInLeaf > 1) ?
176 std::ceil(kEstimatedLeafOccupancy *
static_cast<Scalar>(maxPointsInLeaf))) :
178 auto const nEstimatedLeafNodes =
179 (nPoints / nEstimatedNodesPerLeaf) + (nPoints % nEstimatedNodesPerLeaf != 0);
181#include "pbat/warning/Push.h"
182#include "pbat/warning/SignConversion.h"
183 mNodes.reserve(2 * nEstimatedLeafNodes - 1);
184 auto iota = std::views::iota(
Index{0}, nPoints);
185 mPermutation.resize(nPoints);
186 std::copy(iota.begin(), iota.end(), mPermutation.data());
197 Index constexpr root = 0;
199 mNodes.emplace_back(0, nPoints, KdTreeNode::kLeafNodeLeftChild);
200 while (not stack.IsEmpty())
202 auto const [aabb, nodeIdx, begin, n] = stack.Pop();
203 if (n <= maxPointsInLeaf)
207 Eigen::Index dimension{};
208 (aabb.max() - aabb.min()).maxCoeff(&dimension);
210 Index const halfn = n / 2;
212 mPermutation.data() + begin,
213 mPermutation.data() + begin + halfn,
214 mPermutation.data() + begin + n,
216 return P(dimension, lhs) < P(dimension, rhs);
219 mNodes[nodeIdx].c =
static_cast<Index>(mNodes.size());
221 Scalar const split = P(dimension, mPermutation[begin + halfn]);
223 laabb.max()(dimension) = split;
225 raabb.min()(dimension) = split;
227 mNodes.emplace_back(begin, halfn, KdTreeNode::kLeafNodeLeftChild);
228 mNodes.emplace_back(begin + halfn, n - halfn, KdTreeNode::kLeafNodeLeftChild);
230 stack.Push({laabb, mNodes[nodeIdx].Left(), begin, halfn});
231 stack.Push({raabb, mNodes[nodeIdx].Right(), begin + halfn, n - halfn});
233#include "pbat/warning/Pop.h"
237template <
class FVisit>
240 PBAT_PROFILE_NAMED_SCOPE(
"pbat.geometry.KdTree.DepthFirstSearch");
241#include "pbat/warning/Push.h"
242#include "pbat/warning/SignConversion.h"
244 [&](
Index node) {
return fVisit(node, mNodes[node]); },
245 [&]<
auto c>(
Index node) {
246 if constexpr (c == 0)
247 return mNodes[node].Left();
249 return mNodes[node].Right();
252#include "pbat/warning/Pop.h"
258 auto const& node = mNodes[
static_cast<std::size_t
>(nodeIdx)];
265 namespace vi = std::views;
266 auto indrng = mPermutation | vi::drop(node.
begin) | vi::take(node.
n);
Axis-aligned bounding box class.
Generic n-ary tree traversals.
Fixed-size stack implementation.
Definition Stack.h:26
Axis-aligned bounding box class.
Definition AxisAlignedBoundingBox.h:29
std::vector< KdTreeNode > const & Nodes() const
Returns the nodes of the k-D tree.
Definition KdTree.h:120
void DepthFirstSearch(FVisit visit, Index root=0) const
Depth-first search over the k-D tree.
Definition KdTree.h:238
auto PointsInNode(KdTreeNode const &node) const
Returns the points in a node.
Definition KdTree.h:263
IndexVectorX const & Permutation() const
Returns the permutation of the points in the k-D tree.
Definition KdTree.h:129
auto PointsInNode(Index const nodeIdx) const
Returns the points in a node.
Definition KdTree.h:256
void Construct(Eigen::DenseBase< TDerivedP > const &P, Index maxPointsInLeaf)
Construct a k-D tree from a set of points.
Definition KdTree.h:164
KdTree(Eigen::DenseBase< TDerivedP > const &P, Index maxPointsInLeaf=8)
Construct a k-D tree from a set of points.
Definition KdTree.h:157
Index constexpr Root() const
Returns the root node index.
Definition KdTree.h:146
Fixed-size stack implementation usable in both host and device code.
PBAT_HOST_DEVICE void TraverseNAryTreePseudoPreOrder(FVisit fVisit, FChild fChild, TIndex root=0)
Pre-order traversal over an n-ary tree starting from root.
Definition NAryTreeTraversal.h:65
Geometric queries, quantities and data structures.
Definition AabbKdTreeHierarchy.h:23
The main namespace of the library.
Definition Aliases.h:15
Eigen::Vector< Index, Eigen::Dynamic > IndexVectorX
Dynamic-size index vector type.
Definition Aliases.h:49
std::ptrdiff_t Index
Index type.
Definition Aliases.h:17
double Scalar
Scalar type.
Definition Aliases.h:18
Profiling utilities for the Physics-Based Animation Toolkit (PBAT)
Node of a KDTree.
Definition KdTree.h:31
bool IsInternal() const
Returns true if this node is an internal node, false otherwise.
Definition KdTree.h:47
Index begin
Index to first point encapsulated in this node's AABB in the permutation list.
Definition KdTree.h:33
bool IsLeaf() const
Returns true if this node is a leaf node, false otherwise.
Definition KdTree.h:42
Index n
Definition KdTree.h:34
auto Right() const
Returns right child node.
Definition KdTree.h:57
Index c
Definition KdTree.h:36
auto Left() const
Returns left child node.
Definition KdTree.h:52