Main MRPT website > C++ reference for MRPT 1.9.9
KDTreeCapable.h
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 #ifndef KDTreeCapable_H
10 #define KDTreeCapable_H
11 
12 #include <mrpt/utils/utils_defs.h>
13 
14 // nanoflann library:
15 #include <mrpt/otherlibs/nanoflann/nanoflann.hpp>
17 #include <memory> // unique_ptr
18 
19 namespace mrpt
20 {
21 namespace math
22 {
23 /** \addtogroup kdtree_grp KD-Trees
24  * \ingroup mrpt_base_grp
25  * @{ */
26 
27 /** A generic adaptor class for providing Nearest Neighbor (NN) lookup via the
28  * `nanoflann` library.
29  * This makes use of the CRTP design pattern.
30  *
31  * Derived classes must be aware of the need to call
32  * "kdtree_mark_as_outdated()" when the data points
33  * change to mark the cached KD-tree (an "index") as invalid, and also
34  * implement the following interface
35  * (note that these are not virtual functions due to the usage of CRTP):
36  *
37  * \code
38  * // Must return the number of data points
39  * inline size_t kdtree_get_point_count() const { ... }
40  *
41  * // Returns the distance between the vector "p1[0:size-1]" and the data
42  * point with index "idx_p2" stored in the class:
43  * inline float kdtree_distance(const float *p1, const size_t idx_p2,size_t
44  * size) const { ... }
45  *
46  * // Returns the dim'th component of the idx'th point in the class:
47  * inline num_t kdtree_get_pt(const size_t idx, int dim) const { ... }
48  *
49  * // Optional bounding-box computation: return false to default to a standard
50  * bbox computation loop.
51  * // Return true if the BBOX was already computed by the class and returned
52  * in "bb" so it can be avoided to redo it again.
53  * // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3
54  * for point clouds)
55  * template <class BBOX>
56  * bool kdtree_get_bbox(BBOX &bb) const
57  * {
58  * bb[0].low = ...; bb[0].high = ...; // "x" limits
59  * return true;
60  * }
61  *
62  * \endcode
63  *
64  * The KD-tree index will be built on demand only upon call of any of the query
65  * methods provided by this class.
66  *
67  * Notice that there is only ONE internal cached KD-tree, so if a method to
68  * query a 2D point is called,
69  * then another method for 3D points, then again the 2D method, three KD-trees
70  * will be built. So, try
71  * to group all the calls for a given dimensionality together or build
72  * different class instances for
73  * queries of each dimensionality, etc.
74  *
75  * \sa See some of the derived classes for example implementations. See also
76  * the documentation of nanoflann
77  * \ingroup mrpt_base_grp
78  */
79 template <class Derived, typename num_t = float,
80  typename metric_t = nanoflann::L2_Simple_Adaptor<num_t, Derived>>
82 {
83  public:
84  // Types ---------------
86  // ---------------------
87 
88  /// Constructor
89  inline KDTreeCapable() : m_kdtree_is_uptodate(false) {}
90  /// CRTP helper method
91  inline const Derived& derived() const
92  {
93  return *static_cast<const Derived*>(this);
94  }
95  /// CRTP helper method
96  inline Derived& derived() { return *static_cast<Derived*>(this); }
98  {
100  /** Max points per leaf */
102  };
103 
104  /** Parameters to tune the ANN searches */
106 
107  /** @name Public utility methods to query the KD-tree
108  @{ */
109 
110  /** KD Tree-based search for the closest point (only ONE) to some given 2D
111  *coordinates.
112  * This method automatically build the "m_kdtree_data" structure when:
113  * - It is called for the first time
114  * - The map has changed
115  * - The KD-tree was build for 3D.
116  *
117  * \param x0 The X coordinate of the query.
118  * \param y0 The Y coordinate of the query.
119  * \param out_x The X coordinate of the found closest correspondence.
120  * \param out_y The Y coordinate of the found closest correspondence.
121  * \param out_dist_sqr The square distance between the query and the
122  *returned point.
123  *
124  * \return The index of the closest point in the map array.
125  * \sa kdTreeClosestPoint3D, kdTreeTwoClosestPoint2D
126  */
127  inline size_t kdTreeClosestPoint2D(
128  float x0, float y0, float& out_x, float& out_y,
129  float& out_dist_sqr) const
130  {
131  MRPT_START
132  rebuild_kdTree_2D(); // First: Create the 2D KD-Tree if required
134  THROW_EXCEPTION("There are no points in the KD-tree.")
135 
136  const size_t knn = 1; // Number of points to retrieve
137  size_t ret_index;
138  nanoflann::KNNResultSet<num_t> resultSet(knn);
139  resultSet.init(&ret_index, &out_dist_sqr);
140 
143  m_kdtree2d_data.index->findNeighbors(
144  resultSet, &m_kdtree2d_data.query_point[0],
145  nanoflann::SearchParams());
146 
147  // Copy output to user vars:
148  out_x = derived().kdtree_get_pt(ret_index, 0);
149  out_y = derived().kdtree_get_pt(ret_index, 1);
150 
151  return ret_index;
152  MRPT_END
153  }
154 
155  /// \overload
156  inline size_t kdTreeClosestPoint2D(
157  float x0, float y0, float& out_dist_sqr) const
158  {
159  MRPT_START
160  rebuild_kdTree_2D(); // First: Create the 2D KD-Tree if required
162  THROW_EXCEPTION("There are no points in the KD-tree.")
163 
164  const size_t knn = 1; // Number of points to retrieve
165  size_t ret_index;
166  nanoflann::KNNResultSet<num_t> resultSet(knn);
167  resultSet.init(&ret_index, &out_dist_sqr);
168 
171  m_kdtree2d_data.index->findNeighbors(
172  resultSet, &m_kdtree2d_data.query_point[0],
173  nanoflann::SearchParams());
174 
175  return ret_index;
176  MRPT_END
177  }
178 
179  /// \overload
180  inline size_t kdTreeClosestPoint2D(
181  const TPoint2D& p0, TPoint2D& pOut, float& outDistSqr) const
182  {
183  float dmy1, dmy2;
184  size_t res = kdTreeClosestPoint2D(
185  static_cast<float>(p0.x), static_cast<float>(p0.y), dmy1, dmy2,
186  outDistSqr);
187  pOut.x = dmy1;
188  pOut.y = dmy2;
189  return res;
190  }
191 
192  /** Like kdTreeClosestPoint2D, but just return the square error from some
193  * point to its closest neighbor.
194  */
195  inline float kdTreeClosestPoint2DsqrError(float x0, float y0) const
196  {
197  float closerx, closery, closer_dist;
198  kdTreeClosestPoint2D(x0, y0, closerx, closery, closer_dist);
199  return closer_dist;
200  }
201 
202  inline float kdTreeClosestPoint2DsqrError(const TPoint2D& p0) const
203  {
205  static_cast<float>(p0.x), static_cast<float>(p0.y));
206  }
207 
208  /** KD Tree-based search for the TWO closest point to some given 2D
209  *coordinates.
210  * This method automatically build the "m_kdtree_data" structure when:
211  * - It is called for the first time
212  * - The map has changed
213  * - The KD-tree was build for 3D.
214  *
215  * \param x0 The X coordinate of the query.
216  * \param y0 The Y coordinate of the query.
217  * \param out_x1 The X coordinate of the first correspondence.
218  * \param out_y1 The Y coordinate of the first correspondence.
219  * \param out_x2 The X coordinate of the second correspondence.
220  * \param out_y2 The Y coordinate of the second correspondence.
221  * \param out_dist_sqr1 The square distance between the query and the first
222  *returned point.
223  * \param out_dist_sqr2 The square distance between the query and the
224  *second returned point.
225  *
226  * \sa kdTreeClosestPoint2D
227  */
229  float x0, float y0, float& out_x1, float& out_y1, float& out_x2,
230  float& out_y2, float& out_dist_sqr1, float& out_dist_sqr2) const
231  {
232  MRPT_START
233  rebuild_kdTree_2D(); // First: Create the 2D KD-Tree if required
235  THROW_EXCEPTION("There are no points in the KD-tree.")
236 
237  const size_t knn = 2; // Number of points to retrieve
238  size_t ret_indexes[2];
239  float ret_sqdist[2];
240  nanoflann::KNNResultSet<num_t> resultSet(knn);
241  resultSet.init(&ret_indexes[0], &ret_sqdist[0]);
242 
245  m_kdtree2d_data.index->findNeighbors(
246  resultSet, &m_kdtree2d_data.query_point[0],
247  nanoflann::SearchParams());
248 
249  // Copy output to user vars:
250  out_x1 = derived().kdtree_get_pt(ret_indexes[0], 0);
251  out_y1 = derived().kdtree_get_pt(ret_indexes[0], 1);
252  out_dist_sqr1 = ret_sqdist[0];
253 
254  out_x2 = derived().kdtree_get_pt(ret_indexes[1], 0);
255  out_y2 = derived().kdtree_get_pt(ret_indexes[1], 1);
256  out_dist_sqr2 = ret_sqdist[0];
257 
258  MRPT_END
259  }
260 
262  const TPoint2D& p0, TPoint2D& pOut1, TPoint2D& pOut2,
263  float& outDistSqr1, float& outDistSqr2) const
264  {
265  float dmy1, dmy2, dmy3, dmy4;
267  p0.x, p0.y, dmy1, dmy2, dmy3, dmy4, outDistSqr1, outDistSqr2);
268  pOut1.x = static_cast<double>(dmy1);
269  pOut1.y = static_cast<double>(dmy2);
270  pOut2.x = static_cast<double>(dmy3);
271  pOut2.y = static_cast<double>(dmy4);
272  }
273 
274  /** KD Tree-based search for the N closest point to some given 2D
275  *coordinates.
276  * This method automatically build the "m_kdtree_data" structure when:
277  * - It is called for the first time
278  * - The map has changed
279  * - The KD-tree was build for 3D.
280  *
281  * \param x0 The X coordinate of the query.
282  * \param y0 The Y coordinate of the query.
283  * \param N The number of closest points to search.
284  * \param out_x The vector containing the X coordinates of the
285  *correspondences.
286  * \param out_y The vector containing the Y coordinates of the
287  *correspondences.
288  * \param out_dist_sqr The vector containing the square distance between
289  *the query and the returned points.
290  *
291  * \return The list of indices
292  * \sa kdTreeClosestPoint2D
293  * \sa kdTreeTwoClosestPoint2D
294  */
295  inline std::vector<size_t> kdTreeNClosestPoint2D(
296  float x0, float y0, size_t knn, std::vector<float>& out_x,
297  std::vector<float>& out_y, std::vector<float>& out_dist_sqr) const
298  {
299  MRPT_START
300  rebuild_kdTree_2D(); // First: Create the 2D KD-Tree if required
302  THROW_EXCEPTION("There are no points in the KD-tree.")
303 
304  std::vector<size_t> ret_indexes(knn);
305  out_x.resize(knn);
306  out_y.resize(knn);
307  out_dist_sqr.resize(knn);
308 
309  nanoflann::KNNResultSet<num_t> resultSet(knn);
310  resultSet.init(&ret_indexes[0], &out_dist_sqr[0]);
311 
314  m_kdtree2d_data.index->findNeighbors(
315  resultSet, &m_kdtree2d_data.query_point[0],
316  nanoflann::SearchParams());
317 
318  for (size_t i = 0; i < knn; i++)
319  {
320  out_x[i] = derived().kdtree_get_pt(ret_indexes[i], 0);
321  out_y[i] = derived().kdtree_get_pt(ret_indexes[i], 1);
322  }
323  return ret_indexes;
324  MRPT_END
325  }
326 
327  inline std::vector<size_t> kdTreeNClosestPoint2D(
328  const TPoint2D& p0, size_t N, std::vector<TPoint2D>& pOut,
329  std::vector<float>& outDistSqr) const
330  {
331  std::vector<float> dmy1, dmy2;
332  std::vector<size_t> res = kdTreeNClosestPoint2D(
333  static_cast<float>(p0.x), static_cast<float>(p0.y), N, dmy1, dmy2,
334  outDistSqr);
335  pOut.resize(dmy1.size());
336  for (size_t i = 0; i < dmy1.size(); i++)
337  {
338  pOut[i].x = static_cast<double>(dmy1[i]);
339  pOut[i].y = static_cast<double>(dmy2[i]);
340  }
341  return res;
342  }
343 
344  /** KD Tree-based search for the N closest point to some given 2D
345  *coordinates and returns their indexes.
346  * This method automatically build the "m_kdtree_data" structure when:
347  * - It is called for the first time
348  * - The map has changed
349  * - The KD-tree was build for 3D.
350  *
351  * \param x0 The X coordinate of the query.
352  * \param y0 The Y coordinate of the query.
353  * \param N The number of closest points to search.
354  * \param out_idx The indexes of the found closest correspondence.
355  * \param out_dist_sqr The square distance between the query and the
356  *returned point.
357  *
358  * \sa kdTreeClosestPoint2D
359  */
361  float x0, float y0, size_t knn, std::vector<size_t>& out_idx,
362  std::vector<float>& out_dist_sqr) const
363  {
364  MRPT_START
365  rebuild_kdTree_2D(); // First: Create the 2D KD-Tree if required
367  THROW_EXCEPTION("There are no points in the KD-tree.")
368 
369  out_idx.resize(knn);
370  out_dist_sqr.resize(knn);
371  nanoflann::KNNResultSet<num_t> resultSet(knn);
372  resultSet.init(&out_idx[0], &out_dist_sqr[0]);
373 
376  m_kdtree2d_data.index->findNeighbors(
377  resultSet, &m_kdtree2d_data.query_point[0],
378  nanoflann::SearchParams());
379  MRPT_END
380  }
381 
383  const TPoint2D& p0, size_t N, std::vector<size_t>& outIdx,
384  std::vector<float>& outDistSqr) const
385  {
387  static_cast<float>(p0.x), static_cast<float>(p0.y), N, outIdx,
388  outDistSqr);
389  }
390 
391  /** KD Tree-based search for the closest point (only ONE) to some given 3D
392  *coordinates.
393  * This method automatically build the "m_kdtree_data" structure when:
394  * - It is called for the first time
395  * - The map has changed
396  * - The KD-tree was build for 2D.
397  *
398  * \param x0 The X coordinate of the query.
399  * \param y0 The Y coordinate of the query.
400  * \param z0 The Z coordinate of the query.
401  * \param out_x The X coordinate of the found closest correspondence.
402  * \param out_y The Y coordinate of the found closest correspondence.
403  * \param out_z The Z coordinate of the found closest correspondence.
404  * \param out_dist_sqr The square distance between the query and the
405  *returned point.
406  *
407  * \return The index of the closest point in the map array.
408  * \sa kdTreeClosestPoint2D
409  */
410  inline size_t kdTreeClosestPoint3D(
411  float x0, float y0, float z0, float& out_x, float& out_y, float& out_z,
412  float& out_dist_sqr) const
413  {
414  MRPT_START
415  rebuild_kdTree_3D(); // First: Create the 3D KD-Tree if required
417  THROW_EXCEPTION("There are no points in the KD-tree.")
418 
419  const size_t knn = 1; // Number of points to retrieve
420  size_t ret_index;
421  nanoflann::KNNResultSet<num_t> resultSet(knn);
422  resultSet.init(&ret_index, &out_dist_sqr);
423 
427  m_kdtree3d_data.index->findNeighbors(
428  resultSet, &m_kdtree3d_data.query_point[0],
429  nanoflann::SearchParams());
430 
431  // Copy output to user vars:
432  out_x = derived().kdtree_get_pt(ret_index, 0);
433  out_y = derived().kdtree_get_pt(ret_index, 1);
434  out_z = derived().kdtree_get_pt(ret_index, 2);
435 
436  return ret_index;
437  MRPT_END
438  }
439 
440  /// \overload
441  inline size_t kdTreeClosestPoint3D(
442  float x0, float y0, float z0, float& out_dist_sqr) const
443  {
444  MRPT_START
445  rebuild_kdTree_3D(); // First: Create the 3D KD-Tree if required
447  THROW_EXCEPTION("There are no points in the KD-tree.")
448 
449  const size_t knn = 1; // Number of points to retrieve
450  size_t ret_index;
451  nanoflann::KNNResultSet<num_t> resultSet(knn);
452  resultSet.init(&ret_index, &out_dist_sqr);
453 
457  m_kdtree3d_data.index->findNeighbors(
458  resultSet, &m_kdtree3d_data.query_point[0],
459  nanoflann::SearchParams());
460 
461  return ret_index;
462  MRPT_END
463  }
464 
465  /// \overload
466  inline size_t kdTreeClosestPoint3D(
467  const TPoint3D& p0, TPoint3D& pOut, float& outDistSqr) const
468  {
469  float dmy1, dmy2, dmy3;
470  size_t res = kdTreeClosestPoint3D(
471  static_cast<float>(p0.x), static_cast<float>(p0.y),
472  static_cast<float>(p0.z), dmy1, dmy2, dmy3, outDistSqr);
473  pOut.x = static_cast<double>(dmy1);
474  pOut.y = static_cast<double>(dmy2);
475  pOut.z = static_cast<double>(dmy3);
476  return res;
477  }
478 
479  /** KD Tree-based search for the N closest points to some given 3D
480  *coordinates.
481  * This method automatically build the "m_kdtree_data" structure when:
482  * - It is called for the first time
483  * - The map has changed
484  * - The KD-tree was build for 2D.
485  *
486  * \param x0 The X coordinate of the query.
487  * \param y0 The Y coordinate of the query.
488  * \param z0 The Z coordinate of the query.
489  * \param N The number of closest points to search.
490  * \param out_x The vector containing the X coordinates of the
491  *correspondences.
492  * \param out_y The vector containing the Y coordinates of the
493  *correspondences.
494  * \param out_z The vector containing the Z coordinates of the
495  *correspondences.
496  * \param out_dist_sqr The vector containing the square distance between
497  *the query and the returned points.
498  *
499  * \sa kdTreeNClosestPoint2D
500  */
502  float x0, float y0, float z0, size_t knn, std::vector<float>& out_x,
503  std::vector<float>& out_y, std::vector<float>& out_z,
504  std::vector<float>& out_dist_sqr) const
505  {
506  MRPT_START
507  rebuild_kdTree_3D(); // First: Create the 3D KD-Tree if required
509  THROW_EXCEPTION("There are no points in the KD-tree.")
510 
511  std::vector<size_t> ret_indexes(knn);
512  out_x.resize(knn);
513  out_y.resize(knn);
514  out_z.resize(knn);
515  out_dist_sqr.resize(knn);
516 
517  nanoflann::KNNResultSet<num_t> resultSet(knn);
518  resultSet.init(&ret_indexes[0], &out_dist_sqr[0]);
519 
523  m_kdtree3d_data.index->findNeighbors(
524  resultSet, &m_kdtree3d_data.query_point[0],
525  nanoflann::SearchParams());
526 
527  for (size_t i = 0; i < knn; i++)
528  {
529  out_x[i] = derived().kdtree_get_pt(ret_indexes[i], 0);
530  out_y[i] = derived().kdtree_get_pt(ret_indexes[i], 1);
531  out_z[i] = derived().kdtree_get_pt(ret_indexes[i], 2);
532  }
533  MRPT_END
534  }
535 
536  /** KD Tree-based search for the N closest points to some given 3D
537  *coordinates.
538  * This method automatically build the "m_kdtree_data" structure when:
539  * - It is called for the first time
540  * - The map has changed
541  * - The KD-tree was build for 2D.
542  *
543  * \param x0 The X coordinate of the query.
544  * \param y0 The Y coordinate of the query.
545  * \param z0 The Z coordinate of the query.
546  * \param N The number of closest points to search.
547  * \param out_x The vector containing the X coordinates of the
548  *correspondences.
549  * \param out_y The vector containing the Y coordinates of the
550  *correspondences.
551  * \param out_z The vector containing the Z coordinates of the
552  *correspondences.
553  * \param out_idx The vector containing the indexes of the correspondences.
554  * \param out_dist_sqr The vector containing the square distance between
555  *the query and the returned points.
556  *
557  * \sa kdTreeNClosestPoint2D
558  */
560  float x0, float y0, float z0, size_t knn, std::vector<float>& out_x,
561  std::vector<float>& out_y, std::vector<float>& out_z,
562  std::vector<size_t>& out_idx, std::vector<float>& out_dist_sqr) const
563  {
564  MRPT_START
565  rebuild_kdTree_3D(); // First: Create the 3D KD-Tree if required
567  THROW_EXCEPTION("There are no points in the KD-tree.")
568 
569  out_x.resize(knn);
570  out_y.resize(knn);
571  out_z.resize(knn);
572  out_idx.resize(knn);
573  out_dist_sqr.resize(knn);
574 
575  nanoflann::KNNResultSet<num_t> resultSet(knn);
576  resultSet.init(&out_idx[0], &out_dist_sqr[0]);
577 
581  m_kdtree3d_data.index->findNeighbors(
582  resultSet, &m_kdtree3d_data.query_point[0],
583  nanoflann::SearchParams());
584 
585  for (size_t i = 0; i < knn; i++)
586  {
587  out_x[i] = derived().kdtree_get_pt(out_idx[i], 0);
588  out_y[i] = derived().kdtree_get_pt(out_idx[i], 1);
589  out_z[i] = derived().kdtree_get_pt(out_idx[i], 2);
590  }
591  MRPT_END
592  }
593 
595  const TPoint3D& p0, size_t N, std::vector<TPoint3D>& pOut,
596  std::vector<float>& outDistSqr) const
597  {
598  std::vector<float> dmy1, dmy2, dmy3;
600  static_cast<float>(p0.x), static_cast<float>(p0.y),
601  static_cast<float>(p0.z), N, dmy1, dmy2, dmy3, outDistSqr);
602  pOut.resize(dmy1.size());
603  for (size_t i = 0; i < dmy1.size(); i++)
604  {
605  pOut[i].x = static_cast<double>(dmy1[i]);
606  pOut[i].y = static_cast<double>(dmy2[i]);
607  pOut[i].z = static_cast<double>(dmy3[i]);
608  }
609  }
610 
611  /** KD Tree-based search for all the points within a given radius of some 3D
612  *point.
613  * This method automatically build the "m_kdtree_data" structure when:
614  * - It is called for the first time
615  * - The map has changed
616  * - The KD-tree was build for 2D.
617  *
618  * \param x0 The X coordinate of the query.
619  * \param y0 The Y coordinate of the query.
620  * \param z0 The Z coordinate of the query.
621  * \param maxRadiusSqr The square of the desired search radius.
622  * \param out_indices_dist The output list, with pairs of indeces/squared
623  *distances for the found correspondences.
624  * \return Number of found points.
625  *
626  * \sa kdTreeRadiusSearch2D, kdTreeNClosestPoint3DIdx
627  */
628  inline size_t kdTreeRadiusSearch3D(
629  const num_t x0, const num_t y0, const num_t z0,
630  const num_t maxRadiusSqr,
631  std::vector<std::pair<size_t, num_t>>& out_indices_dist) const
632  {
633  MRPT_START
634  rebuild_kdTree_3D(); // First: Create the 3D KD-Tree if required
635  out_indices_dist.clear();
636  if (m_kdtree3d_data.m_num_points != 0)
637  {
638  const num_t xyz[3] = {x0, y0, z0};
639  m_kdtree3d_data.index->radiusSearch(
640  &xyz[0], maxRadiusSqr, out_indices_dist,
641  nanoflann::SearchParams());
642  }
643  return out_indices_dist.size();
644  MRPT_END
645  }
646 
647  /** KD Tree-based search for all the points within a given radius of some 2D
648  *point.
649  * This method automatically build the "m_kdtree_data" structure when:
650  * - It is called for the first time
651  * - The map has changed
652  * - The KD-tree was build for 3D.
653  *
654  * \param x0 The X coordinate of the query.
655  * \param y0 The Y coordinate of the query.
656  * \param maxRadiusSqr The square of the desired search radius.
657  * \param out_indices_dist The output list, with pairs of indeces/squared
658  *distances for the found correspondences.
659  * \return Number of found points.
660  *
661  * \sa kdTreeRadiusSearch3D, kdTreeNClosestPoint2DIdx
662  */
663  inline size_t kdTreeRadiusSearch2D(
664  const num_t x0, const num_t y0, const num_t maxRadiusSqr,
665  std::vector<std::pair<size_t, num_t>>& out_indices_dist) const
666  {
667  MRPT_START
668  rebuild_kdTree_2D(); // First: Create the 2D KD-Tree if required
669  out_indices_dist.clear();
670  if (m_kdtree2d_data.m_num_points != 0)
671  {
672  const num_t xyz[2] = {x0, y0};
673  m_kdtree2d_data.index->radiusSearch(
674  &xyz[0], maxRadiusSqr, out_indices_dist,
675  nanoflann::SearchParams());
676  }
677  return out_indices_dist.size();
678  MRPT_END
679  }
680 
681  /** KD Tree-based search for the N closest point to some given 3D
682  *coordinates and returns their indexes.
683  * This method automatically build the "m_kdtree_data" structure when:
684  * - It is called for the first time
685  * - The map has changed
686  * - The KD-tree was build for 2D.
687  *
688  * \param x0 The X coordinate of the query.
689  * \param y0 The Y coordinate of the query.
690  * \param z0 The Z coordinate of the query.
691  * \param N The number of closest points to search.
692  * \param out_idx The indexes of the found closest correspondence.
693  * \param out_dist_sqr The square distance between the query and the
694  *returned point.
695  *
696  * \sa kdTreeClosestPoint2D, kdTreeRadiusSearch3D
697  */
699  float x0, float y0, float z0, size_t knn, std::vector<size_t>& out_idx,
700  std::vector<float>& out_dist_sqr) const
701  {
702  MRPT_START
703  rebuild_kdTree_3D(); // First: Create the 3D KD-Tree if required
705  THROW_EXCEPTION("There are no points in the KD-tree.")
706 
707  out_idx.resize(knn);
708  out_dist_sqr.resize(knn);
709  nanoflann::KNNResultSet<num_t> resultSet(knn);
710  resultSet.init(&out_idx[0], &out_dist_sqr[0]);
711 
715  m_kdtree3d_data.index->findNeighbors(
716  resultSet, &m_kdtree3d_data.query_point[0],
717  nanoflann::SearchParams());
718  MRPT_END
719  }
720 
722  const TPoint3D& p0, size_t N, std::vector<size_t>& outIdx,
723  std::vector<float>& outDistSqr) const
724  {
726  static_cast<float>(p0.x), static_cast<float>(p0.y),
727  static_cast<float>(p0.z), N, outIdx, outDistSqr);
728  }
729 
730  /* @} */
731 
732  protected:
733  /** To be called by child classes when KD tree data changes. */
734  inline void kdtree_mark_as_outdated() const
735  {
736  m_kdtree_is_uptodate = false;
737  }
738 
739  private:
740  /** Internal structure with the KD-tree representation (mainly used to avoid
741  * copying pointers with the = operator) */
742  template <int _DIM = -1>
744  {
745  inline TKDTreeDataHolder() {}
746  /** Copy constructor: It actually does NOT copy the kd-tree, a new
747  * object will be created if required! */
749  {
750  }
751  /** Copy operator: It actually does NOT copy the kd-tree, a new object
752  * will be created if required! */
753  inline TKDTreeDataHolder& operator=(const TKDTreeDataHolder& o) noexcept
754  {
755  if (&o != this) clear();
756  return *this;
757  }
758 
759  /** Free memory (if allocated) */
760  inline void clear() noexcept { index.reset(); }
761  typedef nanoflann::KDTreeSingleIndexAdaptor<metric_t, Derived, _DIM>
763 
764  /** nullptr or the up-to-date index */
765  std::unique_ptr<kdtree_index_t> index;
766 
767  std::vector<num_t> query_point;
768  /** Dimensionality. typ: 2,3 */
769  size_t m_dim = _DIM;
770  size_t m_num_points = 0;
771  };
772 
776  /** whether the KD tree needs to be rebuilt or not. */
777  mutable bool m_kdtree_is_uptodate;
778 
779  /// Rebuild, if needed the KD-tree for 2D (nDims=2), 3D (nDims=3), ...
780  /// asking the child class for the data points.
781  void rebuild_kdTree_2D() const
782  {
783  typedef typename TKDTreeDataHolder<2>::kdtree_index_t tree2d_t;
784 
786  {
790  }
791 
792  if (!m_kdtree2d_data.index)
793  {
794  // Erase previous tree:
796  // And build new index:
797  const size_t N = derived().kdtree_get_point_count();
800  m_kdtree2d_data.query_point.resize(2);
801  if (N)
802  {
803  m_kdtree2d_data.index.reset(
804  new tree2d_t(
805  2, derived(), nanoflann::KDTreeSingleIndexAdaptorParams(
807  m_kdtree2d_data.index->buildIndex();
808  }
809  m_kdtree_is_uptodate = true;
810  }
811  }
812 
813  /// Rebuild, if needed the KD-tree for 2D (nDims=2), 3D (nDims=3), ...
814  /// asking the child class for the data points.
815  void rebuild_kdTree_3D() const
816  {
817  typedef typename TKDTreeDataHolder<3>::kdtree_index_t tree3d_t;
818 
820  {
824  }
825 
826  if (!m_kdtree3d_data.index)
827  {
828  // Erase previous tree:
830  // And build new index:
831  const size_t N = derived().kdtree_get_point_count();
834  m_kdtree3d_data.query_point.resize(3);
835  if (N)
836  {
837  m_kdtree3d_data.index.reset(
838  new tree3d_t(
839  3, derived(), nanoflann::KDTreeSingleIndexAdaptorParams(
841  m_kdtree3d_data.index->buildIndex();
842  }
843  m_kdtree_is_uptodate = true;
844  }
845  }
846 
847 }; // end of KDTreeCapable
848 
849 /** @} */ // end of grouping
850 
851 } // End of namespace
852 } // End of namespace
853 #endif
A generic adaptor class for providing Nearest Neighbor (NN) lookup via the nanoflann library.
Definition: KDTreeCapable.h:82
void kdTreeNClosestPoint3DIdx(const TPoint3D &p0, size_t N, std::vector< size_t > &outIdx, std::vector< float > &outDistSqr) const
size_t kdTreeClosestPoint3D(float x0, float y0, float z0, float &out_dist_sqr) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
TKDTreeSearchParams kdtree_search_params
Parameters to tune the ANN searches.
float kdTreeClosestPoint2DsqrError(const TPoint2D &p0) const
void kdTreeNClosestPoint3DIdx(float x0, float y0, float z0, size_t knn, std::vector< size_t > &out_idx, std::vector< float > &out_dist_sqr) const
KD Tree-based search for the N closest point to some given 3D coordinates and returns their indexes.
TKDTreeDataHolder< 3 > m_kdtree3d_data
TKDTreeDataHolder m_kdtreeNd_data
size_t kdTreeClosestPoint2D(const TPoint2D &p0, TPoint2D &pOut, float &outDistSqr) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void kdTreeNClosestPoint3DWithIdx(float x0, float y0, float z0, size_t knn, std::vector< float > &out_x, std::vector< float > &out_y, std::vector< float > &out_z, std::vector< size_t > &out_idx, std::vector< float > &out_dist_sqr) const
KD Tree-based search for the N closest points to some given 3D coordinates.
void kdTreeNClosestPoint3D(const TPoint3D &p0, size_t N, std::vector< TPoint3D > &pOut, std::vector< float > &outDistSqr) const
Derived & derived()
CRTP helper method.
Definition: KDTreeCapable.h:96
size_t kdTreeRadiusSearch3D(const num_t x0, const num_t y0, const num_t z0, const num_t maxRadiusSqr, std::vector< std::pair< size_t, num_t >> &out_indices_dist) const
KD Tree-based search for all the points within a given radius of some 3D point.
void kdtree_mark_as_outdated() const
To be called by child classes when KD tree data changes.
const Derived & derived() const
CRTP helper method.
Definition: KDTreeCapable.h:91
TKDTreeDataHolder< 2 > m_kdtree2d_data
void kdTreeNClosestPoint3D(float x0, float y0, float z0, size_t knn, std::vector< float > &out_x, std::vector< float > &out_y, std::vector< float > &out_z, std::vector< float > &out_dist_sqr) const
KD Tree-based search for the N closest points to some given 3D coordinates.
float kdTreeClosestPoint2DsqrError(float x0, float y0) const
Like kdTreeClosestPoint2D, but just return the square error from some point to its closest neighbor.
void rebuild_kdTree_3D() const
Rebuild, if needed the KD-tree for 2D (nDims=2), 3D (nDims=3), ...
void rebuild_kdTree_2D() const
Rebuild, if needed the KD-tree for 2D (nDims=2), 3D (nDims=3), ...
bool m_kdtree_is_uptodate
whether the KD tree needs to be rebuilt or not.
void kdTreeNClosestPoint2DIdx(const TPoint2D &p0, size_t N, std::vector< size_t > &outIdx, std::vector< float > &outDistSqr) const
KDTreeCapable< Derived, num_t, metric_t > self_t
Definition: KDTreeCapable.h:85
size_t kdTreeClosestPoint2D(float x0, float y0, float &out_dist_sqr) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
size_t kdTreeClosestPoint2D(float x0, float y0, float &out_x, float &out_y, float &out_dist_sqr) const
KD Tree-based search for the closest point (only ONE) to some given 2D coordinates.
void kdTreeTwoClosestPoint2D(const TPoint2D &p0, TPoint2D &pOut1, TPoint2D &pOut2, float &outDistSqr1, float &outDistSqr2) const
size_t kdTreeClosestPoint3D(const TPoint3D &p0, TPoint3D &pOut, float &outDistSqr) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
std::vector< size_t > kdTreeNClosestPoint2D(float x0, float y0, size_t knn, std::vector< float > &out_x, std::vector< float > &out_y, std::vector< float > &out_dist_sqr) const
KD Tree-based search for the N closest point to some given 2D coordinates.
size_t kdTreeClosestPoint3D(float x0, float y0, float z0, float &out_x, float &out_y, float &out_z, float &out_dist_sqr) const
KD Tree-based search for the closest point (only ONE) to some given 3D coordinates.
size_t kdTreeRadiusSearch2D(const num_t x0, const num_t y0, const num_t maxRadiusSqr, std::vector< std::pair< size_t, num_t >> &out_indices_dist) const
KD Tree-based search for all the points within a given radius of some 2D point.
std::vector< size_t > kdTreeNClosestPoint2D(const TPoint2D &p0, size_t N, std::vector< TPoint2D > &pOut, std::vector< float > &outDistSqr) const
void kdTreeNClosestPoint2DIdx(float x0, float y0, size_t knn, std::vector< size_t > &out_idx, std::vector< float > &out_dist_sqr) const
KD Tree-based search for the N closest point to some given 2D coordinates and returns their indexes.
void kdTreeTwoClosestPoint2D(float x0, float y0, float &out_x1, float &out_y1, float &out_x2, float &out_y2, float &out_dist_sqr1, float &out_dist_sqr2) const
KD Tree-based search for the TWO closest point to some given 2D coordinates.
KDTreeCapable()
Constructor.
Definition: KDTreeCapable.h:89
GLuint res
Definition: glext.h:7268
GLuint index
Definition: glext.h:4054
#define MRPT_START
Definition: mrpt_macros.h:425
#define MRPT_END
Definition: mrpt_macros.h:429
#define THROW_EXCEPTION(msg)
Definition: mrpt_macros.h:111
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
Internal structure with the KD-tree representation (mainly used to avoid copying pointers with the = ...
TKDTreeDataHolder & operator=(const TKDTreeDataHolder &o) noexcept
Copy operator: It actually does NOT copy the kd-tree, a new object will be created if required!
nanoflann::KDTreeSingleIndexAdaptor< metric_t, Derived, _DIM > kdtree_index_t
std::unique_ptr< kdtree_index_t > index
nullptr or the up-to-date index
TKDTreeDataHolder(const TKDTreeDataHolder &)
Copy constructor: It actually does NOT copy the kd-tree, a new object will be created if required!
void clear() noexcept
Free memory (if allocated)
Lightweight 2D point.
double x
X,Y coordinates.
Lightweight 3D point.
double x
X,Y,Z coordinates.



Page generated by Doxygen 1.9.1 for MRPT 1.9.9 Git: 63ea9d1f1 Thu Nov 23 00:06:53 2017 +0100 at mar 26 may 2026 12:19:29 CEST