Main MRPT website > C++ reference
MRPT logo
KDTreeCapable.h
Go to the documentation of this file.
00001 /* +---------------------------------------------------------------------------+
00002    |          The Mobile Robot Programming Toolkit (MRPT) C++ library          |
00003    |                                                                           |
00004    |                       http://www.mrpt.org/                                |
00005    |                                                                           |
00006    |   Copyright (C) 2005-2011  University of Malaga                           |
00007    |                                                                           |
00008    |    This software was written by the Machine Perception and Intelligent    |
00009    |      Robotics Lab, University of Malaga (Spain).                          |
00010    |    Contact: Jose-Luis Blanco  <jlblanco@ctima.uma.es>                     |
00011    |                                                                           |
00012    |  This file is part of the MRPT project.                                   |
00013    |                                                                           |
00014    |     MRPT is free software: you can redistribute it and/or modify          |
00015    |     it under the terms of the GNU General Public License as published by  |
00016    |     the Free Software Foundation, either version 3 of the License, or     |
00017    |     (at your option) any later version.                                   |
00018    |                                                                           |
00019    |   MRPT is distributed in the hope that it will be useful,                 |
00020    |     but WITHOUT ANY WARRANTY; without even the implied warranty of        |
00021    |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
00022    |     GNU General Public License for more details.                          |
00023    |                                                                           |
00024    |     You should have received a copy of the GNU General Public License     |
00025    |     along with MRPT.  If not, see <http://www.gnu.org/licenses/>.         |
00026    |                                                                           |
00027    +---------------------------------------------------------------------------+ */
00028 #ifndef  KDTreeCapable_H
00029 #define  KDTreeCapable_H
00030 
00031 #include <mrpt/utils/utils_defs.h>
00032 
00033 // nanoflann library:
00034 #include <mrpt/otherlibs/nanoflann/nanoflann.hpp>
00035 #include <mrpt/math/lightweight_geom_data.h>
00036 
00037 namespace mrpt
00038 {
00039         namespace math
00040         {
00041                 /** \addtogroup kdtree_grp KD-Trees
00042                   *  \ingroup mrpt_base_grp
00043                   *  @{ */
00044 
00045 
00046                 /** A generic adaptor class for providing Approximate Nearest Neighbors (ANN) (via the nanoflann library) to MRPT classses.
00047                  *   This makes use of the CRTP design pattern.
00048                  *
00049                  *  Derived classes must be aware of the need to call "kdtree_mark_as_outdated()" when the data points
00050                  *   change to mark the cached KD-tree (an "index") as invalid, and also implement the following interface
00051                  *   (note that these are not virtual functions due to the usage of CRTP):
00052                  *
00053                  *  \code
00054                  *   // Must return the number of data points
00055                  *   inline size_t kdtree_get_point_count() const { ... }
00056                  *
00057                  *   // Returns the distance between the vector "p1[0:size-1]" and the data point with index "idx_p2" stored in the class:
00058                  *   inline float kdtree_distance(const float *p1, const size_t idx_p2,size_t size) const { ... }
00059                  *
00060                  *   // Returns the dim'th component of the idx'th point in the class:
00061                  *   inline num_t kdtree_get_pt(const size_t idx, int dim) const { ... }
00062                  *
00063                  *   // Optional bounding-box computation: return false to default to a standard bbox computation loop.
00064                  *   //   Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again.
00065                  *   //   Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds)
00066                  *   template <class BBOX>
00067                  *   bool kdtree_get_bbox(BBOX &bb) const
00068                  *   {
00069                  *      bb[0].low = ...; bb[0].high = ...;  // "x" limits
00070                  *      return true;
00071                  *   }
00072                  *
00073                  *  \endcode
00074                  *
00075                  * The KD-tree index will be built on demand only upon call of any of the query methods provided by this class.
00076                  *
00077                  *  Notice that there is only ONE internal cached KD-tree, so if a method to query a 2D point is called,
00078                  *  then another method for 3D points, then again the 2D method, three KD-trees will be built. So, try
00079                  *  to group all the calls for a given dimensionality together or build different class instances for
00080                  *  queries of each dimensionality, etc.
00081                  *
00082                  *  \sa See some of the derived classes for example implementations. See also the documentation of nanoflann
00083                  * \ingroup mrpt_base_grp
00084                  */
00085                 template <class Derived, typename num_t = float, typename metric_t = nanoflann::L2_Simple_Adaptor<num_t,Derived> >
00086                 class KDTreeCapable
00087                 {
00088                 public:
00089                         // Types ---------------
00090                         typedef KDTreeCapable<Derived,num_t,metric_t>                 self_t;
00091                         // ---------------------
00092 
00093                         /// Constructor
00094                         inline KDTreeCapable() : m_kdtree_is_uptodate(false)  { }
00095 
00096                         /// Destructor (nothing needed to do here)
00097                         inline ~KDTreeCapable() { }
00098 
00099                         /// CRTP helper method
00100                         inline const Derived& derived() const { return *static_cast<const Derived*>(this); }
00101                         /// CRTP helper method
00102                         inline       Derived& derived()       { return *static_cast<Derived*>(this); }
00103 
00104                         struct TKDTreeSearchParams
00105                         {
00106                                 TKDTreeSearchParams() :
00107                                         nChecks(32),
00108                                         leaf_max_size(10)
00109                                 {
00110                                 }
00111 
00112                                 int nChecks; //!< The number of checks for ANN (default: 32) - corresponds to FLANN's SearchParams::check
00113                                 int leaf_max_size; //!< Max points per leaf
00114                         };
00115 
00116                         TKDTreeSearchParams  kdtree_search_params; //!< Parameters to tune the ANN searches
00117 
00118                         /** @name Public utility methods to query the KD-tree
00119                                 @{ */
00120 
00121                         /** KD Tree-based search for the closest point (only ONE) to some given 2D coordinates.
00122                           *  This method automatically build the "m_kdtree_data" structure when:
00123                           *             - It is called for the first time
00124                           *             - The map has changed
00125                           *             - The KD-tree was build for 3D.
00126                           *
00127                           * \param x0  The X coordinate of the query.
00128                           * \param y0  The Y coordinate of the query.
00129                           * \param out_x The X coordinate of the found closest correspondence.
00130                           * \param out_y The Y coordinate of the found closest correspondence.
00131                           * \param out_dist_sqr The square distance between the query and the returned point.
00132                           *
00133                           * \return The index of the closest point in the map array.
00134                           *  \sa kdTreeClosestPoint3D, kdTreeTwoClosestPoint2D
00135                           */
00136                         inline size_t kdTreeClosestPoint2D(
00137                                 float   x0,
00138                                 float   y0,
00139                                 float             &out_x,
00140                                 float             &out_y,
00141                                 float             &out_dist_sqr
00142                                 ) const
00143                         {
00144                                 MRPT_START
00145                                 rebuild_kdTree_2D(); // First: Create the 2D KD-Tree if required
00146                                 if ( !m_kdtree2d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00147 
00148                                 const int knn = 1; // Number of points to retrieve
00149                                 int ret_index;
00150                                 nanoflann::KNNResultSet<num_t> resultSet(knn);
00151                                 resultSet.init(&ret_index, &out_dist_sqr );
00152 
00153                                 m_kdtree2d_data.query_point[0] = x0;
00154                                 m_kdtree2d_data.query_point[1] = y0;
00155                         m_kdtree2d_data.index->findNeighbors(resultSet, &m_kdtree2d_data.query_point[0], nanoflann::SearchParams(kdtree_search_params.nChecks));
00156 
00157                                 // Copy output to user vars:
00158                                 out_x = derived().kdtree_get_pt(ret_index,0);
00159                                 out_y = derived().kdtree_get_pt(ret_index,1);
00160 
00161                                 return static_cast<size_t>(ret_index);
00162                                 MRPT_END
00163                         }
00164 
00165                         /// \overload
00166                         inline size_t kdTreeClosestPoint2D(
00167                                 float   x0,
00168                                 float   y0,
00169                                 float   &out_dist_sqr ) const
00170                         {
00171                                 MRPT_START
00172                                 rebuild_kdTree_2D(); // First: Create the 2D KD-Tree if required
00173                                 if ( !m_kdtree2d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00174 
00175                                 const int knn = 1; // Number of points to retrieve
00176                                 int ret_index;
00177                                 nanoflann::KNNResultSet<num_t> resultSet(knn);
00178                                 resultSet.init(&ret_index, &out_dist_sqr );
00179 
00180                                 m_kdtree2d_data.query_point[0] = x0;
00181                                 m_kdtree2d_data.query_point[1] = y0;
00182                         m_kdtree2d_data.index->findNeighbors(resultSet, &m_kdtree2d_data.query_point[0], nanoflann::SearchParams(kdtree_search_params.nChecks));
00183 
00184                                 return static_cast<size_t>(ret_index);
00185                                 MRPT_END
00186                         }
00187 
00188                         /// \overload
00189                         inline size_t kdTreeClosestPoint2D(const TPoint2D &p0,TPoint2D &pOut,float &outDistSqr) const   {
00190                                 float dmy1,dmy2;
00191                                 size_t res=kdTreeClosestPoint2D(static_cast<float>(p0.x),static_cast<float>(p0.y),dmy1,dmy2,outDistSqr);
00192                                 pOut.x=dmy1;
00193                                 pOut.y=dmy2;
00194                                 return res;
00195                         }
00196 
00197                         /** Like kdTreeClosestPoint2D, but just return the square error from some point to its closest neighbor.
00198                           */
00199                         inline float kdTreeClosestPoint2DsqrError(
00200                                 float   x0,
00201                                 float   y0 ) const
00202                         {
00203                                 float closerx,closery,closer_dist;
00204                                 kdTreeClosestPoint2D(x0,y0, closerx,closery,closer_dist);
00205                                 return closer_dist;
00206                         }
00207 
00208                         inline float kdTreeClosestPoint2DsqrError(const TPoint2D &p0) const     {
00209                                 return kdTreeClosestPoint2DsqrError(static_cast<float>(p0.x),static_cast<float>(p0.y));
00210                         }
00211 
00212                         /** KD Tree-based search for the TWO closest point to some given 2D coordinates.
00213                           *  This method automatically build the "m_kdtree_data" structure when:
00214                           *             - It is called for the first time
00215                           *             - The map has changed
00216                           *             - The KD-tree was build for 3D.
00217                           *
00218                           * \param x0  The X coordinate of the query.
00219                           * \param y0  The Y coordinate of the query.
00220                           * \param out_x1 The X coordinate of the first correspondence.
00221                           * \param out_y1 The Y coordinate of the first correspondence.
00222                           * \param out_x2 The X coordinate of the second correspondence.
00223                           * \param out_y2 The Y coordinate of the second correspondence.
00224                           * \param out_dist_sqr1 The square distance between the query and the first returned point.
00225                           * \param out_dist_sqr2 The square distance between the query and the second returned point.
00226                           *
00227                           *  \sa kdTreeClosestPoint2D
00228                           */
00229                         inline void kdTreeTwoClosestPoint2D(
00230                                 float   x0,
00231                                 float   y0,
00232                                 float             &out_x1,
00233                                 float             &out_y1,
00234                                 float             &out_x2,
00235                                 float             &out_y2,
00236                                 float             &out_dist_sqr1,
00237                                 float             &out_dist_sqr2 ) const
00238                         {
00239                                 MRPT_START
00240                                 rebuild_kdTree_2D(); // First: Create the 2D KD-Tree if required
00241                                 if ( !m_kdtree2d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00242 
00243                                 const int knn = 2; // Number of points to retrieve
00244                                 int   ret_indexes[2];
00245                                 float ret_sqdist[2];
00246                                 nanoflann::KNNResultSet<num_t> resultSet(knn);
00247                                 resultSet.init(&ret_indexes[0], &ret_sqdist[0] );
00248 
00249                                 m_kdtree2d_data.query_point[0] = x0;
00250                                 m_kdtree2d_data.query_point[1] = y0;
00251                         m_kdtree2d_data.index->findNeighbors(resultSet, &m_kdtree2d_data.query_point[0], nanoflann::SearchParams(kdtree_search_params.nChecks));
00252 
00253                                 // Copy output to user vars:
00254                                 out_x1 = derived().kdtree_get_pt(ret_indexes[0],0);
00255                                 out_y1 = derived().kdtree_get_pt(ret_indexes[0],1);
00256                                 out_dist_sqr1 = ret_sqdist[0];
00257 
00258                                 out_x2 = derived().kdtree_get_pt(ret_indexes[1],0);
00259                                 out_y2 = derived().kdtree_get_pt(ret_indexes[1],1);
00260                                 out_dist_sqr2 = ret_sqdist[0];
00261 
00262                                 MRPT_END
00263                         }
00264 
00265 
00266                         inline void kdTreeTwoClosestPoint2D(const TPoint2D &p0,TPoint2D &pOut1,TPoint2D &pOut2,float &outDistSqr1,float &outDistSqr2) const     {
00267                                 float dmy1,dmy2,dmy3,dmy4;
00268                                 kdTreeTwoClosestPoint2D(p0.x,p0.y,dmy1,dmy2,dmy3,dmy4,outDistSqr1,outDistSqr2);
00269                                 pOut1.x=static_cast<double>(dmy1);
00270                                 pOut1.y=static_cast<double>(dmy2);
00271                                 pOut2.x=static_cast<double>(dmy3);
00272                                 pOut2.y=static_cast<double>(dmy4);
00273                         }
00274 
00275                         /** KD Tree-based search for the N closest point to some given 2D coordinates.
00276                           *  This method automatically build the "m_kdtree_data" structure when:
00277                           *             - It is called for the first time
00278                           *             - The map has changed
00279                           *             - The KD-tree was build for 3D.
00280                           *
00281                           * \param x0  The X coordinate of the query.
00282                           * \param y0  The Y coordinate of the query.
00283                           * \param N The number of closest points to search.
00284                           * \param out_x The vector containing the X coordinates of the correspondences.
00285                           * \param out_y The vector containing the Y coordinates of the correspondences.
00286                           * \param out_dist_sqr The vector containing the square distance between the query and the returned points.
00287                           *
00288                           * \return The list of indices
00289                           *  \sa kdTreeClosestPoint2D
00290                           *  \sa kdTreeTwoClosestPoint2D
00291                           */
00292                         inline
00293                         std::vector<int> kdTreeNClosestPoint2D(
00294                                 float                   x0,
00295                                 float                   y0,
00296                                 size_t  knn,
00297                                 std::vector<float>  &out_x,
00298                                 std::vector<float>  &out_y,
00299                                 std::vector<float>  &out_dist_sqr ) const
00300                         {
00301                                 MRPT_START
00302                                 rebuild_kdTree_2D(); // First: Create the 2D KD-Tree if required
00303                                 if ( !m_kdtree2d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00304 
00305                                 std::vector<int> ret_indexes(knn);
00306                                 out_x.resize(knn);
00307                                 out_y.resize(knn);
00308                                 out_dist_sqr.resize(knn);
00309 
00310                                 nanoflann::KNNResultSet<num_t> resultSet(knn);
00311                                 resultSet.init(&ret_indexes[0], &out_dist_sqr[0] );
00312 
00313                                 m_kdtree2d_data.query_point[0] = x0;
00314                                 m_kdtree2d_data.query_point[1] = y0;
00315                         m_kdtree2d_data.index->findNeighbors(resultSet, &m_kdtree2d_data.query_point[0], nanoflann::SearchParams(kdtree_search_params.nChecks));
00316 
00317                                 for (size_t i=0;i<knn;i++)
00318                                 {
00319                                         out_x[i] = derived().kdtree_get_pt(ret_indexes[i],0);
00320                                         out_y[i] = derived().kdtree_get_pt(ret_indexes[i],1);
00321                                 }
00322                                 return ret_indexes;
00323                                 MRPT_END
00324                         }
00325 
00326                         inline std::vector<int> kdTreeNClosestPoint2D(const TPoint2D &p0,size_t N,std::vector<TPoint2D> &pOut,std::vector<float> &outDistSqr) const     {
00327                                 std::vector<float> dmy1,dmy2;
00328                                 std::vector<int> res=kdTreeNClosestPoint2D(static_cast<float>(p0.x),static_cast<float>(p0.y),N,dmy1,dmy2,outDistSqr);
00329                                 pOut.resize(dmy1.size());
00330                                 for (size_t i=0;i<dmy1.size();i++)      {
00331                                         pOut[i].x=static_cast<double>(dmy1[i]);
00332                                         pOut[i].y=static_cast<double>(dmy2[i]);
00333                                 }
00334                                 return res;
00335                         }
00336 
00337                         /** KD Tree-based search for the N closest point to some given 2D coordinates and returns their indexes.
00338                           *  This method automatically build the "m_kdtree_data" structure when:
00339                           *             - It is called for the first time
00340                           *             - The map has changed
00341                           *             - The KD-tree was build for 3D.
00342                           *
00343                           * \param x0  The X coordinate of the query.
00344                           * \param y0  The Y coordinate of the query.
00345                           * \param N The number of closest points to search.
00346                           * \param out_idx The indexes of the found closest correspondence.
00347                           * \param out_dist_sqr The square distance between the query and the returned point.
00348                           *
00349                           *  \sa kdTreeClosestPoint2D
00350                           */
00351                         inline void kdTreeNClosestPoint2DIdx(
00352                                 float                   x0,
00353                                 float                   y0,
00354                                 size_t  knn,
00355                                 std::vector<int>        &out_idx,
00356                                 std::vector<float>  &out_dist_sqr ) const
00357                         {
00358                                 MRPT_START
00359                                 rebuild_kdTree_2D(); // First: Create the 2D KD-Tree if required
00360                                 if ( !m_kdtree2d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00361 
00362                                 out_idx.resize(knn);
00363                                 out_dist_sqr.resize(knn);
00364                                 nanoflann::KNNResultSet<num_t> resultSet(knn);
00365                                 resultSet.init(&out_idx[0], &out_dist_sqr[0] );
00366 
00367                                 m_kdtree2d_data.query_point[0] = x0;
00368                                 m_kdtree2d_data.query_point[1] = y0;
00369                         m_kdtree2d_data.index->findNeighbors(resultSet, &m_kdtree2d_data.query_point[0], nanoflann::SearchParams(kdtree_search_params.nChecks));
00370                                 MRPT_END
00371                         }
00372 
00373                         inline void kdTreeNClosestPoint2DIdx(const TPoint2D &p0,size_t N,std::vector<int> &outIdx,std::vector<float> &outDistSqr) const {
00374                                 return kdTreeNClosestPoint2DIdx(static_cast<float>(p0.x),static_cast<float>(p0.y),N,outIdx,outDistSqr);
00375                         }
00376 
00377                         /** KD Tree-based search for the closest point (only ONE) to some given 3D coordinates.
00378                           *  This method automatically build the "m_kdtree_data" structure when:
00379                           *             - It is called for the first time
00380                           *             - The map has changed
00381                           *             - The KD-tree was build for 2D.
00382                           *
00383                           * \param x0  The X coordinate of the query.
00384                           * \param y0  The Y coordinate of the query.
00385                           * \param z0  The Z coordinate of the query.
00386                           * \param out_x The X coordinate of the found closest correspondence.
00387                           * \param out_y The Y coordinate of the found closest correspondence.
00388                           * \param out_z The Z coordinate of the found closest correspondence.
00389                           * \param out_dist_sqr The square distance between the query and the returned point.
00390                           *
00391                           * \return The index of the closest point in the map array.
00392                           *  \sa kdTreeClosestPoint2D
00393                           */
00394                         inline size_t kdTreeClosestPoint3D(
00395                                 float   x0,
00396                                 float   y0,
00397                                 float   z0,
00398                                 float             &out_x,
00399                                 float             &out_y,
00400                                 float             &out_z,
00401                                 float             &out_dist_sqr
00402                                 ) const
00403                         {
00404                                 MRPT_START
00405                                 rebuild_kdTree_3D(); // First: Create the 3D KD-Tree if required
00406                                 if ( !m_kdtree3d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00407 
00408                                 const int knn = 1; // Number of points to retrieve
00409                                 int ret_index;
00410                                 nanoflann::KNNResultSet<num_t> resultSet(knn);
00411                                 resultSet.init(&ret_index, &out_dist_sqr );
00412 
00413                                 m_kdtree3d_data.query_point[0] = x0;
00414                                 m_kdtree3d_data.query_point[1] = y0;
00415                                 m_kdtree3d_data.query_point[2] = z0;
00416                         m_kdtree3d_data.index->findNeighbors(resultSet, &m_kdtree3d_data.query_point[0], nanoflann::SearchParams(kdtree_search_params.nChecks));
00417 
00418                                 // Copy output to user vars:
00419                                 out_x = derived().kdtree_get_pt(ret_index,0);
00420                                 out_y = derived().kdtree_get_pt(ret_index,1);
00421                                 out_z = derived().kdtree_get_pt(ret_index,2);
00422 
00423                                 return static_cast<size_t>(ret_index);
00424                                 MRPT_END
00425                         }
00426 
00427                         /// \overload
00428                         inline size_t kdTreeClosestPoint3D(
00429                                 float   x0,
00430                                 float   y0,
00431                                 float   z0,
00432                                 float             &out_dist_sqr
00433                                 ) const
00434                         {
00435                                 MRPT_START
00436                                 rebuild_kdTree_3D(); // First: Create the 3D KD-Tree if required
00437                                 if ( !m_kdtree3d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00438 
00439                                 const int knn = 1; // Number of points to retrieve
00440                                 int ret_index;
00441                                 nanoflann::KNNResultSet<num_t> resultSet(knn);
00442                                 resultSet.init(&ret_index, &out_dist_sqr );
00443 
00444                                 m_kdtree3d_data.query_point[0] = x0;
00445                                 m_kdtree3d_data.query_point[1] = y0;
00446                                 m_kdtree3d_data.query_point[2] = z0;
00447                         m_kdtree3d_data.index->findNeighbors(resultSet, &m_kdtree3d_data.query_point[0], nanoflann::SearchParams(kdtree_search_params.nChecks));
00448 
00449                                 return static_cast<size_t>(ret_index);
00450                                 MRPT_END
00451                         }
00452 
00453                         /// \overload
00454                         inline size_t kdTreeClosestPoint3D(const TPoint3D &p0,TPoint3D &pOut,float &outDistSqr) const   {
00455                                 float dmy1,dmy2,dmy3;
00456                                 size_t res=kdTreeClosestPoint3D(static_cast<float>(p0.x),static_cast<float>(p0.y),static_cast<float>(p0.z),dmy1,dmy2,dmy3,outDistSqr);
00457                                 pOut.x=static_cast<double>(dmy1);
00458                                 pOut.y=static_cast<double>(dmy2);
00459                                 pOut.z=static_cast<double>(dmy3);
00460                                 return res;
00461                         }
00462 
00463                         /** KD Tree-based search for the N closest points to some given 3D coordinates.
00464                           *  This method automatically build the "m_kdtree_data" structure when:
00465                           *             - It is called for the first time
00466                           *             - The map has changed
00467                           *             - The KD-tree was build for 2D.
00468                           *
00469                           * \param x0  The X coordinate of the query.
00470                           * \param y0  The Y coordinate of the query.
00471                           * \param z0  The Z coordinate of the query.
00472                           * \param N The number of closest points to search.
00473                           * \param out_x The vector containing the X coordinates of the correspondences.
00474                           * \param out_y The vector containing the Y coordinates of the correspondences.
00475                           * \param out_z The vector containing the Z coordinates of the correspondences.
00476                           * \param out_dist_sqr The vector containing the square distance between the query and the returned points.
00477                           *
00478                           *  \sa kdTreeNClosestPoint2D
00479                           */
00480                         inline void kdTreeNClosestPoint3D(
00481                                 float                   x0,
00482                                 float                   y0,
00483                                 float                   z0,
00484                                 size_t  knn,
00485                                 std::vector<float>  &out_x,
00486                                 std::vector<float>  &out_y,
00487                                 std::vector<float>  &out_z,
00488                                 std::vector<float>  &out_dist_sqr ) const
00489                         {
00490                                 MRPT_START
00491                                 rebuild_kdTree_3D(); // First: Create the 3D KD-Tree if required
00492                                 if ( !m_kdtree3d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00493 
00494                                 std::vector<int> ret_indexes(knn);
00495                                 out_x.resize(knn);
00496                                 out_y.resize(knn);
00497                                 out_z.resize(knn);
00498                                 out_dist_sqr.resize(knn);
00499 
00500                                 nanoflann::KNNResultSet<num_t> resultSet(knn);
00501                                 resultSet.init(&ret_indexes[0], &out_dist_sqr[0] );
00502 
00503                                 m_kdtree3d_data.query_point[0] = x0;
00504                                 m_kdtree3d_data.query_point[1] = y0;
00505                                 m_kdtree3d_data.query_point[2] = z0;
00506                         m_kdtree3d_data.index->findNeighbors(resultSet, &m_kdtree3d_data.query_point[0], nanoflann::SearchParams(kdtree_search_params.nChecks));
00507 
00508                                 for (size_t i=0;i<knn;i++)
00509                                 {
00510                                         out_x[i] = derived().kdtree_get_pt(ret_indexes[i],0);
00511                                         out_y[i] = derived().kdtree_get_pt(ret_indexes[i],1);
00512                                         out_z[i] = derived().kdtree_get_pt(ret_indexes[i],2);
00513                                 }
00514                                 MRPT_END
00515                         }
00516 
00517                         inline void kdTreeNClosestPoint3D(const TPoint3D &p0,size_t N,std::vector<TPoint3D> &pOut,std::vector<float> &outDistSqr) const {
00518                                 std::vector<float> dmy1,dmy2,dmy3;
00519                                 kdTreeNClosestPoint3D(static_cast<float>(p0.x),static_cast<float>(p0.y),static_cast<float>(p0.z),N,dmy1,dmy2,dmy3,outDistSqr);
00520                                 pOut.resize(dmy1.size());
00521                                 for (size_t i=0;i<dmy1.size();i++)      {
00522                                         pOut[i].x=static_cast<double>(dmy1[i]);
00523                                         pOut[i].y=static_cast<double>(dmy2[i]);
00524                                         pOut[i].z=static_cast<double>(dmy3[i]);
00525                                 }
00526                         }
00527 
00528                         /** KD Tree-based search for the N closest point to some given 3D coordinates and returns their indexes.
00529                           *  This method automatically build the "m_kdtree_data" structure when:
00530                           *             - It is called for the first time
00531                           *             - The map has changed
00532                           *             - The KD-tree was build for 2D.
00533                           *
00534                           * \param x0  The X coordinate of the query.
00535                           * \param y0  The Y coordinate of the query.
00536                           * \param z0  The Z coordinate of the query.
00537                           * \param N The number of closest points to search.
00538                           * \param out_idx The indexes of the found closest correspondence.
00539                           * \param out_dist_sqr The square distance between the query and the returned point.
00540                           *
00541                           *  \sa kdTreeClosestPoint2D
00542                           */
00543                         inline void kdTreeNClosestPoint3DIdx(
00544                                 float                   x0,
00545                                 float                   y0,
00546                                 float                   z0,
00547                                 size_t  knn,
00548                                 std::vector<int>        &out_idx,
00549                                 std::vector<float>  &out_dist_sqr ) const
00550                         {
00551                                 MRPT_START
00552                                 rebuild_kdTree_3D(); // First: Create the 3D KD-Tree if required
00553                                 if ( !m_kdtree3d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00554 
00555                                 out_idx.resize(knn);
00556                                 out_dist_sqr.resize(knn);
00557                                 nanoflann::KNNResultSet<num_t> resultSet(knn);
00558                                 resultSet.init(&out_idx[0], &out_dist_sqr[0] );
00559 
00560                                 m_kdtree3d_data.query_point[0] = x0;
00561                                 m_kdtree3d_data.query_point[1] = y0;
00562                                 m_kdtree3d_data.query_point[2] = z0;
00563                         m_kdtree3d_data.index->findNeighbors(resultSet, &m_kdtree3d_data.query_point[0], nanoflann::SearchParams(kdtree_search_params.nChecks));
00564                                 MRPT_END
00565                         }
00566 
00567                         inline void kdTreeNClosestPoint3DIdx(const TPoint3D &p0,size_t N,std::vector<int> &outIdx,std::vector<float> &outDistSqr) const {
00568                                 kdTreeNClosestPoint3DIdx(static_cast<float>(p0.x),static_cast<float>(p0.y),static_cast<float>(p0.z),N,outIdx,outDistSqr);
00569                         }
00570 
00571                         /* @} */
00572 
00573                 protected:
00574                         /** To be called by child classes when KD tree data changes. */
00575                         inline void kdtree_mark_as_outdated() const { m_kdtree_is_uptodate = false; }
00576 
00577                 private:
00578                         /** Internal structure with the KD-tree representation (mainly used to avoid copying pointers with the = operator) */
00579                         template <int _DIM = -1>
00580                         struct TKDTreeDataHolder
00581                         {
00582                                 /** Init the pointer to NULL. */
00583                                 inline TKDTreeDataHolder() : index(NULL),m_dim(_DIM), m_num_points(0) { }
00584 
00585                                 /** Copy constructor: It actually does NOT copy the kd-tree, a new object will be created if required!   */
00586                                 inline TKDTreeDataHolder(const TKDTreeDataHolder &o)  : index(NULL),m_dim(_DIM), m_num_points(0) { }
00587 
00588                                 /** Copy operator: It actually does NOT copy the kd-tree, a new object will be created if required!  */
00589                                 inline TKDTreeDataHolder& operator =(const TKDTreeDataHolder &o) {
00590                                         if (&o!=this) clear();
00591                                         return *this;
00592                                 }
00593 
00594                                 /** Free memory (if allocated) */
00595                                 inline ~TKDTreeDataHolder() { clear(); }
00596 
00597                                 /** Free memory (if allocated)  */
00598                                 inline void clear()     { mrpt::utils::delete_safe( index ); }
00599 
00600                                 typedef nanoflann::KDTreeSingleIndexAdaptor<metric_t,Derived, _DIM> kdtree_index_t;
00601 
00602                                 kdtree_index_t *index;  //!< NULL or the up-to-date index
00603 
00604                                 std::vector<num_t> query_point;
00605                                 size_t           m_dim;         //!< Dimensionality. typ: 2,3
00606                                 size_t           m_num_points;
00607                         };
00608 
00609                         mutable TKDTreeDataHolder<2>  m_kdtree2d_data;
00610                         mutable TKDTreeDataHolder<3>  m_kdtree3d_data;
00611                         mutable TKDTreeDataHolder<>   m_kdtreeNd_data;
00612                         mutable bool                  m_kdtree_is_uptodate; //!< whether the KD tree needs to be rebuilt or not.
00613 
00614                         /// Rebuild, if needed the KD-tree for 2D (nDims=2), 3D (nDims=3), ... asking the child class for the data points.
00615                         void rebuild_kdTree_2D() const
00616                         {
00617                                 typedef typename TKDTreeDataHolder<2>::kdtree_index_t  tree2d_t;
00618 
00619                                 if (!m_kdtree_is_uptodate) { m_kdtree2d_data.clear(); m_kdtree3d_data.clear(); m_kdtreeNd_data.clear(); }
00620 
00621                                 if (!m_kdtree2d_data.index)
00622                                 {
00623                                         // Erase previous tree:
00624                                         m_kdtree2d_data.clear();
00625                                         // And build new index:
00626                                         const size_t N = derived().kdtree_get_point_count();
00627                                         m_kdtree2d_data.m_num_points = N;
00628                                         m_kdtree2d_data.m_dim        = 2;
00629                                         m_kdtree2d_data.query_point.resize(2);
00630                                         if (N)
00631                                         {
00632                                                 m_kdtree2d_data.index = new tree2d_t(2, derived(),  nanoflann::KDTreeSingleIndexAdaptorParams(kdtree_search_params.leaf_max_size, 2 ) );
00633                                                 m_kdtree2d_data.index->buildIndex();
00634                                         }
00635                                         m_kdtree_is_uptodate = true;
00636                                 }
00637                         }
00638 
00639                         /// Rebuild, if needed the KD-tree for 2D (nDims=2), 3D (nDims=3), ... asking the child class for the data points.
00640                         void rebuild_kdTree_3D() const
00641                         {
00642                                 typedef typename TKDTreeDataHolder<3>::kdtree_index_t  tree3d_t;
00643 
00644                                 if (!m_kdtree_is_uptodate) { m_kdtree2d_data.clear(); m_kdtree3d_data.clear(); m_kdtreeNd_data.clear(); }
00645 
00646                                 if (!m_kdtree3d_data.index)
00647                                 {
00648                                         // Erase previous tree:
00649                                         m_kdtree3d_data.clear();
00650                                         // And build new index:
00651                                         const size_t N = derived().kdtree_get_point_count();
00652                                         m_kdtree3d_data.m_num_points = N;
00653                                         m_kdtree3d_data.m_dim        = 3;
00654                                         m_kdtree3d_data.query_point.resize(3);
00655                                         if (N)
00656                                         {
00657                                                 m_kdtree3d_data.index = new tree3d_t(3, derived(),  nanoflann::KDTreeSingleIndexAdaptorParams(kdtree_search_params.leaf_max_size, 3 ) );
00658                                                 m_kdtree3d_data.index->buildIndex();
00659                                         }
00660                                         m_kdtree_is_uptodate = true;
00661                                 }
00662                         }
00663 
00664                         /// Rebuild, if needed the KD-tree for 2D (nDims=2), 3D (nDims=3), ... asking the child class for the data points.
00665                         void rebuild_kdTree_Nd(const size_t nDims) const
00666                         {
00667                                 typedef typename TKDTreeDataHolder<>::kdtree_index_t   treeNd_t;
00668 
00669                                 if (!m_kdtree_is_uptodate) { m_kdtree2d_data.clear(); m_kdtree3d_data.clear(); m_kdtreeNd_data.clear(); }
00670 
00671                                 if (!m_kdtreeNd_data.index || m_kdtreeNd_data.m_dim!=nDims )
00672                                 {
00673                                         // Erase previous tree:
00674                                         m_kdtreeNd_data.clear();
00675                                         // And build new index:
00676                                         const size_t N = derived().kdtree_get_point_count();
00677                                         m_kdtreeNd_data.m_num_points = N;
00678                                         m_kdtreeNd_data.m_dim        = nDims;
00679                                         m_kdtreeNd_data.query_point.resize(nDims);
00680                                         if (N)
00681                                         {
00682                                                 m_kdtreeNd_data.index = new treeNd_t(nDims, derived(),  nanoflann::KDTreeSingleIndexAdaptorParams(kdtree_search_params.leaf_max_size, nDims ) );
00683                                                 m_kdtreeNd_data.index->buildIndex();
00684                                         }
00685                                         m_kdtree_is_uptodate = true;
00686                                 }
00687                         } // end of rebuild_kdTree
00688 
00689                 };  // end of KDTreeCapable
00690 
00691                 /**  @} */  // end of grouping
00692 
00693         } // End of namespace
00694 } // End of namespace
00695 #endif



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