00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifndef KDTreeCapable_H
00029 #define KDTreeCapable_H
00030
00031 #include <mrpt/utils/utils_defs.h>
00032
00033
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
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
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
00090 typedef KDTreeCapable<Derived,num_t,metric_t> self_t;
00091
00092
00093
00094 inline KDTreeCapable() : m_kdtree_is_uptodate(false) { }
00095
00096
00097 inline ~KDTreeCapable() { }
00098
00099
00100 inline const Derived& derived() const { return *static_cast<const Derived*>(this); }
00101
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;
00113 int leaf_max_size;
00114 };
00115
00116 TKDTreeSearchParams kdtree_search_params;
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
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();
00146 if ( !m_kdtree2d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00147
00148 const int knn = 1;
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
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
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();
00173 if ( !m_kdtree2d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00174
00175 const int knn = 1;
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
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
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
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
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();
00241 if ( !m_kdtree2d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00242
00243 const int knn = 2;
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
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
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
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();
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
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
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();
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
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
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();
00406 if ( !m_kdtree3d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00407
00408 const int knn = 1;
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
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
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();
00437 if ( !m_kdtree3d_data.m_num_points ) THROW_EXCEPTION("There are no points in the KD-tree.")
00438
00439 const int knn = 1;
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
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
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
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();
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
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
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();
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
00575 inline void kdtree_mark_as_outdated() const { m_kdtree_is_uptodate = false; }
00576
00577 private:
00578
00579 template <int _DIM = -1>
00580 struct TKDTreeDataHolder
00581 {
00582
00583 inline TKDTreeDataHolder() : index(NULL),m_dim(_DIM), m_num_points(0) { }
00584
00585
00586 inline TKDTreeDataHolder(const TKDTreeDataHolder &o) : index(NULL),m_dim(_DIM), m_num_points(0) { }
00587
00588
00589 inline TKDTreeDataHolder& operator =(const TKDTreeDataHolder &o) {
00590 if (&o!=this) clear();
00591 return *this;
00592 }
00593
00594
00595 inline ~TKDTreeDataHolder() { clear(); }
00596
00597
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;
00603
00604 std::vector<num_t> query_point;
00605 size_t m_dim;
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;
00613
00614
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
00624 m_kdtree2d_data.clear();
00625
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
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
00649 m_kdtree3d_data.clear();
00650
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
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
00674 m_kdtreeNd_data.clear();
00675
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 }
00688
00689 };
00690
00691
00692
00693 }
00694 }
00695 #endif