27 struct kdtree_leaf :
public kdtree_elt_base {
28 kdtree_tab_type::const_iterator it;
29 kdtree_leaf(kdtree_tab_type::const_iterator begin,
30 kdtree_tab_type::const_iterator end) :
31 kdtree_elt_base(unsigned(std::distance(begin,end))) { it = begin; }
34 struct kdtree_node :
public kdtree_elt_base {
36 std::unique_ptr<kdtree_elt_base> left, right;
37 kdtree_node(scalar_type v, std::unique_ptr<kdtree_elt_base> &&left_,
38 std::unique_ptr<kdtree_elt_base> &&right_) :
39 kdtree_elt_base(0), split_v(v),
40 left(std::move(left_)), right(std::move(right_)) {}
43 typedef kdtree_tab_type::iterator ITER;
46 struct component_sort {
48 component_sort(
unsigned d) : dir(d) {}
49 bool operator()(
const index_node_pair& a,
const index_node_pair& b)
50 {
return a.n.at(dir) < b.n.at(dir); }
61 static ITER partition(ITER begin, ITER end,
unsigned dir, scalar_type median) {
64 while (begin <= end && (*begin).n.at(dir) <= median) ++begin;
65 while (begin <= end && (*end).n.at(dir) > median) --end;
66 if (begin < end) { begin->swap(*end); ++begin; --end; }
else break;
75 static std::unique_ptr<kdtree_elt_base> build_tree_(ITER begin,
76 ITER end,
unsigned dir) {
77 if (begin == end)
return 0;
78 size_type npts = std::distance(begin,end);
79 if (npts > kdtree_elt_base::PTS_PER_LEAF) {
83 unsigned ndir_tests = unsigned(dir/N); dir = unsigned(dir % N);
86 std::vector<index_node_pair> v(30);
89 v[i] = begin[rand() % npts];
90 std::sort(v.begin(), v.end(), component_sort(dir));
91 median = (v[v.size()/2-1].n.at(dir)+v[v.size()/2].n.at(dir))/2;
93 itmedian = partition(begin,end,dir,median);
102 std::sort(begin, end, component_sort(dir));
103 itmedian = begin + npts/2 - 1;
104 median = (*itmedian).n[dir];
105 while (itmedian < end && (*itmedian).n[dir] == median) itmedian++;
108 if (ndir_tests == N-1)
109 return std::make_unique<kdtree_leaf>(begin,end);
110 else return std::make_unique<kdtree_node>
112 build_tree_(begin, itmedian,
unsigned((dir+1)%N + (ndir_tests+1)*N)), std::unique_ptr<kdtree_node>());
114 assert((*itmedian).n[dir] >= median && median >= (*(itmedian-1)).n[dir]);
115 return std::make_unique<kdtree_node>
116 (median, build_tree_(begin, itmedian,
unsigned((dir+1)%N)),
117 build_tree_(itmedian,end,
unsigned((dir+1)%N)));
120 return std::make_unique<kdtree_leaf>(begin,end);
125 struct points_in_box_data_ {
126 base_node::const_iterator bmin;
127 base_node::const_iterator bmax;
133 static void points_in_box_(
const points_in_box_data_& p,
134 const kdtree_elt_base *t,
unsigned dir) {
136 const kdtree_node *tn =
static_cast<const kdtree_node*
>(t);
137 if (p.bmin[dir] <= tn->split_v && tn->left.get())
138 points_in_box_(p, tn->left.get(), unsigned((dir+1)%p.N));
139 if (p.bmax[dir] > tn->split_v && tn->right)
140 points_in_box_(p, tn->right.get(),
unsigned((dir+1)%p.N));
142 const kdtree_leaf *tl =
static_cast<const kdtree_leaf*
>(t);
143 kdtree_tab_type::const_iterator itpt = tl->it;
146 base_node::const_iterator it=itpt->n.const_begin();
149 if (it[k] < p.bmin[k] || it[k] > p.bmax[k]) {
150 is_in =
false;
break;
153 if (is_in) p.ipts->push_back(*itpt);
159 struct nearest_neighbor_data_ {
160 base_node::const_iterator pos;
161 index_node_pair *ipt;
163 mutable scalar_type dist2;
164 base_node::iterator vec_to_tree_elm;
168 static void nearest_neighbor_assist(
const nearest_neighbor_data_& p,
169 const kdtree_elt_base *t,
unsigned dir) {
170 scalar_type dist2(0);
172 dist2 += p.vec_to_tree_elm[k] * p.vec_to_tree_elm[k];
173 if (dist2 > p.dist2 && p.dist2 > scalar_type(0))
return;
176 const kdtree_node *tn =
static_cast<const kdtree_node*
>(t);
177 scalar_type tmp = p.vec_to_tree_elm[dir];
178 scalar_type dist = p.pos[dir] - tn->split_v;
179 if (tn->left.get()) {
180 if (dist > tmp) p.vec_to_tree_elm[dir] = dist;
181 nearest_neighbor_assist(p, tn->left.get(),
unsigned((dir+1)%p.N));
182 p.vec_to_tree_elm[dir] = tmp;
185 if (-dist > tmp) p.vec_to_tree_elm[dir] = -dist;
186 nearest_neighbor_assist(p, tn->right.get(),
unsigned((dir+1)%p.N));
187 p.vec_to_tree_elm[dir] = tmp;
191 const kdtree_leaf *tl =
static_cast<const kdtree_leaf*
>(t);
192 kdtree_tab_type::const_iterator itpt = tl->it;
194 dist2 = scalar_type(0);
195 base_node::const_iterator it=itpt->n.const_begin();
197 scalar_type dist = it[k] - p.pos[k];
198 dist2 += dist * dist;
200 if (dist2 < p.dist2 || p.dist2 < scalar_type(0)){
208 static void nearest_neighbor_main(
const nearest_neighbor_data_& p,
209 const kdtree_elt_base *t,
unsigned dir) {
211 const kdtree_node *tn =
static_cast<const kdtree_node*
>(t);
212 scalar_type dist = p.pos[dir] - tn->split_v;
213 if ((dist <= scalar_type(0) && tn->left.get()) || !tn->right.get()) {
214 nearest_neighbor_main(p, tn->left.get(),
unsigned((dir+1)%p.N));
215 }
else if (tn->right.get()) {
216 nearest_neighbor_main(p, tn->right.get(),
unsigned((dir+1)%p.N));
222 if (dist * dist <= p.dist2) {
223 for (
size_type k=0; k < p.N; ++k) p.vec_to_tree_elm[k] = 0.;
224 if ((dist <= scalar_type(0) && tn->right.get()) || !tn->left.get()) {
225 p.vec_to_tree_elm[dir] = -dist;
226 nearest_neighbor_assist(p, tn->right.get(),
unsigned((dir+1)%p.N));
227 }
else if (tn->left.get()) {
228 p.vec_to_tree_elm[dir] = dist;
229 nearest_neighbor_assist(p, tn->left.get(),
unsigned((dir+1)%p.N));
234 nearest_neighbor_assist(p, t, dir);
238 void kdtree::clear_tree() { tree = std::unique_ptr<kdtree_elt_base>(); }
241 const base_node &min,
242 const base_node &max) {
244 if (tree == 0) { tree = build_tree_(pts.begin(), pts.end(), 0);
if (!tree)
return; }
245 base_node bmin(min), bmax(max);
246 for (
size_type i=0; i < bmin.size(); ++i)
if (bmin[i] > bmax[i])
return;
247 points_in_box_data_ p;
248 p.bmin = bmin.const_begin(); p.bmax = bmax.const_begin();
249 p.ipts = &ipts; p.N = N;
250 points_in_box_(p, tree.get(), 0);
253 scalar_type kdtree::nearest_neighbor(index_node_pair &ipt,
254 const base_node &pos) {
258 tree = build_tree_(pts.begin(), pts.end(), 0);
259 if (!tree)
return scalar_type(-1);
261 nearest_neighbor_data_ p;
262 p.pos = pos.const_begin();
265 p.dist2 = scalar_type(-1);
267 p.vec_to_tree_elm = tmp.begin();
268 nearest_neighbor_main(p, tree.get(), 0);
Simple implementation of a KD-tree.
std::vector< index_node_pair > kdtree_tab_type
store a set of points with associated indexes.
size_t size_type
used as the common size type in the library