Ponca  aa50bfdf187919869239c5b44b748842569114c1
Point Cloud Analysis library
Loading...
Searching...
No Matches
kdTree.h
1/*
2 This Source Code Form is subject to the terms of the Mozilla Public
3 License, v. 2.0. If a copy of the MPL was not distributed with this
4 file, You can obtain one at http://mozilla.org/MPL/2.0/.
5*/
6
7#pragma once
8
9#include "./kdTreeTraits.h"
10
11#include <iostream>
12#include <memory>
13#include <numeric>
14#include <optional>
15#include <type_traits>
16#include <utility>
17#include <vector>
18
19#include <Eigen/Geometry> // aabb
20
21#include "../../Common/Assert.h"
22
23#include "Query/kdTreeNearestQueries.h"
24#include "Query/kdTreeKNearestQueries.h"
25#include "Query/kdTreeRangeQueries.h"
26
27namespace Ponca {
28template <typename Traits> class KdTreeBase;
29template <typename Traits> class KdTreeDenseBase;
30template <typename Traits> class KdTreeSparseBase;
31
44#ifdef PARSED_WITH_DOXYGEN
46template <typename DataPoint>
47struct KdTree : public Ponca::KdTreeBase<KdTreeDefaultTraits<DataPoint>>{};
49#else
50template <typename DataPoint>
51using KdTree = KdTreeBase<KdTreeDefaultTraits<DataPoint>>; // prefer alias to avoid redefining methods
52#endif
53
54
63#ifdef PARSED_WITH_DOXYGEN
65template <typename DataPoint>
66struct KdTreeDense : public Ponca::KdTreeDenseBase<KdTreeDefaultTraits<DataPoint>>{};
68#else
69template <typename DataPoint>
70using KdTreeDense = KdTreeDenseBase<KdTreeDefaultTraits<DataPoint>>; // prefer alias to avoid redefining methods
71#endif
72
81#ifdef PARSED_WITH_DOXYGEN
83template <typename DataPoint>
84struct KdTreeSparse : Ponca::KdTreeSparseBase<KdTreeDefaultTraits<DataPoint>>{};
86#else
87template <typename DataPoint>
89#endif
90
102template <typename Traits>
104{
105public:
106 using DataPoint = typename Traits::DataPoint;
107 using IndexType = typename Traits::IndexType;
108 using LeafSizeType = typename Traits::LeafSizeType;
109 using PointContainer = typename Traits::PointContainer;
110 using IndexContainer = typename Traits::IndexContainer;
111 using NodeIndexType = typename Traits::NodeIndexType;
112 using NodeType = typename Traits::NodeType;
113 using NodeContainer = typename Traits::NodeContainer;
114
115 using Scalar = typename DataPoint::Scalar;
116 using VectorType = typename DataPoint::VectorType;
117 using AabbType = typename NodeType::AabbType;
118
120 static constexpr std::size_t MAX_NODE_COUNT = NodeType::MAX_COUNT;
122 static constexpr std::size_t MAX_POINT_COUNT = std::size_t(2) << sizeof(IndexType)*8;
123
125 static constexpr int MAX_DEPTH = Traits::MAX_DEPTH;
126
127 static constexpr bool SUPPORTS_SUBSAMPLING = false;
128
129 static_assert(std::is_same<typename PointContainer::value_type, DataPoint>::value,
130 "PointContainer must contain DataPoints");
131
132 // Queries use a value of -1 for invalid indices
133 static_assert(std::is_signed<IndexType>::value, "Index type must be signed");
134
135 static_assert(std::is_same<typename IndexContainer::value_type, IndexType>::value, "Index type mismatch");
136 static_assert(std::is_same<typename NodeContainer::value_type, NodeType>::value, "Node type mismatch");
137
138 static_assert(MAX_DEPTH > 0, "Max depth must be strictly positive");
139
140 // Construction ------------------------------------------------------------
141public:
147 template<typename PointUserContainer, typename Converter>
148 inline void build(PointUserContainer&& points, Converter c);
149
152 {
153 template <typename Input>
154 inline void operator()(Input&& i, PointContainer& o)
155 {
156 using InputContainer = typename std::remove_reference<Input>::type;
157 if constexpr (std::is_same<InputContainer, PointContainer>::value)
158 o = std::forward<Input>(i); // Either move or copy
159 else
160 std::transform(i.cbegin(), i.cend(), std::back_inserter(o),
161 [](const typename InputContainer::value_type &p) -> DataPoint { return DataPoint(p); });
162 }
163 };
164
168 template<typename PointUserContainer>
169 inline void build(PointUserContainer&& points)
170 {
171 build(std::forward<PointUserContainer>(points), DefaultConverter());
172 }
173
175 inline void clear();
176
177 // Accessors ---------------------------------------------------------------
178public:
179 inline NodeIndexType node_count() const
180 {
181 return m_nodes.size();
182 }
183
184 inline IndexType sample_count() const
185 {
186 return (IndexType)m_indices.size();
187 }
188
189 inline IndexType point_count() const
190 {
191 return (IndexType)m_points.size();
192 }
193
194 inline NodeIndexType leaf_count() const
195 {
196 return m_leaf_count;
197 }
198
199 inline PointContainer& points()
200 {
201 return m_points;
202 };
203
204 inline const PointContainer& points() const
205 {
206 return m_points;
207 };
208
209 inline const NodeContainer& nodes() const
210 {
211 return m_nodes;
212 }
213
214 inline const IndexContainer& samples() const
215 {
216 return m_indices;
217 }
218
219 // Parameters --------------------------------------------------------------
220public:
223 {
224 return m_min_cell_size;
225 }
226
229 {
230 PONCA_DEBUG_ASSERT(min_cell_size > 0);
232 }
233
234 // Index mapping -----------------------------------------------------------
235public:
237 inline IndexType pointFromSample(IndexType sample_index) const
238 {
239 return m_indices[sample_index];
240 }
241
246 {
247 return m_points[pointFromSample(sample_index)];
248 }
249
253 inline const DataPoint& pointDataFromSample(IndexType sample_index) const
254 {
255 return m_points[pointFromSample(sample_index)];
256 }
257
258 // Query -------------------------------------------------------------------
259public :
260 KdTreeKNearestPointQuery<Traits> k_nearest_neighbors(const VectorType& point, IndexType k) const
261 {
262 return KdTreeKNearestPointQuery<Traits>(this, k, point);
263 }
264
265 KdTreeKNearestIndexQuery<Traits> k_nearest_neighbors(IndexType index, IndexType k) const
266 {
267 return KdTreeKNearestIndexQuery<Traits>(this, k, index);
268 }
269
270 KdTreeNearestPointQuery<Traits> nearest_neighbor(const VectorType& point) const
271 {
272 return KdTreeNearestPointQuery<Traits>(this, point);
273 }
274
275 KdTreeNearestIndexQuery<Traits> nearest_neighbor(IndexType index) const
276 {
277 return KdTreeNearestIndexQuery<Traits>(this, index);
278 }
279
280 KdTreeRangePointQuery<Traits> range_neighbors(const VectorType& point, Scalar r) const
281 {
282 return KdTreeRangePointQuery<Traits>(this, r, point);
283 }
284
285 KdTreeRangeIndexQuery<Traits> range_neighbors(IndexType index, Scalar r) const
286 {
287 return KdTreeRangeIndexQuery<Traits>(this, r, index);
288 }
289
290 // Utilities ---------------------------------------------------------------
291public:
292 inline bool valid() const;
293 inline void print(std::ostream& os, bool verbose = false) const;
294
295 // Data --------------------------------------------------------------------
296protected:
297 PointContainer m_points;
298 NodeContainer m_nodes;
299 IndexContainer m_indices;
300
303
304 // Internal ----------------------------------------------------------------
305protected:
306 inline KdTreeBase() = default;
307
315 template<typename PointUserContainer, typename IndexUserContainer, typename Converter>
316 inline void buildWithSampling(PointUserContainer&& points,
317 IndexUserContainer sampling,
318 Converter c);
319
325 template<typename PointUserContainer, typename IndexUserContainer>
326 inline void buildWithSampling(PointUserContainer&& points,
327 IndexUserContainer sampling)
328 {
329 buildWithSampling(std::forward<PointUserContainer>(points), std::move(sampling), DefaultConverter());
330 }
331
332private:
333 inline void build_rec(NodeIndexType node_id, IndexType start, IndexType end, int level);
334 inline IndexType partition(IndexType start, IndexType end, int dim, Scalar value);
335};
336
351template <typename Traits>
352class KdTreeDenseBase : public KdTreeBase<Traits>
353{
354private:
355 using Base = KdTreeBase<Traits>;
356
357public:
360 KdTreeDenseBase() = default;
361
363 template<typename PointUserContainer>
364 inline explicit KdTreeDenseBase(PointUserContainer&& points)
365 : Base()
366 {
367 this->build(std::forward<PointUserContainer>(points));
368 }
369};
370
385template <typename Traits>
386class KdTreeSparseBase : public KdTreeBase<Traits>
387{
388private:
389 using Base = KdTreeBase<Traits>;
390
391public:
392 static constexpr bool SUPPORTS_SUBSAMPLING = false;
393
396 KdTreeSparseBase() = default;
397
399 template<typename PointUserContainer>
400 inline explicit KdTreeSparseBase(PointUserContainer&& points)
401 : Base()
402 {
403 this->build(std::forward<PointUserContainer>(points));
404 }
405
411 template<typename PointUserContainer, typename IndexUserContainer>
412 inline KdTreeSparseBase(PointUserContainer&& points, IndexUserContainer sampling)
413 : Base()
414 {
415 this->buildWithSampling(std::forward<PointUserContainer>(points), std::move(sampling));
416 }
417
419};
420
421#include "./kdTree.hpp"
422} // namespace Ponca
423
424template <typename Traits>
425std::ostream& operator<<(std::ostream& os, const Ponca::KdTreeBase<Traits>& kdtree)
426{
427 kdtree.print(os);
428 return os;
429}
[KdTreeSparse type definition]
Definition: kdTree.h:104
typename Traits::DataPoint DataPoint
DataPoint given by user via Traits.
Definition: kdTree.h:106
void set_min_cell_size(LeafSizeType min_cell_size)
Write leaf min size.
Definition: kdTree.h:228
typename DataPoint::Scalar Scalar
Scalar given by user via DataPoint.
Definition: kdTree.h:115
typename Traits::NodeType NodeType
Type of nodes used inside the KdTree.
Definition: kdTree.h:112
typename Traits::IndexType IndexType
Type used to index points into the PointContainer.
Definition: kdTree.h:107
LeafSizeType min_cell_size() const
Read leaf min size.
Definition: kdTree.h:222
void build(PointUserContainer &&points, Converter c)
Generate a tree from a custom contained type converted using the specified converter.
typename Traits::IndexContainer IndexContainer
Container for indices used inside the KdTree.
Definition: kdTree.h:110
static constexpr std::size_t MAX_POINT_COUNT
The maximum number of points that can be stored in the kd-tree.
Definition: kdTree.h:122
typename Traits::NodeContainer NodeContainer
Container for nodes used inside the KdTree.
Definition: kdTree.h:113
static constexpr std::size_t MAX_NODE_COUNT
The maximum number of nodes that the kd-tree can have.
Definition: kdTree.h:120
typename Traits::NodeIndexType NodeIndexType
Type used to index nodes into the NodeContainer.
Definition: kdTree.h:111
void build(PointUserContainer &&points)
Generate a tree from a custom contained type converted using DefaultConverter.
Definition: kdTree.h:169
typename Traits::PointContainer PointContainer
Container for DataPoint used inside the KdTree.
Definition: kdTree.h:109
NodeIndexType m_leaf_count
Number of leaves in the Kdtree (computed during construction)
Definition: kdTree.h:302
void clear()
Clear tree data.
Definition: kdTree.hpp:19
void buildWithSampling(PointUserContainer &&points, IndexUserContainer sampling)
Generate a tree sampled from a custom contained type converted using a KdTreeBase::DefaultConverter.
Definition: kdTree.h:326
static constexpr int MAX_DEPTH
The maximum depth of the kd-tree.
Definition: kdTree.h:125
const DataPoint & pointDataFromSample(IndexType sample_index) const
Return the DataPoint associated with the specified sample index.
Definition: kdTree.h:253
LeafSizeType m_min_cell_size
Minimal number of points per leaf.
Definition: kdTree.h:301
IndexType pointFromSample(IndexType sample_index) const
Return the point index associated with the specified sample index.
Definition: kdTree.h:237
typename NodeType::AabbType AabbType
Bounding box type given by user via NodeType.
Definition: kdTree.h:117
typename Traits::LeafSizeType LeafSizeType
Type used to store the size of leaf nodes.
Definition: kdTree.h:108
DataPoint & pointDataFromSample(IndexType sample_index)
Return the DataPoint associated with the specified sample index.
Definition: kdTree.h:245
typename DataPoint::VectorType VectorType
VectorType given by user via DataPoint.
Definition: kdTree.h:116
void buildWithSampling(PointUserContainer &&points, IndexUserContainer sampling, Converter c)
Generate a tree sampled from a custom contained type converted using a Converter
Customizable base class for dense KdTree datastructure.
Definition: kdTree.h:353
KdTreeDenseBase()=default
Default constructor creating an empty tree.
KdTreeDenseBase(PointUserContainer &&points)
Constructor generating a tree from a custom contained type converted using a KdTreeBase::DefaultConve...
Definition: kdTree.h:364
Customizable base class for KdTreeSparse datastructure.
Definition: kdTree.h:387
KdTreeSparseBase(PointUserContainer &&points, IndexUserContainer sampling)
Constructor generating a tree sampled from a custom contained type converted using a KdTreeBase::Defa...
Definition: kdTree.h:412
KdTreeSparseBase(PointUserContainer &&points)
Constructor generating a tree from a custom contained type converted using a KdTreeBase::DefaultConve...
Definition: kdTree.h:400
KdTreeSparseBase()=default
Default constructor creating an empty tree.
void buildWithSampling(PointUserContainer &&points, IndexUserContainer sampling, Converter c)
Generate a tree sampled from a custom contained type converted using a Converter
This Source Code Form is subject to the terms of the Mozilla Public License, v.
Convert a custom point container to the KdTree PointContainer using DataPoint default constructor.
Definition: kdTree.h:152
[KdTree type definition]
Definition: kdTree.h:66
[KdTreeDense type definition]
Definition: kdTree.h:84
Abstract KdTree type with KdTreeDefaultTraits.
Definition: kdTree.h:47