Main MRPT website > C++ reference
MRPT logo
nanoflann.hpp
Go to the documentation of this file.
00001 /***********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  * Copyright 2008-2009  Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
00005  * Copyright 2008-2009  David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
00006  * Copyright 2011 Jose Luis Blanco (joseluisblancoc@gmail.com).
00007  *   All rights reserved.
00008  *
00009  * THE BSD LICENSE
00010  *
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions
00013  * are met:
00014  *
00015  * 1. Redistributions of source code must retain the above copyright
00016  *    notice, this list of conditions and the following disclaimer.
00017  * 2. Redistributions in binary form must reproduce the above copyright
00018  *    notice, this list of conditions and the following disclaimer in the
00019  *    documentation and/or other materials provided with the distribution.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00022  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00023  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00024  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00026  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00027  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00028  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00029  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00030  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  *************************************************************************/
00032 
00033 #ifndef  NANOFLANN_HPP_
00034 #define  NANOFLANN_HPP_
00035 
00036 #include <vector>
00037 #include <string>
00038 #include <cassert>
00039 #include <map>
00040 #include <algorithm>
00041 #include <stdexcept>
00042 #include <limits>
00043 
00044 #include <cassert>
00045 #include <cstring>
00046 #include <cstdio>
00047 #include <cmath>
00048 
00049 
00050 namespace nanoflann
00051 {
00052 /** @addtogroup nanoflann_grp nanoflann C++ library for ANN
00053   *  @{ */
00054 
00055         /** Library version: 0xMmP (M=Major,m=minor,P=path) */
00056         #define NANOFLANN_VERSION 0x101
00057 
00058         /** @addtogroup result_sets_grp Result set classes
00059           *  @{ */
00060         template <typename DistanceType>
00061         class KNNResultSet
00062         {
00063                 int* indices;
00064                 DistanceType* dists;
00065                 int capacity;
00066                 int count;
00067 
00068         public:
00069                 inline KNNResultSet(int capacity_) : capacity(capacity_), count(0)
00070                 {
00071                 }
00072 
00073                 inline void init(int* indices_, DistanceType* dists_)
00074                 {
00075                         indices = indices_;
00076                         dists = dists_;
00077                         count = 0;
00078                         dists[capacity-1] = (std::numeric_limits<DistanceType>::max)();
00079                 }
00080 
00081                 inline size_t size() const
00082                 {
00083                         return count;
00084                 }
00085 
00086                 inline bool full() const
00087                 {
00088                         return count == capacity;
00089                 }
00090 
00091 
00092                 inline void addPoint(DistanceType dist, int index)
00093                 {
00094                         int i;
00095                         for (i=count; i>0; --i) {
00096 #ifdef NANOFLANN_FIRST_MATCH
00097                                 if ( (dists[i-1]>dist) || ((dist==dists[i-1])&&(indices[i-1]>index)) ) {
00098 #else
00099                                 if (dists[i-1]>dist) {
00100 #endif
00101                                         if (i<capacity) {
00102                                                 dists[i] = dists[i-1];
00103                                                 indices[i] = indices[i-1];
00104                                         }
00105                                 }
00106                                 else break;
00107                         }
00108                         if (i<capacity) {
00109                                 dists[i] = dist;
00110                                 indices[i] = index;
00111                         }
00112                         if (count<capacity) count++;
00113                 }
00114 
00115                 inline DistanceType worstDist() const
00116                 {
00117                         return dists[capacity-1];
00118                 }
00119         };
00120 
00121 
00122         /**
00123          * A result-set class used when performing a radius based search.
00124          */
00125         template <typename DistanceType>
00126         class RadiusResultSet
00127         {
00128         public:
00129                 const DistanceType radius;
00130 
00131                 std::vector<std::pair<int,DistanceType> >& m_indices_dists;
00132 
00133                 inline RadiusResultSet(DistanceType radius_, std::vector<std::pair<int,DistanceType> >& indices_dists) : radius(radius_), m_indices_dists(indices_dists)
00134                 {
00135                         init();
00136                 }
00137 
00138                 inline ~RadiusResultSet() { }
00139 
00140                 inline void init() { m_indices_dists.clear(); }
00141 
00142                 inline size_t size() const { return m_indices_dists.size(); }
00143 
00144                 inline bool full() const { return true; }
00145 
00146                 inline void addPoint(DistanceType dist, int index)
00147                 {
00148                         if (dist<radius)
00149                                 m_indices_dists.push_back(std::make_pair<int,DistanceType>(index,dist));
00150                 }
00151 
00152                 inline DistanceType worstDist() const { return radius; }
00153         };
00154 
00155         /** operator "<" for std::sort() */
00156         template <typename DistanceType>
00157         struct IndexDist_Sorter
00158         {
00159                 inline bool operator()(const std::pair<int,DistanceType> &p1, const std::pair<int,DistanceType> &p2) const
00160                 {
00161                         return p1.second < p2.second;
00162                 }
00163         };
00164 
00165         /** @} */
00166 
00167 
00168         /** @addtogroup loadsave_grp Load/save auxiliary functions
00169           * @{ */
00170         template<typename T>
00171         void save_value(FILE* stream, const T& value, int count = 1)
00172         {
00173                 fwrite(&value, sizeof(value),count, stream);
00174         }
00175 
00176         template<typename T>
00177         void save_value(FILE* stream, const std::vector<T>& value)
00178         {
00179                 size_t size = value.size();
00180                 fwrite(&size, sizeof(size_t), 1, stream);
00181                 fwrite(&value[0], sizeof(T), size, stream);
00182         }
00183 
00184         template<typename T>
00185         void load_value(FILE* stream, T& value, int count = 1)
00186         {
00187                 int read_cnt = fread(&value, sizeof(value), count, stream);
00188                 if (read_cnt != count) {
00189                         throw std::runtime_error("Cannot read from file");
00190                 }
00191         }
00192 
00193 
00194         template<typename T>
00195         void load_value(FILE* stream, std::vector<T>& value)
00196         {
00197                 size_t size;
00198                 int read_cnt = fread(&size, sizeof(size_t), 1, stream);
00199                 if (read_cnt!=1) {
00200                         throw std::runtime_error("Cannot read from file");
00201                 }
00202                 value.resize(size);
00203                 read_cnt = fread(&value[0], sizeof(T), size, stream);
00204                 if (read_cnt!=int(size)) {
00205                         throw std::runtime_error("Cannot read from file");
00206                 }
00207         }
00208         /** @} */
00209 
00210 
00211         /** @addtogroup metric_grp Metric (distance) classes
00212           * @{ */
00213 
00214         template<typename T> inline T abs(T x) { return (x<0) ? -x : x; }
00215         template<> inline int abs<int>(int x) { return ::abs(x); }
00216         template<> inline float abs<float>(float x) { return fabsf(x); }
00217         template<> inline double abs<double>(double x) { return fabs(x); }
00218         template<> inline long double abs<long double>(long double x) { return fabsl(x); }
00219 
00220         /** Manhattan distance functor (generic version, optimized for high-dimensionality data sets).
00221           *  Corresponding distance traits: nanoflann::metric_L1
00222          */
00223         template<class T, class DataSource>
00224         struct L1_Adaptor
00225         {
00226                 typedef T ElementType;
00227                 typedef T DistanceType;
00228                 typedef T ResultType;
00229 
00230                 const DataSource &data_source;
00231 
00232                 L1_Adaptor(const DataSource &_data_source) : data_source(_data_source) { }
00233 
00234                 inline T operator()(const T* a, const size_t b_idx, size_t size, ResultType worst_dist = -1) const
00235                 {
00236                         ResultType result = ResultType();
00237                         const T* last = a + size;
00238                         const T* lastgroup = last - 3;
00239                         size_t d = 0;
00240 
00241                         /* Process 4 items with each loop for efficiency. */
00242                         while (a < lastgroup) {
00243                                 const ResultType diff0 = nanoflann::abs(a[0] - data_source.kdtree_get_pt(b_idx,d++));
00244                                 const ResultType diff1 = nanoflann::abs(a[1] - data_source.kdtree_get_pt(b_idx,d++));
00245                                 const ResultType diff2 = nanoflann::abs(a[2] - data_source.kdtree_get_pt(b_idx,d++));
00246                                 const ResultType diff3 = nanoflann::abs(a[3] - data_source.kdtree_get_pt(b_idx,d++));
00247                                 result += diff0 + diff1 + diff2 + diff3;
00248                                 a += 4;
00249                                 if ((worst_dist>0)&&(result>worst_dist)) {
00250                                         return result;
00251                                 }
00252                         }
00253                         /* Process last 0-3 components.  Not needed for standard vector lengths. */
00254                         while (a < last) {
00255                                 result += nanoflann::abs( *a++ - data_source.kdtree_get_pt(b_idx,d++) );
00256                         }
00257                         return result;
00258                 }
00259 
00260                 template <typename U, typename V>
00261                 inline T accum_dist(const U a, const V b, int dim) const
00262                 {
00263                         return (a-b)*(a-b);
00264                 }
00265         };
00266 
00267         /** Squared Euclidean distance functor (generic version, optimized for high-dimensionality data sets).
00268           *  Corresponding distance traits: nanoflann::metric_L2
00269          */
00270         template<class T, class DataSource>
00271         struct L2_Adaptor
00272         {
00273                 typedef T ElementType;
00274                 typedef T DistanceType;
00275                 typedef T ResultType;
00276 
00277                 const DataSource &data_source;
00278 
00279                 L2_Adaptor(const DataSource &_data_source) : data_source(_data_source) { }
00280 
00281                 inline T operator()(const T* a, const size_t b_idx, size_t size, ResultType worst_dist = -1) const
00282                 {
00283                         ResultType result = ResultType();
00284                         const T* last = a + size;
00285                         const T* lastgroup = last - 3;
00286                         size_t d = 0;
00287 
00288                         /* Process 4 items with each loop for efficiency. */
00289                         while (a < lastgroup) {
00290                                 const ResultType diff0 = a[0] - data_source.kdtree_get_pt(b_idx,d++);
00291                                 const ResultType diff1 = a[1] - data_source.kdtree_get_pt(b_idx,d++);
00292                                 const ResultType diff2 = a[2] - data_source.kdtree_get_pt(b_idx,d++);
00293                                 const ResultType diff3 = a[3] - data_source.kdtree_get_pt(b_idx,d++);
00294                                 result += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;
00295                                 a += 4;
00296                                 if ((worst_dist>0)&&(result>worst_dist)) {
00297                                         return result;
00298                                 }
00299                         }
00300                         /* Process last 0-3 components.  Not needed for standard vector lengths. */
00301                         while (a < last) {
00302                                 const ResultType diff0 = *a++ - data_source.kdtree_get_pt(b_idx,d++);
00303                                 result += diff0 * diff0;
00304                         }
00305                         return result;
00306                 }
00307 
00308                 template <typename U, typename V>
00309                 inline T accum_dist(const U a, const V b, int dim) const
00310                 {
00311                         return (a-b)*(a-b);
00312                 }
00313         };
00314 
00315         /** Squared Euclidean distance functor (suitable for low-dimensionality datasets, like 2D or 3D point clouds)
00316           *  Corresponding distance traits: nanoflann::metric_L2_Simple
00317          */
00318         template<class T, class DataSource>
00319         struct L2_Simple_Adaptor
00320         {
00321                 typedef T ElementType;
00322                 typedef T DistanceType;
00323                 typedef T ResultType;
00324 
00325                 const DataSource &data_source;
00326 
00327                 L2_Simple_Adaptor(const DataSource &_data_source) : data_source(_data_source) { }
00328 
00329                 inline T operator()(const T* a, const size_t b_idx, size_t size) const {
00330                         return data_source.kdtree_distance(a,b_idx,size);
00331                 }
00332 
00333                 template <typename U, typename V>
00334                 inline T accum_dist(const U a, const V b, int dim) const
00335                 {
00336                         return (a-b)*(a-b);
00337                 }
00338         };
00339 
00340         /** Metaprogramming helper traits class for the L1 (Manhattan) metric */
00341         struct metric_L1 {
00342                 template<class T, class DataSource>
00343                 struct traits {
00344                         typedef L1_Adaptor<T,DataSource> distance_t;
00345                 };
00346         };
00347         /** Metaprogramming helper traits class for the L2 (Euclidean) metric */
00348         struct metric_L2 {
00349                 template<class T, class DataSource>
00350                 struct traits {
00351                         typedef L2_Adaptor<T,DataSource> distance_t;
00352                 };
00353         };
00354         /** Metaprogramming helper traits class for the L2_simple (Euclidean) metric */
00355         struct metric_L2_Simple {
00356                 template<class T, class DataSource>
00357                 struct traits {
00358                         typedef L2_Simple_Adaptor<T,DataSource> distance_t;
00359                 };
00360         };
00361 
00362         /** @} */
00363 
00364 
00365 
00366         /** @addtogroup param_grp Parameter structs
00367           * @{ */
00368 
00369         /**  Parameters
00370           */
00371         struct KDTreeSingleIndexAdaptorParams
00372         {
00373                 KDTreeSingleIndexAdaptorParams(int leaf_max_size_ = 10, int dim_ = -1) :
00374                         leaf_max_size(leaf_max_size_), dim(dim_)
00375                 {}
00376 
00377                 int leaf_max_size;
00378                 int dim;
00379         };
00380 
00381         /** Search options for KDTreeSingleIndexAdaptor::findNeighbors() */
00382         struct SearchParams
00383         {
00384                 SearchParams(int checks_ = 32, float eps_ = 0, bool sorted_ = true ) :
00385                         checks(checks_), eps(eps_), sorted(sorted_) {}
00386 
00387                 int checks;  //!< how many leafs to visit when searching for neighbours (-1 for unlimited)
00388                 float eps;  //!< search for eps-approximate neighbours (default: 0)
00389                 bool sorted; //!< only for radius search, require neighbours sorted by distance (default: true)
00390         };
00391         /** @} */
00392 
00393 
00394         /** @addtogroup memalloc_grp Memory allocation
00395           * @{ */
00396 
00397         /**
00398          * Allocates (using C's malloc) a generic type T.
00399          *
00400          * Params:
00401          *     count = number of instances to allocate.
00402          * Returns: pointer (of type T*) to memory buffer
00403          */
00404         template <typename T>
00405         T* allocate(size_t count = 1)
00406         {
00407                 T* mem = (T*) ::malloc(sizeof(T)*count);
00408                 return mem;
00409         }
00410 
00411 
00412         /**
00413          * Pooled storage allocator
00414          *
00415          * The following routines allow for the efficient allocation of storage in
00416          * small chunks from a specified pool.  Rather than allowing each structure
00417          * to be freed individually, an entire pool of storage is freed at once.
00418          * This method has two advantages over just using malloc() and free().  First,
00419          * it is far more efficient for allocating small objects, as there is
00420          * no overhead for remembering all the information needed to free each
00421          * object or consolidating fragmented memory.  Second, the decision about
00422          * how long to keep an object is made at the time of allocation, and there
00423          * is no need to track down all the objects to free them.
00424          *
00425          */
00426 
00427         const size_t     WORDSIZE=16;
00428         const  size_t     BLOCKSIZE=8192;
00429 
00430         class PooledAllocator
00431         {
00432                 /* We maintain memory alignment to word boundaries by requiring that all
00433                     allocations be in multiples of the machine wordsize.  */
00434                 /* Size of machine word in bytes.  Must be power of 2. */
00435                 /* Minimum number of bytes requested at a time from     the system.  Must be multiple of WORDSIZE. */
00436 
00437 
00438                 int     remaining;  /* Number of bytes left in current block of storage. */
00439                 void*   base;     /* Pointer to base of current block of storage. */
00440                 void*   loc;      /* Current location in block to next allocate memory. */
00441                 int     blocksize;
00442 
00443 
00444         public:
00445                 int     usedMemory;
00446                 int     wastedMemory;
00447 
00448                 /**
00449                     Default constructor. Initializes a new pool.
00450                  */
00451                 PooledAllocator(int blocksize = BLOCKSIZE)
00452                 {
00453                         this->blocksize = blocksize;
00454                         remaining = 0;
00455                         base = NULL;
00456 
00457                         usedMemory = 0;
00458                         wastedMemory = 0;
00459                 }
00460 
00461                 /**
00462                  * Destructor. Frees all the memory allocated in this pool.
00463                  */
00464                 ~PooledAllocator()
00465                 {
00466                         void* prev;
00467 
00468                         while (base != NULL) {
00469                                 prev = *((void**) base); /* Get pointer to prev block. */
00470                                 ::free(base);
00471                                 base = prev;
00472                         }
00473                 }
00474 
00475                 /**
00476                  * Returns a pointer to a piece of new memory of the given size in bytes
00477                  * allocated from the pool.
00478                  */
00479                 void* malloc(int size)
00480                 {
00481                         int blocksize;
00482 
00483                         /* Round size up to a multiple of wordsize.  The following expression
00484                             only works for WORDSIZE that is a power of 2, by masking last bits of
00485                             incremented size to zero.
00486                          */
00487                         size = (size + (WORDSIZE - 1)) & ~(WORDSIZE - 1);
00488 
00489                         /* Check whether a new block must be allocated.  Note that the first word
00490                             of a block is reserved for a pointer to the previous block.
00491                          */
00492                         if (size > remaining) {
00493 
00494                                 wastedMemory += remaining;
00495 
00496                                 /* Allocate new storage. */
00497                                 blocksize = (size + sizeof(void*) + (WORDSIZE-1) > BLOCKSIZE) ?
00498                                                         size + sizeof(void*) + (WORDSIZE-1) : BLOCKSIZE;
00499 
00500                                 // use the standard C malloc to allocate memory
00501                                 void* m = ::malloc(blocksize);
00502                                 if (!m) {
00503                                         fprintf(stderr,"Failed to allocate memory.\n");
00504                                         return NULL;
00505                                 }
00506 
00507                                 /* Fill first word of new block with pointer to previous block. */
00508                                 ((void**) m)[0] = base;
00509                                 base = m;
00510 
00511                                 int shift = 0;
00512                                 //int shift = (WORDSIZE - ( (((size_t)m) + sizeof(void*)) & (WORDSIZE-1))) & (WORDSIZE-1);
00513 
00514                                 remaining = blocksize - sizeof(void*) - shift;
00515                                 loc = ((char*)m + sizeof(void*) + shift);
00516                         }
00517                         void* rloc = loc;
00518                         loc = (char*)loc + size;
00519                         remaining -= size;
00520 
00521                         usedMemory += size;
00522 
00523                         return rloc;
00524                 }
00525 
00526                 /**
00527                  * Allocates (using this pool) a generic type T.
00528                  *
00529                  * Params:
00530                  *     count = number of instances to allocate.
00531                  * Returns: pointer (of type T*) to memory buffer
00532                  */
00533                 template <typename T>
00534                 T* allocate(size_t count = 1)
00535                 {
00536                         T* mem = (T*) this->malloc(static_cast<int>( sizeof(T)*count ));
00537                         return mem;
00538                 }
00539 
00540         };
00541         /** @} */
00542 
00543 
00544         /** @addtogroup kdtrees_grp KD-tree classes and adaptors
00545           * @{ */
00546 
00547         /** kd-tree index
00548          *
00549          * Contains the k-d trees and other information for indexing a set of points
00550          * for nearest-neighbor matching.
00551          *
00552          *  The class "DatasetAdaptor" must provide the following interface (can be non-virtual, inlined methods):
00553          *
00554          *  \code
00555          *   // Must return the number of data points
00556          *   inline size_t kdtree_get_point_count() const { ... }
00557          *
00558          *   // 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:
00559          *   inline float kdtree_distance(const float *p1, const size_t idx_p2,size_t size) const { ... }
00560          *
00561          *   // Must return the dim'th component of the idx'th point in the class:
00562          *   inline num_t kdtree_get_pt(const size_t idx, int dim) const { ... }
00563          *
00564          *   // Optional bounding-box computation: return false to default to a standard bbox computation loop.
00565          *   //   Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again.
00566          *   //   Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds)
00567          *   template <class BBOX>
00568          *   bool kdtree_get_bbox(BBOX &bb) const
00569          *   {
00570          *      bb[0].low = ...; bb[0].high = ...;  // 0th dimension limits
00571          *      bb[1].low = ...; bb[1].high = ...;  // 1st dimension limits
00572          *      ...
00573          *      return true;
00574          *   }
00575          *
00576          *  \endcode
00577          */
00578         template <typename Distance, class DatasetAdaptor,int DIM = -1>
00579         class KDTreeSingleIndexAdaptor
00580         {
00581                 typedef typename Distance::ElementType ElementType;
00582                 typedef typename Distance::ResultType DistanceType;
00583 
00584                 /**
00585                  *  Array of indices to vectors in the dataset.
00586                  */
00587                 std::vector<int> vind;
00588 
00589                 int leaf_max_size_;
00590 
00591 
00592                 /**
00593                  * The dataset used by this index
00594                  */
00595                 const DatasetAdaptor &dataset; //!< The source of our data
00596 
00597                 const KDTreeSingleIndexAdaptorParams index_params;
00598 
00599                 int size_;
00600                 int dim;
00601 
00602 
00603                 /*--------------------- Internal Data Structures --------------------------*/
00604                 struct Node
00605                 {
00606                         union {
00607                                 struct
00608                                 {
00609                                         /**
00610                                          * Indices of points in leaf node
00611                                          */
00612                                         int left, right;
00613                                 } lr;
00614                                 struct
00615                                 {
00616                                         /**
00617                                          * Dimension used for subdivision.
00618                                          */
00619                                         int divfeat;
00620                                         /**
00621                                          * The values used for subdivision.
00622                                          */
00623                                         DistanceType divlow, divhigh;
00624                                 } sub;
00625                         };
00626                         /**
00627                          * The child nodes.
00628                          */
00629                         Node* child1, * child2;
00630                 };
00631                 typedef Node* NodePtr;
00632 
00633 
00634                 struct Interval
00635                 {
00636                         ElementType low, high;
00637                 };
00638 
00639                 typedef std::vector<Interval> BoundingBox;
00640 
00641 
00642                 /** This record represents a branch point when finding neighbors in
00643                         the tree.  It contains a record of the minimum distance to the query
00644                         point, as well as the node at which the search resumes.
00645                  */
00646                 template <typename T, typename DistanceType>
00647                 struct BranchStruct
00648                 {
00649                         T node;           /* Tree node at which search resumes */
00650                         DistanceType mindist;     /* Minimum distance to query for all nodes below. */
00651 
00652                         BranchStruct() {}
00653                         BranchStruct(const T& aNode, DistanceType dist) : node(aNode), mindist(dist) {}
00654 
00655                         bool operator<(const BranchStruct<T, DistanceType>& rhs) const
00656                         {
00657                                 return mindist<rhs.mindist;
00658                         }
00659                 };
00660 
00661                 /**
00662                  * Array of k-d trees used to find neighbours.
00663                  */
00664                 NodePtr root_node;
00665                 typedef BranchStruct<NodePtr, DistanceType> BranchSt;
00666                 typedef BranchSt* Branch;
00667 
00668                 BoundingBox root_bbox;
00669 
00670                 /**
00671                  * Pooled memory allocator.
00672                  *
00673                  * Using a pooled memory allocator is more efficient
00674                  * than allocating memory directly when there is a large
00675                  * number small of memory allocations.
00676                  */
00677                 PooledAllocator pool;
00678 
00679         public:
00680 
00681                 Distance distance;
00682 
00683                 /**
00684                  * KDTree constructor
00685                  *
00686                  * Params:
00687                  *          inputData = dataset with the input features
00688                  *          params = parameters passed to the kdtree algorithm
00689                  */
00690                 KDTreeSingleIndexAdaptor(const int dimensionality, const DatasetAdaptor& inputData, const KDTreeSingleIndexAdaptorParams& params = KDTreeSingleIndexAdaptorParams() ) :
00691                         dataset(inputData), index_params(params), distance(inputData)
00692                 {
00693                         size_ = static_cast<int>(dataset.kdtree_get_point_count());
00694                         dim = dimensionality;
00695                         if (DIM>0) dim=DIM;
00696                         else {
00697                                 if (params.dim>0) dim = params.dim;
00698                         }
00699                         leaf_max_size_ = params.leaf_max_size;
00700 
00701                         // Create a permutable array of indices to the input vectors.
00702                         vind.resize(size_);
00703                         for (int i = 0; i < size_; i++) {
00704                                 vind[i] = i;
00705                         }
00706                 }
00707 
00708                 /**
00709                  * Standard destructor
00710                  */
00711                 ~KDTreeSingleIndexAdaptor()
00712                 {
00713                 }
00714 
00715                 /**
00716                  * Builds the index
00717                  */
00718                 void buildIndex()
00719                 {
00720                         computeBoundingBox(root_bbox);
00721                         root_node = divideTree(0, size_, root_bbox );   // construct the tree
00722                 }
00723 
00724                 /**
00725                  *  Returns size of index.
00726                  */
00727                 size_t size() const
00728                 {
00729                         return size_;
00730                 }
00731 
00732                 /**
00733                  * Returns the length of an index feature.
00734                  */
00735                 size_t veclen() const
00736                 {
00737                         return (DIM>0 ? DIM : dim);
00738                 }
00739 
00740                 /**
00741                  * Computes the inde memory usage
00742                  * Returns: memory used by the index
00743                  */
00744                 int usedMemory() const
00745                 {
00746                         return pool.usedMemory+pool.wastedMemory+dataset.kdtree_get_point_count()*sizeof(int);  // pool memory and vind array memory
00747                 }
00748 
00749                 /** \name Query methods
00750                   * @{ */
00751 
00752                 /**
00753                  * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored inside
00754                  * the result object.
00755                  *
00756                  * Params:
00757                  *     result = the result object in which the indices of the nearest-neighbors are stored
00758                  *     vec = the vector for which to search the nearest neighbors
00759                  *     maxCheck = the maximum number of restarts (in a best-bin-first manner)
00760                  *
00761                  * \tparam RESULTSET Should be any ResultSet<DistanceType>
00762                  * \sa knnSearch, radiusSearch
00763                  */
00764                 template <typename RESULTSET>
00765                 void findNeighbors(RESULTSET& result, const ElementType* vec, const SearchParams& searchParams) const
00766                 {
00767                         float epsError = 1+searchParams.eps;
00768 
00769                         std::vector<DistanceType> dists( (DIM>0 ? DIM : dim) ,0);
00770                         DistanceType distsq = computeInitialDistances(vec, dists);
00771                         int count_leaf = 0;
00772                         searchLevel(result, vec, root_node, distsq, dists, epsError,count_leaf);
00773                 }
00774 
00775                 /**
00776                  * Find the "num_closest" nearest neighbors to the \a query_point[0:dim-1]. Their indices are stored inside
00777                  * the result object.
00778                  *  \sa radiusSearch, findNeighbors
00779                  */
00780                 inline void knnSearch(const ElementType *query_point, int num_closest, int *out_indices, ElementType *out_distances_sq, const int nChecks = 10) const
00781                 {
00782                         nanoflann::KNNResultSet<ElementType> resultSet(num_closest);
00783                         resultSet.init(out_indices, out_distances_sq);
00784                         this->findNeighbors(resultSet, query_point, nanoflann::SearchParams(nChecks));
00785                 }
00786 
00787                 /**
00788                  * Find all the neighbors to \a query_point[0:dim-1] within a maximum radius.
00789                  *  The output is given as a vector of pairs, of which the first element is a point index and the second the corresponding distance.
00790                  *  Previous contents of \a IndicesDists are cleared.
00791                  *
00792                  *  If searchParams.sorted==true, the output list is sorted by ascending distances.
00793                  *
00794                  *  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.
00795                  *
00796                  *  \sa knnSearch, findNeighbors
00797                  * \return The number of points within the given radius (i.e. indices.size() or dists.size() )
00798                  */
00799                 size_t radiusSearch(const ElementType *query_point,const DistanceType radius, std::vector<std::pair<int,DistanceType> >& IndicesDists, const SearchParams& searchParams) const
00800                 {
00801                         RadiusResultSet<DistanceType> resultSet(radius,IndicesDists);
00802                         this->findNeighbors(resultSet, query_point, searchParams);
00803 
00804                         if (searchParams.sorted)
00805                                 std::sort(IndicesDists.begin(),IndicesDists.end(), IndexDist_Sorter<DistanceType>() );
00806 
00807                         return resultSet.size();
00808                 }
00809 
00810                 /** @} */
00811 
00812         private:
00813 
00814                 /// Helper accessor to the dataset points:
00815                 inline ElementType dataset_get(size_t idx, int component) const {
00816                         return dataset.kdtree_get_pt(idx,component);
00817                 }
00818 
00819 
00820                 void save_tree(FILE* stream, NodePtr tree)
00821                 {
00822                         save_value(stream, *tree);
00823                         if (tree->child1!=NULL) {
00824                                 save_tree(stream, tree->child1);
00825                         }
00826                         if (tree->child2!=NULL) {
00827                                 save_tree(stream, tree->child2);
00828                         }
00829                 }
00830 
00831 
00832                 void load_tree(FILE* stream, NodePtr& tree)
00833                 {
00834                         tree = pool.allocate<Node>();
00835                         load_value(stream, *tree);
00836                         if (tree->child1!=NULL) {
00837                                 load_tree(stream, tree->child1);
00838                         }
00839                         if (tree->child2!=NULL) {
00840                                 load_tree(stream, tree->child2);
00841                         }
00842                 }
00843 
00844 
00845                 void computeBoundingBox(BoundingBox& bbox)
00846                 {
00847                         bbox.resize((DIM>0 ? DIM : dim));
00848                         if (dataset.kdtree_get_bbox(bbox))
00849                         {
00850                                 // Done! It was implemented in derived class
00851                         }
00852                         else
00853                         {
00854                                 for (int i=0; i<(DIM>0 ? DIM : dim); ++i) {
00855                                         bbox[i].low =
00856                                                 bbox[i].high = dataset_get(0,i);
00857                                 }
00858                                 const size_t N = dataset.kdtree_get_point_count();
00859                                 for (size_t k=1; k<N; ++k) {
00860                                         for (int i=0; i<(DIM>0 ? DIM : dim); ++i) {
00861                                                 if (dataset_get(k,i)<bbox[i].low) bbox[i].low = dataset_get(k,i);
00862                                                 if (dataset_get(k,i)>bbox[i].high) bbox[i].high = dataset_get(k,i);
00863                                         }
00864                                 }
00865                         }
00866                 }
00867 
00868 
00869                 /**
00870                  * Create a tree node that subdivides the list of vecs from vind[first]
00871                  * to vind[last].  The routine is called recursively on each sublist.
00872                  * Place a pointer to this new tree node in the location pTree.
00873                  *
00874                  * Params: pTree = the new node to create
00875                  *                  first = index of the first vector
00876                  *                  last = index of the last vector
00877                  */
00878                 NodePtr divideTree(int left, int right, BoundingBox& bbox)
00879                 {
00880                         NodePtr node = pool.allocate<Node>(); // allocate memory
00881 
00882                         /* If too few exemplars remain, then make this a leaf node. */
00883                         if ( (right-left) <= leaf_max_size_) {
00884                                 node->child1 = node->child2 = NULL;    /* Mark as leaf node. */
00885                                 node->lr.left = left;
00886                                 node->lr.right = right;
00887 
00888                                 // compute bounding-box of leaf points
00889                                 for (int i=0; i<(DIM>0 ? DIM : dim); ++i) {
00890                                         bbox[i].low = dataset_get(vind[left],i);
00891                                         bbox[i].high = dataset_get(vind[left],i);
00892                                 }
00893                                 for (int k=left+1; k<right; ++k) {
00894                                         for (int i=0; i<(DIM>0 ? DIM : dim); ++i) {
00895                                                 if (bbox[i].low>dataset_get(vind[k],i)) bbox[i].low=dataset_get(vind[k],i);
00896                                                 if (bbox[i].high<dataset_get(vind[k],i)) bbox[i].high=dataset_get(vind[k],i);
00897                                         }
00898                                 }
00899                         }
00900                         else {
00901                                 int idx;
00902                                 int cutfeat;
00903                                 DistanceType cutval;
00904                                 middleSplit_(&vind[0]+left, right-left, idx, cutfeat, cutval, bbox);
00905 
00906                                 node->sub.divfeat = cutfeat;
00907 
00908                                 BoundingBox left_bbox(bbox);
00909                                 left_bbox[cutfeat].high = cutval;
00910                                 node->child1 = divideTree(left, left+idx, left_bbox);
00911 
00912                                 BoundingBox right_bbox(bbox);
00913                                 right_bbox[cutfeat].low = cutval;
00914                                 node->child2 = divideTree(left+idx, right, right_bbox);
00915 
00916                                 node->sub.divlow = left_bbox[cutfeat].high;
00917                                 node->sub.divhigh = right_bbox[cutfeat].low;
00918 
00919                                 for (int i=0; i<(DIM>0 ? DIM : dim); ++i) {
00920                                         bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low);
00921                                         bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high);
00922                                 }
00923                         }
00924 
00925                         return node;
00926                 }
00927 
00928                 void computeMinMax(int* ind, int count, int element, ElementType& min_elem, ElementType& max_elem)
00929                 {
00930                         min_elem = dataset_get(ind[0],element);
00931                         max_elem = dataset_get(ind[0],element);
00932                         for (int i=1; i<count; ++i) {
00933                                 ElementType val = dataset_get(ind[i],element);
00934                                 if (val<min_elem) min_elem = val;
00935                                 if (val>max_elem) max_elem = val;
00936                         }
00937                 }
00938 
00939                 void middleSplit(int* ind, int count, int& index, int& cutfeat, DistanceType& cutval, const BoundingBox& bbox)
00940                 {
00941                         // find the largest span from the approximate bounding box
00942                         ElementType max_span = bbox[0].high-bbox[0].low;
00943                         cutfeat = 0;
00944                         cutval = (bbox[0].high+bbox[0].low)/2;
00945                         for (size_t i=1; i<(DIM>0 ? DIM : dim); ++i) {
00946                                 ElementType span = bbox[i].low-bbox[i].low;
00947                                 if (span>max_span) {
00948                                         max_span = span;
00949                                         cutfeat = i;
00950                                         cutval = (bbox[i].high+bbox[i].low)/2;
00951                                 }
00952                         }
00953 
00954                         // compute exact span on the found dimension
00955                         ElementType min_elem, max_elem;
00956                         computeMinMax(ind, count, cutfeat, min_elem, max_elem);
00957                         cutval = (min_elem+max_elem)/2;
00958                         max_span = max_elem - min_elem;
00959 
00960                         // check if a dimension of a largest span exists
00961                         size_t k = cutfeat;
00962                         for (size_t i=0; i<(DIM>0 ? DIM : dim); ++i) {
00963                                 if (i==k) continue;
00964                                 ElementType span = bbox[i].high-bbox[i].low;
00965                                 if (span>max_span) {
00966                                         computeMinMax(ind, count, i, min_elem, max_elem);
00967                                         span = max_elem - min_elem;
00968                                         if (span>max_span) {
00969                                                 max_span = span;
00970                                                 cutfeat = i;
00971                                                 cutval = (min_elem+max_elem)/2;
00972                                         }
00973                                 }
00974                         }
00975                         int lim1, lim2;
00976                         planeSplit(ind, count, cutfeat, cutval, lim1, lim2);
00977 
00978                         if (lim1>count/2) index = lim1;
00979                         else if (lim2<count/2) index = lim2;
00980                         else index = count/2;
00981                 }
00982 
00983 
00984                 void middleSplit_(int* ind, int count, int& index, int& cutfeat, DistanceType& cutval, const BoundingBox& bbox)
00985                 {
00986                         const DistanceType EPS=static_cast<DistanceType>(0.00001);
00987                         ElementType max_span = bbox[0].high-bbox[0].low;
00988                         for (int i=1; i<(DIM>0 ? DIM : dim); ++i) {
00989                                 ElementType span = bbox[i].high-bbox[i].low;
00990                                 if (span>max_span) {
00991                                         max_span = span;
00992                                 }
00993                         }
00994                         ElementType max_spread = -1;
00995                         cutfeat = 0;
00996                         for (int i=0; i<(DIM>0 ? DIM : dim); ++i) {
00997                                 ElementType span = bbox[i].high-bbox[i].low;
00998                                 if (span>(1-EPS)*max_span) {
00999                                         ElementType min_elem, max_elem;
01000                                         computeMinMax(ind, count, cutfeat, min_elem, max_elem);
01001                                         ElementType spread = max_elem-min_elem;;
01002                                         if (spread>max_spread) {
01003                                                 cutfeat = i;
01004                                                 max_spread = spread;
01005                                         }
01006                                 }
01007                         }
01008                         // split in the middle
01009                         DistanceType split_val = (bbox[cutfeat].low+bbox[cutfeat].high)/2;
01010                         ElementType min_elem, max_elem;
01011                         computeMinMax(ind, count, cutfeat, min_elem, max_elem);
01012 
01013                         if (split_val<min_elem) cutval = min_elem;
01014                         else if (split_val>max_elem) cutval = max_elem;
01015                         else cutval = split_val;
01016 
01017                         int lim1, lim2;
01018                         planeSplit(ind, count, cutfeat, cutval, lim1, lim2);
01019 
01020                         if (lim1>count/2) index = lim1;
01021                         else if (lim2<count/2) index = lim2;
01022                         else index = count/2;
01023                 }
01024 
01025 
01026                 /**
01027                  *  Subdivide the list of points by a plane perpendicular on axe corresponding
01028                  *  to the 'cutfeat' dimension at 'cutval' position.
01029                  *
01030                  *  On return:
01031                  *  dataset[ind[0..lim1-1]][cutfeat]<cutval
01032                  *  dataset[ind[lim1..lim2-1]][cutfeat]==cutval
01033                  *  dataset[ind[lim2..count]][cutfeat]>cutval
01034                  */
01035                 void planeSplit(int* ind, int count, int cutfeat, DistanceType cutval, int& lim1, int& lim2)
01036                 {
01037                         /* Move vector indices for left subtree to front of list. */
01038                         int left = 0;
01039                         int right = count-1;
01040                         for (;; ) {
01041                                 while (left<=right && dataset_get(ind[left],cutfeat)<cutval) ++left;
01042                                 while (left<=right && dataset_get(ind[right],cutfeat)>=cutval) --right;
01043                                 if (left>right) break;
01044                                 std::swap(ind[left], ind[right]);
01045                                 ++left;
01046                                 --right;
01047                         }
01048                         /* If either list is empty, it means that all remaining features
01049                          * are identical. Split in the middle to maintain a balanced tree.
01050                          */
01051                         lim1 = left;
01052                         right = count-1;
01053                         for (;; ) {
01054                                 while (left<=right && dataset_get(ind[left],cutfeat)<=cutval) ++left;
01055                                 while (left<=right && dataset_get(ind[right],cutfeat)>cutval) --right;
01056                                 if (left>right) break;
01057                                 std::swap(ind[left], ind[right]);
01058                                 ++left;
01059                                 --right;
01060                         }
01061                         lim2 = left;
01062                 }
01063 
01064                 DistanceType computeInitialDistances(const ElementType* vec, std::vector<DistanceType>& dists) const
01065                 {
01066                         DistanceType distsq = 0.0;
01067 
01068                         for (int i = 0; i < (DIM>0 ? DIM : dim); ++i) {
01069                                 if (vec[i] < root_bbox[i].low) {
01070                                         dists[i] = distance.accum_dist(vec[i], root_bbox[i].low, i);
01071                                         distsq += dists[i];
01072                                 }
01073                                 if (vec[i] > root_bbox[i].high) {
01074                                         dists[i] = distance.accum_dist(vec[i], root_bbox[i].high, i);
01075                                         distsq += dists[i];
01076                                 }
01077                         }
01078 
01079                         return distsq;
01080                 }
01081 
01082                 /**
01083                  * Performs an exact search in the tree starting from a node.
01084                  * \tparam RESULTSET Should be any ResultSet<DistanceType>
01085                  */
01086                 template <class RESULTSET>
01087                 void searchLevel(RESULTSET& result_set, const ElementType* vec, const NodePtr node, DistanceType mindistsq,
01088                                                  std::vector<DistanceType>& dists, const float epsError, int &count_leaf) const
01089                 {
01090                         /* If this is a leaf node, then do check and return. */
01091                         if ((node->child1 == NULL)&&(node->child2 == NULL)) {
01092                                 count_leaf += (node->lr.right-node->lr.left);
01093                                 DistanceType worst_dist = result_set.worstDist();
01094                                 for (int i=node->lr.left; i<node->lr.right; ++i) {
01095                                         int index = vind[i];// reorder... : i;
01096                                         DistanceType dist = distance(vec, index, (DIM>0 ? DIM : dim));
01097                                         if (dist<worst_dist) {
01098                                                 result_set.addPoint(dist,vind[i]);
01099                                         }
01100                                 }
01101                                 return;
01102                         }
01103 
01104                         /* Which child branch should be taken first? */
01105                         int idx = node->sub.divfeat;
01106                         ElementType val = vec[idx];
01107                         DistanceType diff1 = val - node->sub.divlow;
01108                         DistanceType diff2 = val - node->sub.divhigh;
01109 
01110                         NodePtr bestChild;
01111                         NodePtr otherChild;
01112                         DistanceType cut_dist;
01113                         if ((diff1+diff2)<0) {
01114                                 bestChild = node->child1;
01115                                 otherChild = node->child2;
01116                                 cut_dist = distance.accum_dist(val, node->sub.divhigh, idx);
01117                         }
01118                         else {
01119                                 bestChild = node->child2;
01120                                 otherChild = node->child1;
01121                                 cut_dist = distance.accum_dist( val, node->sub.divlow, idx);
01122                         }
01123 
01124                         /* Call recursively to search next level down. */
01125                         searchLevel(result_set, vec, bestChild, mindistsq, dists, epsError,count_leaf);
01126 
01127                         DistanceType dst = dists[idx];
01128                         mindistsq = mindistsq + cut_dist - dst;
01129                         dists[idx] = cut_dist;
01130                         if (mindistsq*epsError<=result_set.worstDist()) {
01131                                 searchLevel(result_set, vec, otherChild, mindistsq, dists, epsError,count_leaf);
01132                         }
01133                         dists[idx] = dst;
01134                 }
01135 
01136 
01137                 void saveIndex(FILE* stream)
01138                 {
01139                         save_value(stream, size_);
01140                         save_value(stream, dim);
01141                         save_value(stream, root_bbox);
01142                         save_value(stream, leaf_max_size_);
01143                         save_value(stream, vind);
01144                         save_tree(stream, root_node);
01145                 }
01146 
01147                 void loadIndex(FILE* stream)
01148                 {
01149                         load_value(stream, size_);
01150                         load_value(stream, dim);
01151                         load_value(stream, root_bbox);
01152                         load_value(stream, leaf_max_size_);
01153                         load_value(stream, vind);
01154                         load_tree(stream, root_node);
01155                 }
01156 
01157         };   // class KDTree
01158 
01159 
01160         /** A simple KD-tree adaptor for working with data directly stored in an Eigen Matrix, without duplicating the data storage.
01161           *  Each row in the matrix represents a point in the state space.
01162           *
01163           *  Example of usage:
01164           * \code
01165           *     Eigen::Matrix<num_t,Dynamic,Dynamic>  mat;
01166           *     // Fill out "mat"...
01167           *
01168           *     typedef KDTreeEigenMatrixAdaptor< Eigen::Matrix<num_t,Dynamic,Dynamic> >  my_kd_tree_t;
01169           *     const int max_leaf = 10;
01170           *     my_kd_tree_t   mat_index(dimdim, mat, max_leaf );
01171           *     mat_index.index->buildIndex();
01172           *     mat_index.index->...
01173           * \endcode
01174           *
01175           *  \tparam DIM If set to >0, it specifies a compile-time fixed dimensionality for the points in the data set, allowing more compiler optimizations.
01176           *  \tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc.
01177           */
01178         template <class MatrixType, int DIM = -1, class Distance = nanoflann::metric_L2>
01179         struct KDTreeEigenMatrixAdaptor
01180         {
01181                 typedef KDTreeEigenMatrixAdaptor<MatrixType,DIM,Distance> self_t;
01182                 typedef typename MatrixType::Scalar              num_t;
01183                 typedef typename Distance::template traits<num_t,self_t>::distance_t metric_t;
01184                 typedef KDTreeSingleIndexAdaptor< metric_t,self_t,DIM>  index_t;
01185 
01186                 index_t* index; //! The kd-tree index for the user to call its methods as usual with any other FLANN index.
01187 
01188                 /// Constructor: takes a const ref to the matrix object with the data points
01189                 KDTreeEigenMatrixAdaptor(const int dimensionality, const MatrixType &mat, const int leaf_max_size = 10) : m_data_matrix(mat)
01190                 {
01191                         const size_t dims = mat.cols();
01192                         if (DIM>0 && static_cast<int>(dims)!=DIM)
01193                                 throw std::runtime_error("Data set dimensionality does not match the 'DIM' template argument");
01194                         index = new index_t( dims, *this /* adaptor */, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size, dims ) );
01195                         index->buildIndex();
01196                 }
01197 
01198                 ~KDTreeEigenMatrixAdaptor() {
01199                         delete index;
01200                 }
01201 
01202                 const MatrixType &m_data_matrix;
01203 
01204                 /** Query for the \a num_closest closest points to a given point (entered as query_point[0:dim-1]).
01205                   *  Note that this is a short-cut method for index->findNeighbors().
01206                   *  The user can also call index->... methods as desired.
01207                   */
01208                 inline void query(const num_t *query_point, int num_closest, int *out_indices, num_t *out_distances_sq, const int nChecks = 10) const
01209                 {
01210                         nanoflann::KNNResultSet<typename MatrixType::Scalar> resultSet(num_closest);
01211                         resultSet.init(out_indices, out_distances_sq);
01212                         index->findNeighbors(resultSet, query_point, nanoflann::SearchParams(nChecks));
01213                 }
01214 
01215                 /** @name Interface expected by KDTreeSingleIndexAdaptor
01216                   * @{ */
01217 
01218                 const self_t & derived() const {
01219                         return *this;
01220                 }
01221                 self_t & derived()       {
01222                         return *this;
01223                 }
01224 
01225                 // Must return the number of data points
01226                 inline size_t kdtree_get_point_count() const {
01227                         return m_data_matrix.rows();
01228                 }
01229 
01230                 // Returns the distance between the vector "p1[0:size-1]" and the data point with index "idx_p2" stored in the class:
01231                 inline num_t kdtree_distance(const num_t *p1, const size_t idx_p2,size_t size) const
01232                 {
01233                         num_t s=0;
01234                         for (size_t i=0; i<size; i++) {
01235                                 const num_t d= p1[i]-m_data_matrix.coeff(idx_p2,i);
01236                                 s+=d*d;
01237                         }
01238                         return s;
01239                 }
01240 
01241                 // Returns the dim'th component of the idx'th point in the class:
01242                 inline num_t kdtree_get_pt(const size_t idx, int dim) const {
01243                         return m_data_matrix.coeff(idx,dim);
01244                 }
01245 
01246                 // Optional bounding-box computation: return false to default to a standard bbox computation loop.
01247                 //   Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again.
01248                 //   Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds)
01249                 template <class BBOX>
01250                 bool kdtree_get_bbox(BBOX &bb) const {
01251                         return false;
01252                 }
01253 
01254                 /** @} */
01255 
01256         }; // end of KDTreeEigenMatrixAdaptor
01257         /** @} */
01258 
01259 /** @} */ // end of grouping
01260 } // end of NS
01261 
01262 
01263 #endif /* NANOFLANN_HPP_ */



Page generated by Doxygen 1.7.5 for MRPT 0.9.5 SVN: at Thu Oct 13 21:25:36 UTC 2011