11#ifndef PBAT_GEOMETRY_BOUNDINGVOLUMEHIERARCHY_H
12#define PBAT_GEOMETRY_BOUNDINGVOLUMEHIERARCHY_H
20#include <tbb/parallel_for.h>
35template <
class TDerived,
class TBoundingVolume,
class TPrimitive,
int Dims>
36class BoundingVolumeHierarchy
42 static auto constexpr kDims = Dims;
44 template <
class TDerived2,
class TBoundingVolume2,
class TPrimitive2,
int Dims2>
45 friend class BoundingVolumeHierarchy;
47 BoundingVolumeHierarchy() =
default;
79 template <
class FIntersectsBoundingVolume,
class FIntersectsPrimitive>
81 FIntersectsBoundingVolume&& ibv,
82 FIntersectsPrimitive&& ip,
83 std::size_t reserve = 50ULL)
const;
95 template <
class FDistanceToBoundingVolume,
class FDistanceToPrimitive>
98 const -> std::pair<std::vector<Index>, std::vector<Scalar>>;
115 return static_cast<TDerived const*
>(
this)->
Primitive(p);
134 template <
class RPrimitiveIndices>
137 return static_cast<TDerived const*
>(
this)->
BoundingVolumeOf(primitiveIndexRange);
165 class TBoundingVolume2,
168 class FBoundingVolumesOverlap,
169 class FPrimitivesOverlap,
170 class FPrimitivesAreAdjacent>
172 BoundingVolumeHierarchy<TDerived2, TBoundingVolume2, TPrimitive2, Dims2>
const& other,
173 FBoundingVolumesOverlap&& bvo,
174 FPrimitivesOverlap&& po,
175 FPrimitivesAreAdjacent&& PrimitivesAreAdjacent =
176 [](
PrimitiveType const& p1, TPrimitive2
const& p2) ->
bool {
return false; },
177 std::size_t reserve = 50ULL)
const;
183template <
class TDerived,
class TBoundingVolume,
class TPrimitive,
int Dims>
186 Index maxPointsInLeaf)
189 for (
auto p = 0; p < P.cols(); ++p)
193 mKdTree.Construct(P, maxPointsInLeaf);
194 std::size_t
const nBoundingVolumes =
mKdTree.Nodes().size();
196 tbb::parallel_for(std::size_t{0ULL}, nBoundingVolumes, [
this](std::size_t b) {
201template <
class TDerived,
class TBoundingVolume,
class TPrimitive,
int Dims>
206 std::size_t
const bvIdxStl =
static_cast<std::size_t
>(bvIdx);
210template <
class TDerived,
class TBoundingVolume,
class TPrimitive,
int Dims>
213 auto const& nodes =
mKdTree.Nodes();
214 tbb::parallel_for(std::size_t{0ULL}, nodes.size(), [&](std::size_t bvIdx) {
220template <
class TDerived,
class TBoundingVolume,
class TPrimitive,
int Dims>
221template <
class FIntersectsBoundingVolume,
class FIntersectsPrimitive>
222inline std::vector<Index>
224 FIntersectsBoundingVolume&& ibv,
225 FIntersectsPrimitive&& ip,
226 std::size_t reserve)
const
228 std::vector<Index> intersectingPrimitives{};
229 intersectingPrimitives.reserve(reserve);
234 for (
auto const idx :
mKdTree.PointsInNode(node))
236 bool const bIntersects = ip(
Primitive(idx));
239 intersectingPrimitives.push_back(idx);
246 auto const bvIdxStl =
static_cast<std::size_t
>(bvIdx);
253 return intersectingPrimitives;
256template <
class TDerived,
class TBoundingVolume,
class TPrimitive,
int Dims>
257template <
class FDistanceToBoundingVolume,
class FDistanceToPrimitive>
260 FDistanceToBoundingVolume&& db,
261 FDistanceToPrimitive&& dp,
262 std::size_t K)
const -> std::pair<std::vector<Index>, std::vector<Scalar>>
264 std::vector<Index> neighbours{};
265 std::vector<Scalar> distances{};
266 neighbours.reserve(K);
267 distances.reserve(K);
269 enum class EQueueItem { Volume,
Primitive };
278 auto const MakeVolumeQueueItem = [&](
Index bvIdx) {
279 auto const bvIdxStl =
static_cast<std::size_t
>(bvIdx);
282 QueueItem
const q{EQueueItem::Volume, bvIdx, d};
285 auto const MakePrimitiveQueueItem = [&](
Index pIdx) {
288 QueueItem
const q{EQueueItem::Primitive, pIdx, d};
292 auto const Greater = [](QueueItem
const& q1, QueueItem
const& q2) {
295 using PriorityQueue = std::priority_queue<QueueItem, std::vector<QueueItem>,
decltype(Greater)>;
296 PriorityQueue queue{Greater};
297 queue.push(MakeVolumeQueueItem(0));
298 auto const& nodes =
mKdTree.Nodes();
299 while (!queue.empty())
301 QueueItem
const q = queue.top();
303 if (q.type == EQueueItem::Volume)
305 auto const qIdxStl =
static_cast<std::size_t
>(q.idx);
309 for (
auto const pIdx :
mKdTree.PointsInNode(node))
311 queue.push(MakePrimitiveQueueItem(pIdx));
316 queue.push(MakeVolumeQueueItem(node.
Left()));
317 queue.push(MakeVolumeQueueItem(node.
Right()));
325 neighbours.push_back(q.idx);
326 distances.push_back(q.d);
329 if (neighbours.size() == K)
332 return {neighbours, distances};
335template <
class TDerived,
class TBoundingVolume,
class TPrimitive,
int Dims>
338 class TBoundingVolume2,
341 class FBoundingVolumesOverlap,
342 class FPrimitivesOverlap,
343 class FPrimitivesAreAdjacent>
346 BoundingVolumeHierarchy<TDerived2, TBoundingVolume2, TPrimitive2, Dims2>
const& other,
347 FBoundingVolumesOverlap&& bvo,
348 FPrimitivesOverlap&& po,
349 FPrimitivesAreAdjacent&& pa,
350 std::size_t reserve)
const
352 using BoundingVolumeType2 = TBoundingVolume2;
353 std::vector<Index> overlaps{};
354 overlaps.reserve(reserve * 2);
355 auto const& nodes1 =
mKdTree.Nodes();
358 using PrimitivePairType = std::pair<Index, Index>;
359 std::stack<PrimitivePairType> stack{};
361 while (!stack.empty())
363 auto const [n1, n2] = stack.top();
364 auto const n1Stl =
static_cast<std::size_t
>(n1);
365 auto const n2Stl =
static_cast<std::size_t
>(n2);
374 bool const bIsNode1Leaf = node1.
IsLeaf();
375 bool const bIsNode2Leaf = node2.
IsLeaf();
376 if (bIsNode1Leaf and bIsNode2Leaf)
378 for (
auto const p1 :
mKdTree.PointsInNode(node1))
389 overlaps.push_back(p1);
390 overlaps.push_back(p2);
395 else if (bIsNode1Leaf and not bIsNode2Leaf)
397 stack.push({n1, node2.
Left()});
398 stack.push({n1, node2.
Right()});
400 else if (not bIsNode1Leaf and bIsNode2Leaf)
402 stack.push({node1.
Left(), n2});
403 stack.push({node1.
Right(), n2});
407 auto const n1n = node1.
n;
408 auto const n2n = node2.
n;
411 stack.push({node1.
Left(), n2});
412 stack.push({node1.
Right(), n2});
416 stack.push({n1, node2.
Left()});
417 stack.push({n1, node2.
Right()});
This file contains the KdTree class.
KdTree< kDims > mKdTree
Definition BoundingVolumeHierarchy.h:180
void Construct(Index nPrimitives, Index maxPointsInLeaf=10)
Construct the BVH from a set of primitives.
Definition BoundingVolumeHierarchy.h:184
TPrimitive PrimitiveType
Type of primitives.
Definition BoundingVolumeHierarchy.h:41
auto BoundingVolumes() const -> std::vector< BoundingVolumeType > const &
Returns the bounding volumes of this BVH.
Definition BoundingVolumeHierarchy.h:59
auto PrimitivesInBoundingVolume(Index bvIdx) const
Returns the indices of the primitives contained in the bounding volume bvIdx.
Definition BoundingVolumeHierarchy.h:203
auto PrimitiveLocation(PrimitiveType const &primitive) const
Returns the location of the primitive.
Definition BoundingVolumeHierarchy.h:123
BoundingVolumeType BoundingVolumeOf(RPrimitiveIndices &&primitiveIndexRange) const
Returns the bounding volume of the primitives in the range [first, last)
Definition BoundingVolumeHierarchy.h:135
std::vector< Index > PrimitivesIntersecting(FIntersectsBoundingVolume &&ibv, FIntersectsPrimitive &&ip, std::size_t reserve=50ULL) const
Returns the indices of the primitives intersecting the bounding volume bv.
Definition BoundingVolumeHierarchy.h:223
TBoundingVolume BoundingVolumeType
Type of bounding volumes.
Definition BoundingVolumeHierarchy.h:40
auto NearestPrimitivesTo(FDistanceToBoundingVolume &&db, FDistanceToPrimitive &&dp, std::size_t K) const -> std::pair< std::vector< Index >, std::vector< Scalar > >
Obtains the k nearest neighbours (primitives of this BVH)
Definition BoundingVolumeHierarchy.h:259
PrimitiveType Primitive(Index p) const
Returns the primitive at index p.
Definition BoundingVolumeHierarchy.h:113
void Update()
Update the bounding volumes of this BVH.
Definition BoundingVolumeHierarchy.h:211
IndexMatrixX OverlappingPrimitivesImpl(BoundingVolumeHierarchy< TDerived2, TBoundingVolume2, TPrimitive2, Dims2 > const &other, FBoundingVolumesOverlap &&bvo, FPrimitivesOverlap &&po, FPrimitivesAreAdjacent &&PrimitivesAreAdjacent=[](PrimitiveType const &p1, TPrimitive2 const &p2) -> bool { return false;}, std::size_t reserve=50ULL) const
Returns the indices of the primitives overlapping between this BVH and another BVH.
Definition BoundingVolumeHierarchy.h:345
std::vector< BoundingVolumeType > mBoundingVolumes
Definition BoundingVolumeHierarchy.h:179
TDerived DerivedType
Actual type.
Definition BoundingVolumeHierarchy.h:39
static auto constexpr kDims
Definition BoundingVolumeHierarchy.h:42
KDTree class.
Definition KdTree.h:66
std::vector< KdTreeNode > const & Nodes() const
Returns the nodes of the k-D tree.
Definition KdTree.h:120
auto PointsInNode(Index const nodeIdx) const
Returns the points in a node.
Definition KdTree.h:256
Eigen adaptors for ranges.
auto ToEigen(R &&r) -> Eigen::Map< Eigen::Vector< std::ranges::range_value_t< R >, Eigen::Dynamic > const >
Map a range of scalars to an eigen vector of such scalars.
Definition Eigen.h:28
Geometric queries, quantities and data structures.
Definition AabbKdTreeHierarchy.h:23
The main namespace of the library.
Definition Aliases.h:15
std::ptrdiff_t Index
Index type.
Definition Aliases.h:17
Eigen::Matrix< Index, Eigen::Dynamic, Eigen::Dynamic > IndexMatrixX
Dynamic-size index matrix type.
Definition Aliases.h:50
double Scalar
Scalar type.
Definition Aliases.h:18
Eigen::Matrix< Scalar, Rows, Cols > Matrix
Fixed-size matrix type.
Definition Aliases.h:31
Node of a KDTree.
Definition KdTree.h:31
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
auto Left() const
Returns left child node.
Definition KdTree.h:52