Skip to content

Commit ed08fbe

Browse files
committed
Document BoundingVolumeHierarchy
1 parent ae89b6a commit ed08fbe

File tree

1 file changed

+96
-33
lines changed

1 file changed

+96
-33
lines changed

source/pbat/geometry/BoundingVolumeHierarchy.h

Lines changed: 96 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1-
#ifndef PBAT_GEOMETRY_BOUNDING_VOLUME_HIERARCHY_H
2-
#define PBAT_GEOMETRY_BOUNDING_VOLUME_HIERARCHY_H
1+
/**
2+
* @file BoundingVolumeHierarchy.h
3+
* @author Quoc-Minh Ton-That ([email protected])
4+
* @brief Bounding volume hierarchy (BVH) implementation for spatial partitioning of primitives.
5+
* @date 2025-02-12
6+
*
7+
* @copyright Copyright (c) 2025
8+
*
9+
*/
10+
11+
#ifndef PBAT_GEOMETRY_BOUNDINGVOLUMEHIERARCHY_H
12+
#define PBAT_GEOMETRY_BOUNDINGVOLUMEHIERARCHY_H
313

414
#include "KdTree.h"
515

@@ -18,44 +28,52 @@ namespace geometry {
1828
* @brief CRTP base class for BVHs.
1929
*
2030
* @tparam TDerived Type of the child class (the concrete BVH implementation)
21-
* @tparam TPrimitive Type of primitives stored in the BVH
2231
* @tparam TBoundingVolume Type of bounding volumes used in the BVH tree
32+
* @tparam TPrimitive Type of primitives stored in the BVH
2333
* @tparam Dims Embedding dimensionality
2434
*/
2535
template <class TDerived, class TBoundingVolume, class TPrimitive, int Dims>
2636
class BoundingVolumeHierarchy
2737
{
2838
public:
29-
using DerivedType = TDerived;
30-
using BoundingVolumeType = TBoundingVolume;
31-
using PrimitiveType = TPrimitive;
32-
static auto constexpr kDims = Dims;
39+
using DerivedType = TDerived; ///< Actual type
40+
using BoundingVolumeType = TBoundingVolume; ///< Type of bounding volumes
41+
using PrimitiveType = TPrimitive; ///< Type of primitives
42+
static auto constexpr kDims = Dims; ///< Embedding dimensionality
3343

3444
template <class TDerived2, class TBoundingVolume2, class TPrimitive2, int Dims2>
3545
friend class BoundingVolumeHierarchy;
3646

3747
BoundingVolumeHierarchy() = default;
3848

3949
/**
40-
* @brief
41-
* @param maxPointsInLeaf
50+
* @brief Construct the BVH from a set of primitives
51+
* @param nPrimitives Number of primitives
52+
* @param maxPointsInLeaf Maximum number of primitives in a leaf node
4253
*/
4354
void Construct(std::size_t nPrimitives, std::size_t maxPointsInLeaf = 10u);
4455
/**
45-
* @brief
46-
* @return
56+
* @brief Returns the bounding volumes of this BVH
57+
* @return Bounding volumes
4758
*/
48-
std::vector<BoundingVolumeType> const& BoundingVolumes() const { return mBoundingVolumes; }
59+
auto BoundingVolumes() const -> std::vector<BoundingVolumeType> const&
60+
{
61+
return mBoundingVolumes;
62+
}
4963
/**
5064
* @brief Returns the indices of the primitives contained in the bounding volume bvIdx
51-
* @param bvIdx
52-
* @return
65+
* @param bvIdx Index of the bounding volume
66+
* @return Range of indices of the primitives
5367
*/
5468
auto PrimitivesInBoundingVolume(Index bvIdx) const;
5569
/**
56-
* @brief
70+
* @brief Returns the indices of the primitives intersecting the bounding volume bv
71+
* @tparam FIntersectsBoundingVolume Callable with signature `bool pred(BoundingVolume const&)`
72+
* @tparam FIntersectsPrimitive Callable with signature `bool pred(Primitive const&)`
73+
* primitive `p` is intersected.
5774
* @param ibv Predicate pred(bv) evaluating to true if the bounding volume bv is intersected.
5875
* @param ip Predicate pred(p) evaluating to true if the primitive p is intersected.
76+
* @param reserve Estimated number of intersecting primitives to reserve in memory
5977
* @return
6078
*/
6179
template <class FIntersectsBoundingVolume, class FIntersectsPrimitive>
@@ -65,38 +83,83 @@ class BoundingVolumeHierarchy
6583
std::size_t reserve = 50ULL) const;
6684
/**
6785
* @brief Obtains the k nearest neighbours (primitives of this BVH)
68-
* @tparam T
86+
* @tparam FDistanceToBoundingVolume Callable with signature `Scalar pred(BoundingVolume
87+
* const&)`
88+
* @tparam FDistanceToPrimitive Callable with signature `Scalar pred(Primitive const&)`
6989
* @param db Distance function d(b) between bounding volume b and user-owned shape
7090
* @param dp Distance function d(p) between primitive p and user-owned shape
7191
* @param K Number of nearest neighbours to query
72-
* @return
92+
* @return Pair of vectors containing the indices of the nearest primitives and their
93+
* distances
7394
*/
7495
template <class FDistanceToBoundingVolume, class FDistanceToPrimitive>
75-
std::pair<std::vector<Index>, std::vector<Scalar>>
96+
auto
7697
NearestPrimitivesTo(FDistanceToBoundingVolume&& db, FDistanceToPrimitive&& dp, std::size_t K)
77-
const;
98+
const -> std::pair<std::vector<Index>, std::vector<Scalar>>;
7899

79100
/**
80101
* @brief Update the bounding volumes of this BVH
81102
*/
82103
void Update();
83104

84105
// Static virtual functions (CRTP)
106+
107+
/**
108+
* @brief Returns the primitive at index p
109+
* @note This function must be implemented by the derived class
110+
* @param p Index of the primitive
111+
* @return Primitive at index p
112+
*/
85113
PrimitiveType Primitive(Index p) const
86114
{
87115
return static_cast<TDerived const*>(this)->Primitive(p);
88116
}
117+
/**
118+
* @brief Returns the location of the primitive
119+
* @note This function must be implemented by the derived class
120+
* @param primitive Primitive
121+
* @return Location of the primitive
122+
*/
89123
auto PrimitiveLocation(PrimitiveType const& primitive) const
90124
{
91125
return static_cast<TDerived const*>(this)->PrimitiveLocation(primitive);
92126
}
127+
/**
128+
* @brief Returns the bounding volume of the primitives in the range [first, last)
129+
* @note This function must be implemented by the derived class
130+
* @tparam RPrimitiveIndices Range of primitive indices
131+
* @param primitiveIndexRange Range of primitive indices
132+
* @return Bounding volume of the primitives
133+
*/
93134
template <class RPrimitiveIndices>
94135
BoundingVolumeType BoundingVolumeOf(RPrimitiveIndices&& primitiveIndexRange) const
95136
{
96137
return static_cast<TDerived const*>(this)->BoundingVolumeOf(primitiveIndexRange);
97138
}
98139

99140
protected:
141+
/**
142+
* @brief Returns the indices of the primitives overlapping between this BVH and another BVH
143+
* @tparam TDerived2 Type of the other BVH
144+
* @tparam TBoundingVolume2 Type of bounding volumes of the other BVH
145+
* @tparam TPrimitive2 Type of primitives of the other BVH
146+
* @tparam FBoundingVolumesOverlap Callable with signature `bool pred(BoundingVolume const&,
147+
* BoundingVolume2 const&)`
148+
* @tparam FPrimitivesOverlap Callable with signature `bool pred(Primitive const&, Primitive2
149+
* const&)`
150+
* @tparam FPrimitivesAreAdjacent Callable with signature `bool pred(Primitive const&,
151+
* Primitive2 const&)`
152+
* @tparam Dims2 Embedding dimensionality of the other BVH
153+
* @param other Other BVH
154+
* @param bvo Predicate pred(bv1, bv2) evaluating to true if the bounding volumes bv1 and bv2
155+
* overlap
156+
* @param po Predicate pred(p1, p2) evaluating to true if the primitives p1 and p2 overlap
157+
* @param PrimitivesAreAdjacent Predicate pred(p1, p2) evaluating to true if the primitives p1
158+
* and p2 are adjacent
159+
* @param reserve Estimated number of overlapping primitives to reserve in memory
160+
* @return `2 x |# overlaps|` matrix of overlapping primitive indices
161+
*
162+
*/
100163
template <
101164
class TDerived2,
102165
class TBoundingVolume2,
@@ -113,8 +176,8 @@ class BoundingVolumeHierarchy
113176
[](PrimitiveType const& p1, TPrimitive2 const& p2) -> bool { return false; },
114177
std::size_t reserve = 50ULL) const;
115178

116-
std::vector<BoundingVolumeType> mBoundingVolumes;
117-
KdTree<kDims> mKdTree;
179+
std::vector<BoundingVolumeType> mBoundingVolumes; ///< Bounding volumes of the BVH
180+
KdTree<kDims> mKdTree; ///< K-d tree used to store the primitives and the BVH tree
118181
};
119182

120183
template <class TDerived, class TBoundingVolume, class TPrimitive, int Dims>
@@ -176,14 +239,14 @@ BoundingVolumeHierarchy<TDerived, TBoundingVolume, TPrimitive, Dims>::Primitives
176239
intersectingPrimitives.push_back(idx);
177240
}
178241
}
179-
return false; ///< Cannot visit deeper than a leaf node
242+
return false; // Cannot visit deeper than a leaf node
180243
}
181244
else
182245
{
183246
auto const bvIdxStl = static_cast<std::size_t>(bvIdx);
184247
BoundingVolumeType const& bv = mBoundingVolumes[bvIdxStl];
185-
return ibv(bv); ///< Visit deeper if this bounding volume overlaps with the
186-
///< queried shape
248+
return ibv(bv); // Visit deeper if this bounding volume overlaps with the
249+
// queried shape
187250
}
188251
});
189252

@@ -192,11 +255,11 @@ BoundingVolumeHierarchy<TDerived, TBoundingVolume, TPrimitive, Dims>::Primitives
192255

193256
template <class TDerived, class TBoundingVolume, class TPrimitive, int Dims>
194257
template <class FDistanceToBoundingVolume, class FDistanceToPrimitive>
195-
inline std::pair<std::vector<Index>, std::vector<Scalar>>
258+
inline auto
196259
BoundingVolumeHierarchy<TDerived, TBoundingVolume, TPrimitive, Dims>::NearestPrimitivesTo(
197260
FDistanceToBoundingVolume&& db,
198261
FDistanceToPrimitive&& dp,
199-
std::size_t K) const
262+
std::size_t K) const -> std::pair<std::vector<Index>, std::vector<Scalar>>
200263
{
201264
std::vector<Index> neighbours{};
202265
std::vector<Scalar> distances{};
@@ -206,11 +269,11 @@ BoundingVolumeHierarchy<TDerived, TBoundingVolume, TPrimitive, Dims>::NearestPri
206269
enum class EQueueItem { Volume, Primitive };
207270
struct QueueItem
208271
{
209-
EQueueItem type; ///< Indicates if this QueueItem holds a primitive or a volume
210-
Index idx; ///< Index of the primitive, if this QueueItem holds a primitive, or index
211-
///< of the node, if this QueueItem holds a volume (recall that node_idx =
212-
///< bv_idx + 1)
213-
Scalar d; ///< Distance from this QueueItem to p
272+
EQueueItem type; // Indicates if this QueueItem holds a primitive or a volume
273+
Index idx; // Index of the primitive, if this QueueItem holds a primitive, or index
274+
// of the node, if this QueueItem holds a volume (recall that node_idx =
275+
// bv_idx + 1)
276+
Scalar d; // Distance from this QueueItem to p
214277
};
215278
auto const MakeVolumeQueueItem = [&](Index bvIdx) {
216279
auto const bvIdxStl = static_cast<std::size_t>(bvIdx);
@@ -297,7 +360,7 @@ BoundingVolumeHierarchy<TDerived, TBoundingVolume, TPrimitive, Dims>::Overlappin
297360

298361
using PrimitivePairType = std::pair<Index, Index>;
299362
std::stack<PrimitivePairType> stack{};
300-
stack.push({0, 0}); ///< Root bounding volumes of *this and other
363+
stack.push({0, 0}); // Root bounding volumes of *this and other
301364
while (!stack.empty())
302365
{
303366
auto const [n1, n2] = stack.top();
@@ -370,4 +433,4 @@ BoundingVolumeHierarchy<TDerived, TBoundingVolume, TPrimitive, Dims>::Overlappin
370433
} // namespace geometry
371434
} // namespace pbat
372435

373-
#endif // PBAT_GEOMETRY_BOUNDING_VOLUME_HIERARCHY_H
436+
#endif // PBAT_GEOMETRY_BOUNDINGVOLUMEHIERARCHY_H

0 commit comments

Comments
 (0)