12#ifndef MFEM_KDTREE_HPP
13#define MFEM_KDTREE_HPP
15#include "../config/config.hpp"
32template <
typename T
float,
int ndim>
38 for (
int i=1; i<ndim; i++)
47template<
typename T
float,
int ndim>
54 for (
int i=1; i<ndim; i++)
63template<
typename T
float,
int ndim>
69 if (xx[0]<Tfloat(0.0)) { tm=-xx[0];}
71 for (
int i=1; i<ndim; i++)
73 if (xx[i]<Tfloat(0.0))
75 if (tm<(-xx[i])) {tm=-xx[i];}
79 if (tm<xx[i]) {tm=xx[i];}
90template <
typename Tindex,
typename T
float>
95 virtual void AddPoint(
const Tfloat *xx, Tindex ii) = 0;
116template <
typename Tindex,
typename Tfloat,
size_t ndim=3,
117 typename Tnorm=KDTreeNorms::Norm_l2<Tfloat,ndim> >
131 PointND(
const Tfloat *xx_) { std::copy(xx_,xx_+ndim,
xx); }
159 typedef typename std::vector<NodeND>::iterator
iterator;
189 SortInPlace(data.begin(),data.end(),0);
195 data.emplace_back(pt, ii);
201 data.emplace_back(xx, ii);
207 PointS best_candidate;
208 best_candidate.sp=pt;
210 best_candidate.pos =0;
211 best_candidate.dist=Dist(data[0].pt, best_candidate.sp);
212 best_candidate.level=0;
213 PSearch(data.begin(), data.end(), 0, best_candidate);
214 return data[best_candidate.pos].ind;
225 PointS best_candidate;
226 best_candidate.sp=pt;
228 best_candidate.pos =0;
229 best_candidate.dist=Dist(data[0].pt, best_candidate.sp);
230 best_candidate.level=0;
231 PSearch(data.begin(), data.end(), 0, best_candidate);
233 clp=data[best_candidate.pos].pt;
234 return data[best_candidate.pos].ind;
248 PointS best_candidate;
249 best_candidate.sp=pt;
251 best_candidate.pos =0;
252 best_candidate.dist=Dist(data[0].pt, best_candidate.sp);
253 best_candidate.level=0;
254 PSearch(data.begin(), data.end(), 0, best_candidate);
256 ind=data[best_candidate.pos].ind;
257 dist=best_candidate.dist;
258 clp=data[best_candidate.pos].pt;
265 PointS best_candidate;
266 best_candidate.sp=pt;
268 best_candidate.pos =0;
269 best_candidate.dist=Dist(data[0].pt, best_candidate.sp);
271 for (
auto iti=data.begin()+1; iti!=data.end(); iti++)
273 dd=Dist(iti->pt, best_candidate.sp);
274 if (dd<best_candidate.dist)
276 best_candidate.pos=iti-data.begin();
277 best_candidate.dist=dd;
281 ind=data[best_candidate.pos].ind;
282 dist=best_candidate.dist;
288 std::vector<Tfloat> & dist)
302 std::vector<Tindex> &res,
303 std::vector<Tfloat> &dist)
306 for (
auto iti=data.begin(); iti!=data.end(); iti++)
308 dd=Dist(iti->pt, pt);
311 res.push_back(iti->ind);
319 std::vector<Tindex> &res)
322 for (
auto iti=data.begin(); iti!=data.end(); iti++)
324 dd=Dist(iti->pt, pt);
327 res.push_back(iti->ind);
342 CompN(std::uint8_t dd):
dim(dd) {}
345 bool operator() (
const PointND& p1,
const PointND& p2)
347 return p1.xx[
dim]<p2.xx[
dim];
351 bool operator() (
const NodeND& n1,
const NodeND& n2)
353 return n1.pt.xx[
dim]<n2.pt.xx[
dim];
361 Tfloat Dist(
const PointND &pt1,
const PointND &pt2)
const
363 for (
size_t i=0; i<ndim; i++)
365 tp.xx[i]=pt1.xx[i]-pt2.xx[i];
371 std::vector<NodeND> data;
375 Tfloat FindMedian(
typename std::vector<NodeND>::iterator itb,
376 typename std::vector<NodeND>::iterator ite,
380 std::nth_element(itb, itb+siz/2, ite, CompN(cdim));
381 return itb->pt.xx[cdim];
385 void SortInPlace(
typename std::vector<NodeND>::iterator itb,
386 typename std::vector<NodeND>::iterator ite,
389 std::uint8_t cdim=(std::uint8_t)(level%ndim);
393 std::nth_element(itb, itb+siz/2, ite, CompN(cdim));
395 SortInPlace(itb, itb+siz/2, level);
396 SortInPlace(itb+siz/2+1,ite, level);
411 void PSearch(
typename std::vector<NodeND>::const_iterator itb,
412 typename std::vector<NodeND>::const_iterator ite,
413 size_t level, PointS& bc)
const
415 std::uint8_t
dim=(std::uint8_t) (level%ndim);
417 typename std::vector<NodeND>::const_iterator mtb=itb+siz/2;
422 if ((bc.sp.xx[
dim]-bc.dist)>mtb->pt.xx[
dim])
424 PSearch(itb+siz/2+1, ite, level, bc);
426 else if ((bc.sp.xx[
dim]+bc.dist)<mtb->pt.xx[
dim])
428 PSearch(itb,itb+siz/2, level, bc);
432 if (bc.sp.xx[
dim]<mtb->pt.xx[
dim])
435 PSearch(itb,itb+siz/2, level, bc);
437 if (!((bc.sp.xx[
dim]+bc.dist)<mtb->pt.xx[
dim]))
439 PSearch(itb+siz/2+1, ite, level, bc);
442 Tfloat dd=Dist(mtb->pt, bc.sp);
445 bc.dist=dd; bc.pos=mtb-data.begin(); bc.level=level;
453 PSearch(itb+siz/2+1, ite, level, bc);
455 if (!((bc.sp.xx[
dim]-bc.dist)>mtb->pt.xx[
dim]))
457 PSearch(itb, itb+siz/2, level, bc);
460 Tfloat dd=Dist(mtb->pt, bc.sp);
463 bc.dist=dd; bc.pos=mtb-data.begin(); bc.level=level;
474 for (
auto it=itb; it!=ite; it++)
476 dd=Dist(it->pt, bc.sp);
479 bc.pos=it-data.begin();
488 void NNS(PointND& pt,
const int& npoints,
489 typename std::vector<NodeND>::iterator itb,
490 typename std::vector<NodeND>::iterator ite,
492 std::vector< std::tuple<Tfloat,Tindex> > & res)
const
494 std::uint8_t
dim=(std::uint8_t) (level%ndim);
496 typename std::vector<NodeND>::iterator mtb=itb+siz/2;
501 Tfloat R=std::get<0>(res[npoints-1]);
503 Tfloat dd=Dist(mtb->pt, pt);
506 res[npoints-1]=std::make_tuple(dd,mtb->ind);
507 std::nth_element(res.begin(), res.end()-1, res.end());
508 R=std::get<0>(res[npoints-1]);
510 if ((pt.xx[
dim]-R)>mtb->pt.xx[
dim])
512 NNS(pt, npoints, itb+siz/2+1, ite, level, res);
514 else if ((pt.xx[
dim]+R)<mtb->pt.xx[
dim])
516 NNS(pt, npoints, itb, itb+siz/2, level, res);
520 NNS(pt,npoints, itb+siz/2+1, ite, level, res);
521 NNS(pt,npoints, itb, itb+siz/2, level, res);
527 for (
auto it=itb; it!=ite; it++)
530 if (dd< std::get<0>(res[npoints-1]))
532 res[npoints-1]=std::make_tuple(dd,it->ind);
533 std::nth_element(res.begin(), res.end()-1, res.end());
541 typename std::vector<NodeND>::iterator itb,
542 typename std::vector<NodeND>::iterator ite,
544 std::vector<Tindex> & res)
const
546 std::uint8_t
dim=(std::uint8_t) (level%ndim);
548 typename std::vector<NodeND>::iterator mtb=itb+siz/2;
553 if ((pt.xx[
dim]-R)>mtb->pt.xx[
dim])
557 else if ((pt.xx[
dim]+R)<mtb->pt.xx[
dim])
567 Tfloat dd=Dist(mtb->pt, pt);
570 res.push_back(mtb->ind);
577 for (
auto it=itb; it!=ite; it++)
582 res.push_back(it->ind);
590 typename std::vector<NodeND>::iterator itb,
591 typename std::vector<NodeND>::iterator ite,
593 std::vector<Tindex> & res, std::vector<Tfloat> & dist)
const
595 std::uint8_t
dim=(std::uint8_t) (level%ndim);
597 typename std::vector<NodeND>::iterator mtb=itb+siz/2;
602 if ((pt.xx[
dim]-R)>mtb->pt.xx[
dim])
606 else if ((pt.xx[
dim]+R)<mtb->pt.xx[
dim])
616 Tfloat dd=Dist(mtb->pt, pt);
619 res.push_back(mtb->ind);
627 for (
auto it=itb; it!=ite; it++)
632 res.push_back(it->ind);
Abstract base class for KDTree. Can be used when the dimension of the space is known dynamically.
virtual ~KDTreeBase()
Virtual destructor.
virtual void AddPoint(const Tfloat *xx, Tindex ii)=0
Adds a point to the tree. See KDTree::AddPoint().
virtual void Sort()=0
Sorts the tree. Should be performed after adding points and before performing queries....
virtual Tindex FindClosestPoint(const Tfloat *xx) const =0
Returns the index of the closest point to xx.
void FindClosestPointSlow(const PointND &pt, Tindex &ind, Tfloat &dist) const
Brute force search - please, use it only for debuging purposes.
Tindex FindClosestPoint(const PointND &pt, const PointND &clp) const
Finds the nearest neighbour index and return the clossest point in clp.
std::vector< NodeND >::iterator iterator
Data iterator.
void FindNeighborPoints(const PointND &pt, Tfloat R, std::vector< Tindex > &res, std::vector< Tfloat > &dist)
size_t size() const
Returns the size of the point cloud.
void FindClosestPoint(const PointND &pt, Tindex &ind, Tfloat &dist, PointND &clp) const
Returns the closest point and the distance to the input point pt.
void FindNeighborPointsSlow(const PointND &pt, Tfloat R, std::vector< Tindex > &res)
Brute force search - please, use it only for debuging purposes.
Tindex FindClosestPoint(const PointND &pt) const
Finds the nearest neighbour index.
void FindNeighborPoints(const PointND &pt, Tfloat R, std::vector< Tindex > &res)
void AddPoint(const PointND &pt, Tindex ii)
Adds a new node to the point cloud.
KDTree()=default
Default constructor.
iterator end()
Returns iterator to the end of the point cloud.
void AddPoint(const Tfloat *xx, Tindex ii) override
Adds a new node by coordinates and an associated index.
iterator begin()
Returns iterator to beginning of the point cloud.
void clear()
Clears the point cloud.
void FindNeighborPointsSlow(const PointND &pt, Tfloat R, std::vector< Tindex > &res, std::vector< Tfloat > &dist)
Brute force search - please, use it only for debuging purposes.
int SpaceDimension() const
Returns the spatial dimension of the points.
void FindClosestPoint(const PointND &pt, Tindex &ind, Tfloat &dist) const
Returns the closest point and the distance to the input point pt.
Tindex FindClosestPoint(const Tfloat *xx) const override
Returns the index of the closest point to xx.
KDTree< int, real_t, 1 > KDTree1D
Defines KDTree in 1D.
KDTree< int, real_t, 3 > KDTree3D
Defines KDTree in 3D.
KDTree< int, real_t, 2 > KDTree2D
Defines KDTree in 2D.
Evaluates l1 norm of a vector.
Tfloat operator()(const Tfloat *xx) const
Evaluates l2 norm of a vector.
Tfloat operator()(const Tfloat *xx) const
Finds the max absolute value of a vector.
Tfloat operator()(const Tfloat *xx) const
Structure defining a node in the KDTree.
NodeND()=default
Default constructor: fill with zeros.
Tindex ind
Defines the attached index.
PointND pt
Defines a point in the ndim-dimensional space.
NodeND(PointND pt_, Tindex ind_=0)
Create from given point and index.
PointND()
Default constructor: fill with zeros.
Tfloat xx[ndim]
Coordinates of the point.
PointND(const Tfloat *xx_)
Copy coordinates from pointer/array xx_.