pure-cpp 1.0.0
A C++ physics simulation benchmark comparing performance with Python implementations
kdtree.hpp
Go to the documentation of this file.
1#ifndef KDTREE_HPP
2#define KDTREE_HPP
3
4/**
5 * \file kdtree.hpp
6 * \brief A k-d tree wrapper for broad-phase collision detection using
7 * nanoflann.
8 * \author Le Bars, Yoann
9 * \ingroup PhysicsAcceleration
10 *
11 * This file is part of the pure C++ benchmark.
12 */
13
14#include <nanoflann.hpp>
15
16#include "body.hpp"
17
18namespace Model {
19
20 /**
21 * \brief An adapter to allow nanoflann to work directly with our `Bodies`
22 * SoA container.
23 *
24 * Note: The method names in this class follow the `snake_case` convention
25 * required by the nanoflann library's adapter interface, rather than the
26 * project's standard `camelCase`.
27 * \ingroup PhysicsAcceleration
28 */
30 public:
31 /**
32 * \brief Construct a new Bodies Adaptor object.
33 * \param in_bodies The `Bodies` container.
34 */
35 explicit BodiesAdaptor(const Bodies& in_bodies) : bodies_(in_bodies) {}
36
37 /**
38 * \brief Returns the number of bodies (points) in the dataset.
39 * \return The number of bodies.
40 */
41 [[nodiscard]] inline std::size_t kdtree_get_point_count() const {
42 return bodies_.size();
43 }
44
45 /**
46 * \brief Returns the value of a single dimension of a point.
47 * \param idx The index of the point.
48 * \param dim The dimension (0 for x, 1 for y, 2 for z).
49 * \return The coordinate value.
50 */
51 [[nodiscard]] inline double kdtree_get_pt(const std::size_t idx,
52 const std::size_t dim) const {
53 return bodies_.x_[idx][dim];
54 }
55
56 /**
57 * \brief Optional bounding box calculation (not used here).
58 * \tparam BBOX The type of the bounding box.
59 * \return Always false.
60 */
61 template <class BBOX>
62 bool kdtree_get_bbox(BBOX& /*bb*/) const {
63 return false;
64 }
65
66 private:
67 /// \brief A const reference to the bodies container.
69 };
70
71 /**
72 * \brief A k-d tree for fast nearest neighbour searches, specialized for
73 * our `Bodies` container.
74 */
75 class KDTree {
76 public:
77 /// \brief The specific KD-Tree type using our adapter.
78 using TreeType = nanoflann::KDTreeSingleIndexAdaptor<
79 nanoflann::L2_Simple_Adaptor<double, BodiesAdaptor>,
80 BodiesAdaptor, // NOLINT
81 3 /* dimensionality */, std::size_t /* index type */>;
82
83 /**
84 * \brief Construct a new KDTree object and build the index.
85 * \param in_bodies The `Bodies` container to build the tree from.
86 */
87 explicit KDTree(const Bodies& in_bodies)
88 : adaptor_(in_bodies),
89 tree_(3 /* dimensionality */, adaptor_,
90 // Set leaf_max_size to 10. This is a good balance for
91 // performance.
92 nanoflann::KDTreeSingleIndexAdaptorParams(10)) {}
93
94 /**
95 * \brief Rebuilds the internal k-d tree index.
96 * Calling this on an existing tree reuses nanoflann's internal memory
97 * pool.
98 */
99 void buildIndex() { tree_.buildIndex(); }
100
101 /**
102 * \brief Finds all bodies within a given radius of a query point.
103 *
104 * \param query_point The centre point of the search.
105 * \param search_radius The radius of the search sphere.
106 * \param out_results A vector to store the results (pairs of index and
107 * squared distance).
108 * \return The number of neighbours found.
109 */
110 template <typename VectorOfPairs>
111 std::size_t radiusSearch(const double* query_point,
112 const double search_radius,
113 VectorOfPairs& out_results) {
114/* The SearchParameters class was renamed from SearchParams in v1.5.0.
115 We check for the legacy version macro to decide which API to use. */
116#if defined(NANOFLANN_VERSION) && NANOFLANN_VERSION < 0x150
117 // Use the legacy API for nanoflann < 1.5.0
118 return tree_.radiusSearch(query_point,
119 search_radius * search_radius,
120 out_results, nanoflann::SearchParams());
121#else
122 // Use the modern API for nanoflann >= 1.5.0
123 return tree_.radiusSearch(
124 query_point, search_radius * search_radius, out_results,
125 nanoflann::SearchParameters());
126#endif
127 }
128
129 private:
130 /// \brief The adapter that lets nanoflann access our data.
132 /// \brief The underlying nanoflann k-d tree index.
134 };
135
136} // namespace Model
137
138#endif // KDTREE_HPP
SoA container for simulation bodies and proxies for AoS-like access.
An adapter to allow nanoflann to work directly with our Bodies SoA container.
Definition: kdtree.hpp:29
bool kdtree_get_bbox(BBOX &) const
Optional bounding box calculation (not used here).
Definition: kdtree.hpp:62
BodiesAdaptor(const Bodies &in_bodies)
Construct a new Bodies Adaptor object.
Definition: kdtree.hpp:35
double kdtree_get_pt(const std::size_t idx, const std::size_t dim) const
Returns the value of a single dimension of a point.
Definition: kdtree.hpp:51
const Bodies & bodies_
A const reference to the bodies container.
Definition: kdtree.hpp:68
std::size_t kdtree_get_point_count() const
Returns the number of bodies (points) in the dataset.
Definition: kdtree.hpp:41
Structure-of-Arrays (SoA) container for all bodies in the simulation.
Definition: body.hpp:275
std::size_t size() const
Get number of bodies in the simulation.
Definition: body.hpp:370
std::vector< Vector3d > x_
Bodies' positions.
Definition: body.hpp:430
A k-d tree for fast nearest neighbour searches, specialized for our Bodies container.
Definition: kdtree.hpp:75
BodiesAdaptor adaptor_
The adapter that lets nanoflann access our data.
Definition: kdtree.hpp:131
nanoflann::KDTreeSingleIndexAdaptor< nanoflann::L2_Simple_Adaptor< double, BodiesAdaptor >, BodiesAdaptor, 3, std::size_t > TreeType
The specific KD-Tree type using our adapter.
Definition: kdtree.hpp:81
TreeType tree_
The underlying nanoflann k-d tree index.
Definition: kdtree.hpp:133
std::size_t radiusSearch(const double *query_point, const double search_radius, VectorOfPairs &out_results)
Finds all bodies within a given radius of a query point.
Definition: kdtree.hpp:111
KDTree(const Bodies &in_bodies)
Construct a new KDTree object and build the index.
Definition: kdtree.hpp:87
void buildIndex()
Rebuilds the internal k-d tree index. Calling this on an existing tree reuses nanoflann's internal me...
Definition: kdtree.hpp:99