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 */
105  TKDTreeSearchParams kdtree_search_params;
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 
773  mutable TKDTreeDataHolder<2> m_kdtree2d_data;
774  mutable TKDTreeDataHolder<3> m_kdtree3d_data;
775  mutable TKDTreeDataHolder<> m_kdtreeNd_data;
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
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...
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 kdTreeNClosestPoint3DIdx(const TPoint3D &p0, size_t N, std::vector< size_t > &outIdx, std::vector< float > &outDistSqr) const
KDTreeCapable()
Constructor.
Definition: KDTreeCapable.h:89
double x
X,Y coordinates.
void kdTreeNClosestPoint2DIdx(const TPoint2D &p0, size_t N, std::vector< size_t > &outIdx, std::vector< float > &outDistSqr) const
TKDTreeDataHolder & operator=(const TKDTreeDataHolder &o) noexcept
Copy operator: It actually does NOT copy the kd-tree, a new object will be created if required! ...
void kdTreeTwoClosestPoint2D(const TPoint2D &p0, TPoint2D &pOut1, TPoint2D &pOut2, float &outDistSqr1, float &outDistSqr2) const
#define THROW_EXCEPTION(msg)
size_t kdTreeClosestPoint3D(const TPoint3D &p0, TPoint3D &pOut, float &outDistSqr) const
TKDTreeDataHolder< 2 > m_kdtree2d_data
const Derived & derived() const
CRTP helper method.
Definition: KDTreeCapable.h:91
KDTreeCapable< Derived, num_t, metric_t > self_t
Definition: KDTreeCapable.h:85
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 rebuild_kdTree_2D() const
Rebuild, if needed the KD-tree for 2D (nDims=2), 3D (nDims=3), ...
Derived & derived()
CRTP helper method.
Definition: KDTreeCapable.h:96
Internal structure with the KD-tree representation (mainly used to avoid copying pointers with the = ...
A generic adaptor class for providing Nearest Neighbor (NN) lookup via the nanoflann library...
Definition: KDTreeCapable.h:81
TKDTreeDataHolder< 3 > m_kdtree3d_data
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.
#define MRPT_END
GLuint index
Definition: glext.h:4054
void rebuild_kdTree_3D() const
Rebuild, if needed the KD-tree for 2D (nDims=2), 3D (nDims=3), ...
float kdTreeClosestPoint2DsqrError(const TPoint2D &p0) const
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.
nanoflann::KDTreeSingleIndexAdaptor< metric_t, Derived, _DIM > kdtree_index_t
std::vector< size_t > kdTreeNClosestPoint2D(const TPoint2D &p0, size_t N, std::vector< TPoint2D > &pOut, std::vector< float > &outDistSqr) const
size_t kdTreeClosestPoint2D(float x0, float y0, float &out_dist_sqr) const
size_t kdTreeClosestPoint2D(const TPoint2D &p0, TPoint2D &pOut, float &outDistSqr) const
size_t kdTreeClosestPoint3D(float x0, float y0, float z0, float &out_dist_sqr) const
double x
X,Y,Z coordinates.
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.
#define MRPT_START
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
bool m_kdtree_is_uptodate
whether the KD tree needs to be rebuilt or not.
void kdTreeNClosestPoint3D(const TPoint3D &p0, size_t N, std::vector< TPoint3D > &pOut, std::vector< float > &outDistSqr) const
void kdtree_mark_as_outdated() const
To be called by child classes when KD tree data changes.
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.
TKDTreeDataHolder(const TKDTreeDataHolder &)
Copy constructor: It actually does NOT copy the kd-tree, a new object will be created if required! ...
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.
GLuint res
Definition: glext.h:7268
TKDTreeDataHolder m_kdtreeNd_data
TKDTreeSearchParams kdtree_search_params
Parameters to tune the ANN searches.
Lightweight 3D point.
Lightweight 2D point.
void clear() noexcept
Free memory (if allocated)
float kdTreeClosestPoint2DsqrError(float x0, float y0) const
Like kdTreeClosestPoint2D, but just return the square error from some point to its closest neighbor...
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.
std::unique_ptr< kdtree_index_t > index
nullptr or the up-to-date index
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.



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019