Main MRPT website > C++ reference
MRPT logo
nanoflann.hpp
Go to the documentation of this file.
1 /***********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
5  * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
6  * Copyright 2011 Jose Luis Blanco (joseluisblancoc@gmail.com).
7  * All rights reserved.
8  *
9  * THE BSD LICENSE
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  * notice, this list of conditions and the following disclaimer in the
19  * documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *************************************************************************/
32 
33 #ifndef NANOFLANN_HPP_
34 #define NANOFLANN_HPP_
35 
36 #include <vector>
37 #include <string>
38 #include <cassert>
39 #include <map>
40 #include <algorithm>
41 #include <stdexcept>
42 #include <limits>
43 
44 #include <cassert>
45 #include <cstring>
46 #include <cstdio>
47 #include <cmath>
48 
49 
50 namespace nanoflann
51 {
52 /** @addtogroup nanoflann_grp nanoflann C++ library for ANN
53  * @{ */
54 
55  /** Library version: 0xMmP (M=Major,m=minor,P=path) */
56  #define NANOFLANN_VERSION 0x112
57 
58  /** @addtogroup result_sets_grp Result set classes
59  * @{ */
60  template <typename DistanceType, typename IndexType = size_t, typename CountType = size_t>
62  {
63  IndexType * indices;
64  DistanceType* dists;
65  CountType capacity;
66  CountType count;
67 
68  public:
69  inline KNNResultSet(CountType capacity_) : capacity(capacity_), count(0)
70  {
71  }
72 
73  inline void init(IndexType* indices_, DistanceType* dists_)
74  {
75  indices = indices_;
76  dists = dists_;
77  count = 0;
78  dists[capacity-1] = (std::numeric_limits<DistanceType>::max)();
79  }
80 
81  inline CountType size() const
82  {
83  return count;
84  }
85 
86  inline bool full() const
87  {
88  return count == capacity;
89  }
90 
91 
92  inline void addPoint(DistanceType dist, IndexType index)
93  {
94  CountType i;
95  for (i=count; i>0; --i) {
96 #ifdef NANOFLANN_FIRST_MATCH
97  if ( (dists[i-1]>dist) || ((dist==dists[i-1])&&(indices[i-1]>index)) ) {
98 #else
99  if (dists[i-1]>dist) {
100 #endif
101  if (i<capacity) {
102  dists[i] = dists[i-1];
103  indices[i] = indices[i-1];
104  }
105  }
106  else break;
107  }
108  if (i<capacity) {
109  dists[i] = dist;
110  indices[i] = index;
111  }
112  if (count<capacity) count++;
113  }
114 
115  inline DistanceType worstDist() const
116  {
117  return dists[capacity-1];
118  }
119  };
120 
121 
122  /**
123  * A result-set class used when performing a radius based search.
124  */
125  template <typename DistanceType, typename IndexType = size_t>
127  {
128  public:
129  const DistanceType radius;
130 
131  std::vector<std::pair<IndexType,DistanceType> >& m_indices_dists;
132 
133  inline RadiusResultSet(DistanceType radius_, std::vector<std::pair<IndexType,DistanceType> >& indices_dists) : radius(radius_), m_indices_dists(indices_dists)
134  {
135  init();
136  }
137 
138  inline ~RadiusResultSet() { }
139 
140  inline void init() { m_indices_dists.clear(); }
141 
142  inline size_t size() const { return m_indices_dists.size(); }
143 
144  inline bool full() const { return true; }
145 
146  inline void addPoint(DistanceType dist, IndexType index)
147  {
148  if (dist<radius)
149  m_indices_dists.push_back(std::make_pair<IndexType,DistanceType>(index,dist));
150  }
151 
152  inline DistanceType worstDist() const { return radius; }
153  };
154 
155  /** operator "<" for std::sort() */
157  {
158  /** PairType will be typically: std::pair<IndexType,DistanceType> */
159  template <typename PairType>
160  inline bool operator()(const PairType &p1, const PairType &p2) const {
161  return p1.second < p2.second;
162  }
163  };
164 
165  /** @} */
166 
167 
168  /** @addtogroup loadsave_grp Load/save auxiliary functions
169  * @{ */
170  template<typename T>
171  void save_value(FILE* stream, const T& value, size_t count = 1)
172  {
173  fwrite(&value, sizeof(value),count, stream);
174  }
175 
176  template<typename T>
177  void save_value(FILE* stream, const std::vector<T>& value)
178  {
179  size_t size = value.size();
180  fwrite(&size, sizeof(size_t), 1, stream);
181  fwrite(&value[0], sizeof(T), size, stream);
182  }
183 
184  template<typename T>
185  void load_value(FILE* stream, T& value, size_t count = 1)
186  {
187  size_t read_cnt = fread(&value, sizeof(value), count, stream);
188  if (read_cnt != count) {
189  throw std::runtime_error("Cannot read from file");
190  }
191  }
192 
193 
194  template<typename T>
195  void load_value(FILE* stream, std::vector<T>& value)
196  {
197  size_t size;
198  size_t read_cnt = fread(&size, sizeof(size_t), 1, stream);
199  if (read_cnt!=1) {
200  throw std::runtime_error("Cannot read from file");
201  }
202  value.resize(size);
203  read_cnt = fread(&value[0], sizeof(T), size, stream);
204  if (read_cnt!=size) {
205  throw std::runtime_error("Cannot read from file");
206  }
207  }
208  /** @} */
209 
210 
211  /** @addtogroup metric_grp Metric (distance) classes
212  * @{ */
213 
214  template<typename T> inline T abs(T x) { return (x<0) ? -x : x; }
215  template<> inline int abs<int>(int x) { return ::abs(x); }
216  template<> inline float abs<float>(float x) { return fabsf(x); }
217  template<> inline double abs<double>(double x) { return fabs(x); }
218  template<> inline long double abs<long double>(long double x) { return fabsl(x); }
219 
220  /** Manhattan distance functor (generic version, optimized for high-dimensionality data sets).
221  * Corresponding distance traits: nanoflann::metric_L1
222  * \tparam T Type of the elements (e.g. double, float, uint8_t)
223  * \tparam DistanceType Type of distance variables (must be signed) (e.g. float, double, int64_t)
224  */
225  template<class T, class DataSource, typename _DistanceType = T>
226  struct L1_Adaptor
227  {
228  typedef T ElementType;
229  typedef _DistanceType DistanceType;
230 
231  const DataSource &data_source;
232 
233  L1_Adaptor(const DataSource &_data_source) : data_source(_data_source) { }
234 
235  inline DistanceType operator()(const T* a, const size_t b_idx, size_t size, DistanceType worst_dist = -1) const
236  {
237  DistanceType result = DistanceType();
238  const T* last = a + size;
239  const T* lastgroup = last - 3;
240  size_t d = 0;
241 
242  /* Process 4 items with each loop for efficiency. */
243  while (a < lastgroup) {
244  const DistanceType diff0 = nanoflann::abs(a[0] - data_source.kdtree_get_pt(b_idx,d++));
245  const DistanceType diff1 = nanoflann::abs(a[1] - data_source.kdtree_get_pt(b_idx,d++));
246  const DistanceType diff2 = nanoflann::abs(a[2] - data_source.kdtree_get_pt(b_idx,d++));
247  const DistanceType diff3 = nanoflann::abs(a[3] - data_source.kdtree_get_pt(b_idx,d++));
248  result += diff0 + diff1 + diff2 + diff3;
249  a += 4;
250  if ((worst_dist>0)&&(result>worst_dist)) {
251  return result;
252  }
253  }
254  /* Process last 0-3 components. Not needed for standard vector lengths. */
255  while (a < last) {
256  result += nanoflann::abs( *a++ - data_source.kdtree_get_pt(b_idx,d++) );
257  }
258  return result;
259  }
260 
261  template <typename U, typename V>
262  inline DistanceType accum_dist(const U a, const V b, int dim) const
263  {
264  return (a-b)*(a-b);
265  }
266  };
267 
268  /** Squared Euclidean distance functor (generic version, optimized for high-dimensionality data sets).
269  * Corresponding distance traits: nanoflann::metric_L2
270  * \tparam T Type of the elements (e.g. double, float, uint8_t)
271  * \tparam DistanceType Type of distance variables (must be signed) (e.g. float, double, int64_t)
272  */
273  template<class T, class DataSource, typename _DistanceType = T>
274  struct L2_Adaptor
275  {
276  typedef T ElementType;
277  typedef _DistanceType DistanceType;
278 
279  const DataSource &data_source;
280 
281  L2_Adaptor(const DataSource &_data_source) : data_source(_data_source) { }
282 
283  inline DistanceType operator()(const T* a, const size_t b_idx, size_t size, DistanceType worst_dist = -1) const
284  {
285  DistanceType result = DistanceType();
286  const T* last = a + size;
287  const T* lastgroup = last - 3;
288  size_t d = 0;
289 
290  /* Process 4 items with each loop for efficiency. */
291  while (a < lastgroup) {
292  const DistanceType diff0 = a[0] - data_source.kdtree_get_pt(b_idx,d++);
293  const DistanceType diff1 = a[1] - data_source.kdtree_get_pt(b_idx,d++);
294  const DistanceType diff2 = a[2] - data_source.kdtree_get_pt(b_idx,d++);
295  const DistanceType diff3 = a[3] - data_source.kdtree_get_pt(b_idx,d++);
296  result += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;
297  a += 4;
298  if ((worst_dist>0)&&(result>worst_dist)) {
299  return result;
300  }
301  }
302  /* Process last 0-3 components. Not needed for standard vector lengths. */
303  while (a < last) {
304  const DistanceType diff0 = *a++ - data_source.kdtree_get_pt(b_idx,d++);
305  result += diff0 * diff0;
306  }
307  return result;
308  }
309 
310  template <typename U, typename V>
311  inline DistanceType accum_dist(const U a, const V b, int dim) const
312  {
313  return (a-b)*(a-b);
314  }
315  };
316 
317  /** Squared Euclidean distance functor (suitable for low-dimensionality datasets, like 2D or 3D point clouds)
318  * Corresponding distance traits: nanoflann::metric_L2_Simple
319  * \tparam T Type of the elements (e.g. double, float, uint8_t)
320  * \tparam DistanceType Type of distance variables (must be signed) (e.g. float, double, int64_t)
321  */
322  template<class T, class DataSource, typename _DistanceType = T>
324  {
325  typedef T ElementType;
326  typedef _DistanceType DistanceType;
327 
328  const DataSource &data_source;
329 
330  L2_Simple_Adaptor(const DataSource &_data_source) : data_source(_data_source) { }
331 
332  inline DistanceType operator()(const T* a, const size_t b_idx, size_t size) const {
333  return data_source.kdtree_distance(a,b_idx,size);
334  }
335 
336  template <typename U, typename V>
337  inline DistanceType accum_dist(const U a, const V b, int dim) const
338  {
339  return (a-b)*(a-b);
340  }
341  };
342 
343  /** Metaprogramming helper traits class for the L1 (Manhattan) metric */
344  struct metric_L1 {
345  template<class T, class DataSource>
346  struct traits {
348  };
349  };
350  /** Metaprogramming helper traits class for the L2 (Euclidean) metric */
351  struct metric_L2 {
352  template<class T, class DataSource>
353  struct traits {
355  };
356  };
357  /** Metaprogramming helper traits class for the L2_simple (Euclidean) metric */
359  template<class T, class DataSource>
360  struct traits {
362  };
363  };
364 
365  /** @} */
366 
367 
368 
369  /** @addtogroup param_grp Parameter structs
370  * @{ */
371 
372  /** Parameters (see http://code.google.com/p/nanoflann/ for help choosing the parameters)
373  */
375  {
376  KDTreeSingleIndexAdaptorParams(size_t _leaf_max_size = 10, int dim_ = -1) :
377  leaf_max_size(_leaf_max_size), dim(dim_)
378  {}
379 
381  int dim;
382  };
383 
384  /** Search options for KDTreeSingleIndexAdaptor::findNeighbors() */
386  {
387  /** Note: The first argument (checks_IGNORED_) is ignored, but kept for compatibility with the FLANN interface */
388  SearchParams(int checks_IGNORED_ = 32, float eps_ = 0, bool sorted_ = true ) :
389  eps(eps_), sorted(sorted_) {}
390 
391  int checks; //!< Ignored parameter (Kept for compatibility with the FLANN interface).
392  float eps; //!< search for eps-approximate neighbours (default: 0)
393  bool sorted; //!< only for radius search, require neighbours sorted by distance (default: true)
394  };
395  /** @} */
396 
397 
398  /** @addtogroup memalloc_grp Memory allocation
399  * @{ */
400 
401  /**
402  * Allocates (using C's malloc) a generic type T.
403  *
404  * Params:
405  * count = number of instances to allocate.
406  * Returns: pointer (of type T*) to memory buffer
407  */
408  template <typename T>
409  inline T* allocate(size_t count = 1)
410  {
411  T* mem = (T*) ::malloc(sizeof(T)*count);
412  return mem;
413  }
414 
415 
416  /**
417  * Pooled storage allocator
418  *
419  * The following routines allow for the efficient allocation of storage in
420  * small chunks from a specified pool. Rather than allowing each structure
421  * to be freed individually, an entire pool of storage is freed at once.
422  * This method has two advantages over just using malloc() and free(). First,
423  * it is far more efficient for allocating small objects, as there is
424  * no overhead for remembering all the information needed to free each
425  * object or consolidating fragmented memory. Second, the decision about
426  * how long to keep an object is made at the time of allocation, and there
427  * is no need to track down all the objects to free them.
428  *
429  */
430 
431  const size_t WORDSIZE=16;
432  const size_t BLOCKSIZE=8192;
433 
435  {
436  /* We maintain memory alignment to word boundaries by requiring that all
437  allocations be in multiples of the machine wordsize. */
438  /* Size of machine word in bytes. Must be power of 2. */
439  /* Minimum number of bytes requested at a time from the system. Must be multiple of WORDSIZE. */
440 
441 
442  size_t remaining; /* Number of bytes left in current block of storage. */
443  void* base; /* Pointer to base of current block of storage. */
444  void* loc; /* Current location in block to next allocate memory. */
445  size_t blocksize;
446 
447 
448  public:
449  size_t usedMemory;
450  size_t wastedMemory;
451 
452  /**
453  Default constructor. Initializes a new pool.
454  */
455  PooledAllocator(const size_t blocksize = BLOCKSIZE)
456  {
457  this->blocksize = blocksize;
458  remaining = 0;
459  base = NULL;
460 
461  usedMemory = 0;
462  wastedMemory = 0;
463  }
464 
465  /**
466  * Destructor. Frees all the memory allocated in this pool.
467  */
469  {
470  while (base != NULL) {
471  void *prev = *((void**) base); /* Get pointer to prev block. */
472  ::free(base);
473  base = prev;
474  }
475  }
476 
477  /**
478  * Returns a pointer to a piece of new memory of the given size in bytes
479  * allocated from the pool.
480  */
481  void* malloc(const size_t req_size)
482  {
483  /* Round size up to a multiple of wordsize. The following expression
484  only works for WORDSIZE that is a power of 2, by masking last bits of
485  incremented size to zero.
486  */
487  const size_t size = (req_size + (WORDSIZE - 1)) & ~(WORDSIZE - 1);
488 
489  /* Check whether a new block must be allocated. Note that the first word
490  of a block is reserved for a pointer to the previous block.
491  */
492  if (size > remaining) {
493 
494  wastedMemory += remaining;
495 
496  /* Allocate new storage. */
497  const size_t blocksize = (size + sizeof(void*) + (WORDSIZE-1) > BLOCKSIZE) ?
498  size + sizeof(void*) + (WORDSIZE-1) : BLOCKSIZE;
499 
500  // use the standard C malloc to allocate memory
501  void* m = ::malloc(blocksize);
502  if (!m) {
503  fprintf(stderr,"Failed to allocate memory.\n");
504  return NULL;
505  }
506 
507  /* Fill first word of new block with pointer to previous block. */
508  ((void**) m)[0] = base;
509  base = m;
510 
511  size_t shift = 0;
512  //int size_t = (WORDSIZE - ( (((size_t)m) + sizeof(void*)) & (WORDSIZE-1))) & (WORDSIZE-1);
513 
514  remaining = blocksize - sizeof(void*) - shift;
515  loc = ((char*)m + sizeof(void*) + shift);
516  }
517  void* rloc = loc;
518  loc = (char*)loc + size;
519  remaining -= size;
520 
521  usedMemory += size;
522 
523  return rloc;
524  }
525 
526  /**
527  * Allocates (using this pool) a generic type T.
528  *
529  * Params:
530  * count = number of instances to allocate.
531  * Returns: pointer (of type T*) to memory buffer
532  */
533  template <typename T>
534  T* allocate(const size_t count = 1)
535  {
536  T* mem = (T*) this->malloc(sizeof(T)*count);
537  return mem;
538  }
539 
540  };
541  /** @} */
542 
543 
544  /** @addtogroup kdtrees_grp KD-tree classes and adaptors
545  * @{ */
546 
547  /** kd-tree index
548  *
549  * Contains the k-d trees and other information for indexing a set of points
550  * for nearest-neighbor matching.
551  *
552  * The class "DatasetAdaptor" must provide the following interface (can be non-virtual, inlined methods):
553  *
554  * \code
555  * // Must return the number of data points
556  * inline size_t kdtree_get_point_count() const { ... }
557  *
558  * // Must return the Euclidean (L2) distance between the vector "p1[0:size-1]" and the data point with index "idx_p2" stored in the class:
559  * inline DistanceType kdtree_distance(const T *p1, const size_t idx_p2,size_t size) const { ... }
560  *
561  * // Must return the dim'th component of the idx'th point in the class:
562  * inline T kdtree_get_pt(const size_t idx, int dim) const { ... }
563  *
564  * // Optional bounding-box computation: return false to default to a standard bbox computation loop.
565  * // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again.
566  * // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds)
567  * template <class BBOX>
568  * bool kdtree_get_bbox(BBOX &bb) const
569  * {
570  * bb[0].low = ...; bb[0].high = ...; // 0th dimension limits
571  * bb[1].low = ...; bb[1].high = ...; // 1st dimension limits
572  * ...
573  * return true;
574  * }
575  *
576  * \endcode
577  *
578  * \tparam IndexType Will be typically size_t or int
579  */
580  template <typename Distance, class DatasetAdaptor,int DIM = -1, typename IndexType = size_t>
582  {
583  public:
584  typedef typename Distance::ElementType ElementType;
585  typedef typename Distance::DistanceType DistanceType;
586  protected:
587 
588  /**
589  * Array of indices to vectors in the dataset.
590  */
591  std::vector<IndexType> vind;
592 
594 
595 
596  /**
597  * The dataset used by this index
598  */
599  const DatasetAdaptor &dataset; //!< The source of our data
600 
602 
603  size_t m_size;
604  int dim; //!< Dimensionality of each data point
605 
606 
607  /*--------------------- Internal Data Structures --------------------------*/
608  struct Node
609  {
610  union {
611  struct
612  {
613  /**
614  * Indices of points in leaf node
615  */
616  IndexType left, right;
617  } lr;
618  struct
619  {
620  /**
621  * Dimension used for subdivision.
622  */
623  int divfeat;
624  /**
625  * The values used for subdivision.
626  */
628  } sub;
629  };
630  /**
631  * The child nodes.
632  */
633  Node* child1, * child2;
634  };
635  typedef Node* NodePtr;
636 
637 
638  struct Interval
639  {
641  };
642 
643  typedef std::vector<Interval> BoundingBox;
644 
645 
646  /** This record represents a branch point when finding neighbors in
647  the tree. It contains a record of the minimum distance to the query
648  point, as well as the node at which the search resumes.
649  */
650  template <typename T, typename DistanceType>
652  {
653  T node; /* Tree node at which search resumes */
654  DistanceType mindist; /* Minimum distance to query for all nodes below. */
655 
657  BranchStruct(const T& aNode, DistanceType dist) : node(aNode), mindist(dist) {}
658 
659  inline bool operator<(const BranchStruct<T, DistanceType>& rhs) const
660  {
661  return mindist<rhs.mindist;
662  }
663  };
664 
665  /**
666  * Array of k-d trees used to find neighbours.
667  */
670  typedef BranchSt* Branch;
671 
673 
674  /**
675  * Pooled memory allocator.
676  *
677  * Using a pooled memory allocator is more efficient
678  * than allocating memory directly when there is a large
679  * number small of memory allocations.
680  */
682 
683  public:
684 
685  Distance distance;
686 
687  /**
688  * KDTree constructor
689  *
690  * Params:
691  * inputData = dataset with the input features
692  * params = parameters passed to the kdtree algorithm (see http://code.google.com/p/nanoflann/ for help choosing the parameters)
693  */
694  KDTreeSingleIndexAdaptor(const int dimensionality, const DatasetAdaptor& inputData, const KDTreeSingleIndexAdaptorParams& params = KDTreeSingleIndexAdaptorParams() ) :
695  dataset(inputData), index_params(params), distance(inputData)
696  {
697  m_size = dataset.kdtree_get_point_count();
698  dim = dimensionality;
699  if (DIM>0) dim=DIM;
700  else {
701  if (params.dim>0) dim = params.dim;
702  }
703  m_leaf_max_size = params.leaf_max_size;
704 
705  // Create a permutable array of indices to the input vectors.
706  init_vind();
707  }
708 
709  /**
710  * Standard destructor
711  */
713  {
714  }
715 
716  /**
717  * Builds the index
718  */
719  void buildIndex()
720  {
721  init_vind();
722  computeBoundingBox(root_bbox);
723  root_node = divideTree(0, m_size, root_bbox ); // construct the tree
724  }
725 
726  /**
727  * Returns size of index.
728  */
729  size_t size() const
730  {
731  return m_size;
732  }
733 
734  /**
735  * Returns the length of an index feature.
736  */
737  size_t veclen() const
738  {
739  return static_cast<size_t>(DIM>0 ? DIM : dim);
740  }
741 
742  /**
743  * Computes the inde memory usage
744  * Returns: memory used by the index
745  */
746  size_t usedMemory() const
747  {
748  return pool.usedMemory+pool.wastedMemory+dataset.kdtree_get_point_count()*sizeof(IndexType); // pool memory and vind array memory
749  }
750 
751  /** \name Query methods
752  * @{ */
753 
754  /**
755  * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored inside
756  * the result object.
757  *
758  * Params:
759  * result = the result object in which the indices of the nearest-neighbors are stored
760  * vec = the vector for which to search the nearest neighbors
761  *
762  * \tparam RESULTSET Should be any ResultSet<DistanceType>
763  * \sa knnSearch, radiusSearch
764  */
765  template <typename RESULTSET>
766  void findNeighbors(RESULTSET& result, const ElementType* vec, const SearchParams& searchParams) const
767  {
768  float epsError = 1+searchParams.eps;
769 
770  std::vector<DistanceType> dists( (DIM>0 ? DIM : dim) ,0);
771  DistanceType distsq = computeInitialDistances(vec, dists);
772  searchLevel(result, vec, root_node, distsq, dists, epsError); // "count_leaf" parameter removed since was neither used nor returned to the user.
773  }
774 
775  /**
776  * Find the "num_closest" nearest neighbors to the \a query_point[0:dim-1]. Their indices are stored inside
777  * the result object.
778  * \sa radiusSearch, findNeighbors
779  * \note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface.
780  */
781  inline void knnSearch(const ElementType *query_point, const size_t num_closest, IndexType *out_indices, DistanceType *out_distances_sq, const int nChecks_IGNORED = 10) const
782  {
784  resultSet.init(out_indices, out_distances_sq);
785  this->findNeighbors(resultSet, query_point, nanoflann::SearchParams());
786  }
787 
788  /**
789  * Find all the neighbors to \a query_point[0:dim-1] within a maximum radius.
790  * The output is given as a vector of pairs, of which the first element is a point index and the second the corresponding distance.
791  * Previous contents of \a IndicesDists are cleared.
792  *
793  * If searchParams.sorted==true, the output list is sorted by ascending distances.
794  *
795  * For a better performance, it is advisable to do a .reserve() on the vector if you have any wild guess about the number of expected matches.
796  *
797  * \sa knnSearch, findNeighbors
798  * \return The number of points within the given radius (i.e. indices.size() or dists.size() )
799  */
800  size_t radiusSearch(const ElementType *query_point,const DistanceType radius, std::vector<std::pair<IndexType,DistanceType> >& IndicesDists, const SearchParams& searchParams) const
801  {
802  RadiusResultSet<DistanceType,IndexType> resultSet(radius,IndicesDists);
803  this->findNeighbors(resultSet, query_point, searchParams);
804 
805  if (searchParams.sorted)
806  std::sort(IndicesDists.begin(),IndicesDists.end(), IndexDist_Sorter() );
807 
808  return resultSet.size();
809  }
810 
811  /** @} */
812 
813  private:
814  /** Make sure the auxiliary list \a vind has the same size than the current dataset, and re-generate if size has changed. */
815  void init_vind()
816  {
817  // Create a permutable array of indices to the input vectors.
818  m_size = dataset.kdtree_get_point_count();
819  if (vind.size()!=m_size)
820  {
821  vind.resize(m_size);
822  for (size_t i = 0; i < m_size; i++) vind[i] = i;
823  }
824  }
825 
826  /// Helper accessor to the dataset points:
827  inline ElementType dataset_get(size_t idx, int component) const {
828  return dataset.kdtree_get_pt(idx,component);
829  }
830 
831 
832  void save_tree(FILE* stream, NodePtr tree)
833  {
834  save_value(stream, *tree);
835  if (tree->child1!=NULL) {
836  save_tree(stream, tree->child1);
837  }
838  if (tree->child2!=NULL) {
839  save_tree(stream, tree->child2);
840  }
841  }
842 
843 
844  void load_tree(FILE* stream, NodePtr& tree)
845  {
846  tree = pool.allocate<Node>();
847  load_value(stream, *tree);
848  if (tree->child1!=NULL) {
849  load_tree(stream, tree->child1);
850  }
851  if (tree->child2!=NULL) {
852  load_tree(stream, tree->child2);
853  }
854  }
855 
856 
857  void computeBoundingBox(BoundingBox& bbox)
858  {
859  bbox.resize((DIM>0 ? DIM : dim));
860  if (dataset.kdtree_get_bbox(bbox))
861  {
862  // Done! It was implemented in derived class
863  }
864  else
865  {
866  for (int i=0; i<(DIM>0 ? DIM : dim); ++i) {
867  bbox[i].low =
868  bbox[i].high = dataset_get(0,i);
869  }
870  const size_t N = dataset.kdtree_get_point_count();
871  for (size_t k=1; k<N; ++k) {
872  for (int i=0; i<(DIM>0 ? DIM : dim); ++i) {
873  if (dataset_get(k,i)<bbox[i].low) bbox[i].low = dataset_get(k,i);
874  if (dataset_get(k,i)>bbox[i].high) bbox[i].high = dataset_get(k,i);
875  }
876  }
877  }
878  }
879 
880 
881  /**
882  * Create a tree node that subdivides the list of vecs from vind[first]
883  * to vind[last]. The routine is called recursively on each sublist.
884  * Place a pointer to this new tree node in the location pTree.
885  *
886  * Params: pTree = the new node to create
887  * first = index of the first vector
888  * last = index of the last vector
889  */
890  NodePtr divideTree(const IndexType left, const IndexType right, BoundingBox& bbox)
891  {
892  NodePtr node = pool.allocate<Node>(); // allocate memory
893 
894  /* If too few exemplars remain, then make this a leaf node. */
895  if ( (right-left) <= m_leaf_max_size) {
896  node->child1 = node->child2 = NULL; /* Mark as leaf node. */
897  node->lr.left = left;
898  node->lr.right = right;
899 
900  // compute bounding-box of leaf points
901  for (int i=0; i<(DIM>0 ? DIM : dim); ++i) {
902  bbox[i].low = dataset_get(vind[left],i);
903  bbox[i].high = dataset_get(vind[left],i);
904  }
905  for (IndexType k=left+1; k<right; ++k) {
906  for (int i=0; i<(DIM>0 ? DIM : dim); ++i) {
907  if (bbox[i].low>dataset_get(vind[k],i)) bbox[i].low=dataset_get(vind[k],i);
908  if (bbox[i].high<dataset_get(vind[k],i)) bbox[i].high=dataset_get(vind[k],i);
909  }
910  }
911  }
912  else {
913  IndexType idx;
914  int cutfeat;
915  DistanceType cutval;
916  middleSplit_(&vind[0]+left, right-left, idx, cutfeat, cutval, bbox);
917 
918  node->sub.divfeat = cutfeat;
919 
920  BoundingBox left_bbox(bbox);
921  left_bbox[cutfeat].high = cutval;
922  node->child1 = divideTree(left, left+idx, left_bbox);
923 
924  BoundingBox right_bbox(bbox);
925  right_bbox[cutfeat].low = cutval;
926  node->child2 = divideTree(left+idx, right, right_bbox);
927 
928  node->sub.divlow = left_bbox[cutfeat].high;
929  node->sub.divhigh = right_bbox[cutfeat].low;
930 
931  for (int i=0; i<(DIM>0 ? DIM : dim); ++i) {
932  bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low);
933  bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high);
934  }
935  }
936 
937  return node;
938  }
939 
940  void computeMinMax(IndexType* ind, IndexType count, int element, ElementType& min_elem, ElementType& max_elem)
941  {
942  min_elem = dataset_get(ind[0],element);
943  max_elem = dataset_get(ind[0],element);
944  for (IndexType i=1; i<count; ++i) {
945  ElementType val = dataset_get(ind[i],element);
946  if (val<min_elem) min_elem = val;
947  if (val>max_elem) max_elem = val;
948  }
949  }
950 
951  void middleSplit(IndexType* ind, IndexType count, IndexType& index, int& cutfeat, DistanceType& cutval, const BoundingBox& bbox)
952  {
953  // find the largest span from the approximate bounding box
954  ElementType max_span = bbox[0].high-bbox[0].low;
955  cutfeat = 0;
956  cutval = (bbox[0].high+bbox[0].low)/2;
957  for (int i=1; i<(DIM>0 ? DIM : dim); ++i) {
958  ElementType span = bbox[i].low-bbox[i].low;
959  if (span>max_span) {
960  max_span = span;
961  cutfeat = i;
962  cutval = (bbox[i].high+bbox[i].low)/2;
963  }
964  }
965 
966  // compute exact span on the found dimension
967  ElementType min_elem, max_elem;
968  computeMinMax(ind, count, cutfeat, min_elem, max_elem);
969  cutval = (min_elem+max_elem)/2;
970  max_span = max_elem - min_elem;
971 
972  // check if a dimension of a largest span exists
973  size_t k = cutfeat;
974  for (size_t i=0; i<(DIM>0 ? DIM : dim); ++i) {
975  if (i==k) continue;
976  ElementType span = bbox[i].high-bbox[i].low;
977  if (span>max_span) {
978  computeMinMax(ind, count, i, min_elem, max_elem);
979  span = max_elem - min_elem;
980  if (span>max_span) {
981  max_span = span;
982  cutfeat = i;
983  cutval = (min_elem+max_elem)/2;
984  }
985  }
986  }
987  IndexType lim1, lim2;
988  planeSplit(ind, count, cutfeat, cutval, lim1, lim2);
989 
990  if (lim1>count/2) index = lim1;
991  else if (lim2<count/2) index = lim2;
992  else index = count/2;
993  }
994 
995 
996  void middleSplit_(IndexType* ind, IndexType count, IndexType& index, int& cutfeat, DistanceType& cutval, const BoundingBox& bbox)
997  {
998  const DistanceType EPS=static_cast<DistanceType>(0.00001);
999  ElementType max_span = bbox[0].high-bbox[0].low;
1000  for (int i=1; i<(DIM>0 ? DIM : dim); ++i) {
1001  ElementType span = bbox[i].high-bbox[i].low;
1002  if (span>max_span) {
1003  max_span = span;
1004  }
1005  }
1006  ElementType max_spread = -1;
1007  cutfeat = 0;
1008  for (int i=0; i<(DIM>0 ? DIM : dim); ++i) {
1009  ElementType span = bbox[i].high-bbox[i].low;
1010  if (span>(1-EPS)*max_span) {
1011  ElementType min_elem, max_elem;
1012  computeMinMax(ind, count, cutfeat, min_elem, max_elem);
1013  ElementType spread = max_elem-min_elem;;
1014  if (spread>max_spread) {
1015  cutfeat = i;
1016  max_spread = spread;
1017  }
1018  }
1019  }
1020  // split in the middle
1021  DistanceType split_val = (bbox[cutfeat].low+bbox[cutfeat].high)/2;
1022  ElementType min_elem, max_elem;
1023  computeMinMax(ind, count, cutfeat, min_elem, max_elem);
1024 
1025  if (split_val<min_elem) cutval = min_elem;
1026  else if (split_val>max_elem) cutval = max_elem;
1027  else cutval = split_val;
1028 
1029  IndexType lim1, lim2;
1030  planeSplit(ind, count, cutfeat, cutval, lim1, lim2);
1031 
1032  if (lim1>count/2) index = lim1;
1033  else if (lim2<count/2) index = lim2;
1034  else index = count/2;
1035  }
1036 
1037 
1038  /**
1039  * Subdivide the list of points by a plane perpendicular on axe corresponding
1040  * to the 'cutfeat' dimension at 'cutval' position.
1041  *
1042  * On return:
1043  * dataset[ind[0..lim1-1]][cutfeat]<cutval
1044  * dataset[ind[lim1..lim2-1]][cutfeat]==cutval
1045  * dataset[ind[lim2..count]][cutfeat]>cutval
1046  */
1047  void planeSplit(IndexType* ind, const IndexType count, int cutfeat, DistanceType cutval, IndexType& lim1, IndexType& lim2)
1048  {
1049  /* Move vector indices for left subtree to front of list. */
1050  IndexType left = 0;
1051  IndexType right = count-1;
1052  for (;; ) {
1053  while (left<=right && dataset_get(ind[left],cutfeat)<cutval) ++left;
1054  while (right && left<=right && dataset_get(ind[right],cutfeat)>=cutval) --right;
1055  if (left>right || !right) break; // "!right" was added to support unsigned Index types
1056  std::swap(ind[left], ind[right]);
1057  ++left;
1058  --right;
1059  }
1060  /* If either list is empty, it means that all remaining features
1061  * are identical. Split in the middle to maintain a balanced tree.
1062  */
1063  lim1 = left;
1064  right = count-1;
1065  for (;; ) {
1066  while (left<=right && dataset_get(ind[left],cutfeat)<=cutval) ++left;
1067  while (right && left<=right && dataset_get(ind[right],cutfeat)>cutval) --right;
1068  if (left>right || !right) break; // "!right" was added to support unsigned Index types
1069  std::swap(ind[left], ind[right]);
1070  ++left;
1071  --right;
1072  }
1073  lim2 = left;
1074  }
1075 
1076  DistanceType computeInitialDistances(const ElementType* vec, std::vector<DistanceType>& dists) const
1077  {
1078  DistanceType distsq = 0.0;
1079 
1080  for (int i = 0; i < (DIM>0 ? DIM : dim); ++i) {
1081  if (vec[i] < root_bbox[i].low) {
1082  dists[i] = distance.accum_dist(vec[i], root_bbox[i].low, i);
1083  distsq += dists[i];
1084  }
1085  if (vec[i] > root_bbox[i].high) {
1086  dists[i] = distance.accum_dist(vec[i], root_bbox[i].high, i);
1087  distsq += dists[i];
1088  }
1089  }
1090 
1091  return distsq;
1092  }
1093 
1094  /**
1095  * Performs an exact search in the tree starting from a node.
1096  * \tparam RESULTSET Should be any ResultSet<DistanceType>
1097  */
1098  template <class RESULTSET>
1099  void searchLevel(RESULTSET& result_set, const ElementType* vec, const NodePtr node, DistanceType mindistsq,
1100  std::vector<DistanceType>& dists, const float epsError) const
1101  {
1102  /* If this is a leaf node, then do check and return. */
1103  if ((node->child1 == NULL)&&(node->child2 == NULL)) {
1104  //count_leaf += (node->lr.right-node->lr.left); // Removed since was neither used nor returned to the user.
1105  DistanceType worst_dist = result_set.worstDist();
1106  for (IndexType i=node->lr.left; i<node->lr.right; ++i) {
1107  const IndexType index = vind[i];// reorder... : i;
1108  DistanceType dist = distance(vec, index, (DIM>0 ? DIM : dim));
1109  if (dist<worst_dist) {
1110  result_set.addPoint(dist,vind[i]);
1111  }
1112  }
1113  return;
1114  }
1115 
1116  /* Which child branch should be taken first? */
1117  int idx = node->sub.divfeat;
1118  ElementType val = vec[idx];
1119  DistanceType diff1 = val - node->sub.divlow;
1120  DistanceType diff2 = val - node->sub.divhigh;
1121 
1122  NodePtr bestChild;
1123  NodePtr otherChild;
1124  DistanceType cut_dist;
1125  if ((diff1+diff2)<0) {
1126  bestChild = node->child1;
1127  otherChild = node->child2;
1128  cut_dist = distance.accum_dist(val, node->sub.divhigh, idx);
1129  }
1130  else {
1131  bestChild = node->child2;
1132  otherChild = node->child1;
1133  cut_dist = distance.accum_dist( val, node->sub.divlow, idx);
1134  }
1135 
1136  /* Call recursively to search next level down. */
1137  searchLevel(result_set, vec, bestChild, mindistsq, dists, epsError);
1138 
1139  DistanceType dst = dists[idx];
1140  mindistsq = mindistsq + cut_dist - dst;
1141  dists[idx] = cut_dist;
1142  if (mindistsq*epsError<=result_set.worstDist()) {
1143  searchLevel(result_set, vec, otherChild, mindistsq, dists, epsError);
1144  }
1145  dists[idx] = dst;
1146  }
1147 
1148 
1149  void saveIndex(FILE* stream)
1150  {
1151  save_value(stream, m_size);
1152  save_value(stream, dim);
1153  save_value(stream, root_bbox);
1154  save_value(stream, m_leaf_max_size);
1155  save_value(stream, vind);
1156  save_tree(stream, root_node);
1157  }
1158 
1159  void loadIndex(FILE* stream)
1160  {
1161  load_value(stream, m_size);
1162  load_value(stream, dim);
1163  load_value(stream, root_bbox);
1164  load_value(stream, m_leaf_max_size);
1165  load_value(stream, vind);
1166  load_tree(stream, root_node);
1167  }
1168 
1169  }; // class KDTree
1170 
1171 
1172  /** A simple KD-tree adaptor for working with data directly stored in an Eigen Matrix, without duplicating the data storage.
1173  * Each row in the matrix represents a point in the state space.
1174  *
1175  * Example of usage:
1176  * \code
1177  * Eigen::Matrix<num_t,Dynamic,Dynamic> mat;
1178  * // Fill out "mat"...
1179  *
1180  * typedef KDTreeEigenMatrixAdaptor< Eigen::Matrix<num_t,Dynamic,Dynamic> > my_kd_tree_t;
1181  * const int max_leaf = 10;
1182  * my_kd_tree_t mat_index(dimdim, mat, max_leaf );
1183  * mat_index.index->buildIndex();
1184  * mat_index.index->...
1185  * \endcode
1186  *
1187  * \tparam DIM If set to >0, it specifies a compile-time fixed dimensionality for the points in the data set, allowing more compiler optimizations.
1188  * \tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc.
1189  * \tparam IndexType The type for indices in the KD-tree index (typically, size_t of int)
1190  */
1191  template <class MatrixType, int DIM = -1, class Distance = nanoflann::metric_L2, typename IndexType = size_t>
1193  {
1195  typedef typename MatrixType::Scalar num_t;
1196  typedef typename Distance::template traits<num_t,self_t>::distance_t metric_t;
1198 
1199  index_t* index; //! The kd-tree index for the user to call its methods as usual with any other FLANN index.
1200 
1201  /// Constructor: takes a const ref to the matrix object with the data points
1202  KDTreeEigenMatrixAdaptor(const int dimensionality, const MatrixType &mat, const int leaf_max_size = 10) : m_data_matrix(mat)
1203  {
1204  const size_t dims = mat.cols();
1205  if (DIM>0 && static_cast<int>(dims)!=DIM)
1206  throw std::runtime_error("Data set dimensionality does not match the 'DIM' template argument");
1207  index = new index_t( dims, *this /* adaptor */, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size, dims ) );
1208  index->buildIndex();
1209  }
1210 
1212  delete index;
1213  }
1214 
1215  const MatrixType &m_data_matrix;
1216 
1217  /** Query for the \a num_closest closest points to a given point (entered as query_point[0:dim-1]).
1218  * Note that this is a short-cut method for index->findNeighbors().
1219  * The user can also call index->... methods as desired.
1220  * \note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface.
1221  */
1222  inline void query(const num_t *query_point, const size_t num_closest, IndexType *out_indices, num_t *out_distances_sq, const int nChecks_IGNORED = 10) const
1223  {
1225  resultSet.init(out_indices, out_distances_sq);
1226  index->findNeighbors(resultSet, query_point, nanoflann::SearchParams());
1227  }
1228 
1229  /** @name Interface expected by KDTreeSingleIndexAdaptor
1230  * @{ */
1231 
1232  const self_t & derived() const {
1233  return *this;
1234  }
1236  return *this;
1237  }
1238 
1239  // Must return the number of data points
1240  inline size_t kdtree_get_point_count() const {
1241  return m_data_matrix.rows();
1242  }
1243 
1244  // Returns the distance between the vector "p1[0:size-1]" and the data point with index "idx_p2" stored in the class:
1245  inline num_t kdtree_distance(const num_t *p1, const size_t idx_p2,size_t size) const
1246  {
1247  num_t s=0;
1248  for (size_t i=0; i<size; i++) {
1249  const num_t d= p1[i]-m_data_matrix.coeff(idx_p2,i);
1250  s+=d*d;
1251  }
1252  return s;
1253  }
1254 
1255  // Returns the dim'th component of the idx'th point in the class:
1256  inline num_t kdtree_get_pt(const size_t idx, int dim) const {
1257  return m_data_matrix.coeff(idx,dim);
1258  }
1259 
1260  // Optional bounding-box computation: return false to default to a standard bbox computation loop.
1261  // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again.
1262  // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds)
1263  template <class BBOX>
1264  bool kdtree_get_bbox(BBOX &bb) const {
1265  return false;
1266  }
1267 
1268  /** @} */
1269 
1270  }; // end of KDTreeEigenMatrixAdaptor
1271  /** @} */
1272 
1273 /** @} */ // end of grouping
1274 } // end of NS
1275 
1276 
1277 #endif /* NANOFLANN_HPP_ */



Page generated by Doxygen 1.8.3 for MRPT 0.9.6 SVN: at Fri Feb 15 22:05:02 EST 2013