28 struct kdtree_leaf :
public kdtree_elt_base {
29 kdtree_tab_type::const_iterator it;
30 kdtree_leaf(kdtree_tab_type::const_iterator begin,
31 kdtree_tab_type::const_iterator end) :
32 kdtree_elt_base(unsigned(std::distance(begin,end))) { it = begin; }
35 struct kdtree_node :
public kdtree_elt_base {
37 std::unique_ptr<kdtree_elt_base> left, right;
38 kdtree_node(scalar_type v, std::unique_ptr<kdtree_elt_base> &&left_,
39 std::unique_ptr<kdtree_elt_base> &&right_) :
40 kdtree_elt_base(0), split_v(v),
41 left(std::move(left_)), right(std::move(right_)) {}
44 typedef kdtree_tab_type::iterator ITER;
47 struct component_sort {
49 component_sort(
unsigned d) : dir(d) {}
50 bool operator()(
const index_node_pair& a,
const index_node_pair& b)
51 {
return a.n.at(dir) < b.n.at(dir); }
62 static ITER partition(ITER begin, ITER end,
unsigned dir, scalar_type median) {
65 while (begin <= end && (*begin).n.at(dir) <= median) ++begin;
66 while (begin <= end && (*end).n.at(dir) > median) --end;
67 if (begin < end) { begin->swap(*end); ++begin; --end; }
else break;
76 static std::unique_ptr<kdtree_elt_base> build_tree_(ITER begin,
77 ITER end,
unsigned dir) {
78 if (begin == end)
return 0;
79 size_type npts = std::distance(begin,end);
80 if (npts > kdtree_elt_base::PTS_PER_LEAF) {
84 unsigned ndir_tests = unsigned(dir/N); dir = unsigned(dir % N);
87 std::vector<index_node_pair> v(30);
90 v[i] = begin[rand() % npts];
91 std::sort(v.begin(), v.end(), component_sort(dir));
92 median = (v[v.size()/2-1].n.at(dir)+v[v.size()/2].n.at(dir))/2;
94 itmedian = partition(begin,end,dir,median);
103 std::sort(begin, end, component_sort(dir));
104 itmedian = begin + npts/2 - 1;
105 median = (*itmedian).n[dir];
106 while (itmedian < end && (*itmedian).n[dir] == median) itmedian++;
109 if (ndir_tests == N-1)
110 return std::make_unique<kdtree_leaf>(begin,end);
111 else return std::make_unique<kdtree_node>
113 build_tree_(begin, itmedian,
unsigned((dir+1)%N + (ndir_tests+1)*N)), std::unique_ptr<kdtree_node>());
115 assert((*itmedian).n[dir] >= median && median >= (*(itmedian-1)).n[dir]);
116 return std::make_unique<kdtree_node>
117 (median, build_tree_(begin, itmedian,
unsigned((dir+1)%N)),
118 build_tree_(itmedian,end,
unsigned((dir+1)%N)));
121 return std::make_unique<kdtree_leaf>(begin,end);
126 struct points_in_box_data_ {
127 base_node::const_iterator bmin;
128 base_node::const_iterator bmax;
134 static void points_in_box_(
const points_in_box_data_& p,
135 const kdtree_elt_base *t,
unsigned dir) {
137 const kdtree_node *tn =
static_cast<const kdtree_node*
>(t);
138 if (p.bmin[dir] <= tn->split_v && tn->left.get())
139 points_in_box_(p, tn->left.get(), unsigned((dir+1)%p.N));
140 if (p.bmax[dir] > tn->split_v && tn->right)
141 points_in_box_(p, tn->right.get(),
unsigned((dir+1)%p.N));
143 const kdtree_leaf *tl =
static_cast<const kdtree_leaf*
>(t);
144 kdtree_tab_type::const_iterator itpt = tl->it;
147 base_node::const_iterator it=itpt->n.const_begin();
150 if (it[k] < p.bmin[k] || it[k] > p.bmax[k]) {
151 is_in =
false;
break;
154 if (is_in) p.ipts->push_back(*itpt);
160 struct nearest_neighbor_data_ {
161 base_node::const_iterator pos;
162 index_node_pair *ipt;
164 mutable scalar_type dist2;
165 base_node::iterator vec_to_tree_elm;
169 static void nearest_neighbor_assist(
const nearest_neighbor_data_& p,
170 const kdtree_elt_base *t,
unsigned dir) {
171 scalar_type dist2(0);
173 dist2 += p.vec_to_tree_elm[k] * p.vec_to_tree_elm[k];
174 if (dist2 > p.dist2 && p.dist2 > scalar_type(0))
return;
177 const kdtree_node *tn =
static_cast<const kdtree_node*
>(t);
178 scalar_type tmp = p.vec_to_tree_elm[dir];
179 scalar_type dist = p.pos[dir] - tn->split_v;
180 if (tn->left.get()) {
181 if (dist > tmp) p.vec_to_tree_elm[dir] = dist;
182 nearest_neighbor_assist(p, tn->left.get(),
unsigned((dir+1)%p.N));
183 p.vec_to_tree_elm[dir] = tmp;
186 if (-dist > tmp) p.vec_to_tree_elm[dir] = -dist;
187 nearest_neighbor_assist(p, tn->right.get(),
unsigned((dir+1)%p.N));
188 p.vec_to_tree_elm[dir] = tmp;
192 const kdtree_leaf *tl =
static_cast<const kdtree_leaf*
>(t);
193 kdtree_tab_type::const_iterator itpt = tl->it;
195 dist2 = scalar_type(0);
196 base_node::const_iterator it=itpt->n.const_begin();
198 scalar_type dist = it[k] - p.pos[k];
199 dist2 += dist * dist;
201 if (dist2 < p.dist2 || p.dist2 < scalar_type(0)){
209 static void nearest_neighbor_main(
const nearest_neighbor_data_& p,
210 const kdtree_elt_base *t,
unsigned dir) {
212 const kdtree_node *tn =
static_cast<const kdtree_node*
>(t);
213 scalar_type dist = p.pos[dir] - tn->split_v;
214 if ((dist <= scalar_type(0) && tn->left.get()) || !tn->right.get()) {
215 nearest_neighbor_main(p, tn->left.get(),
unsigned((dir+1)%p.N));
216 }
else if (tn->right.get()) {
217 nearest_neighbor_main(p, tn->right.get(),
unsigned((dir+1)%p.N));
223 if (dist * dist <= p.dist2) {
224 for (
size_type k=0; k < p.N; ++k) p.vec_to_tree_elm[k] = 0.;
225 if ((dist <= scalar_type(0) && tn->right.get()) || !tn->left.get()) {
226 p.vec_to_tree_elm[dir] = -dist;
227 nearest_neighbor_assist(p, tn->right.get(),
unsigned((dir+1)%p.N));
228 }
else if (tn->left.get()) {
229 p.vec_to_tree_elm[dir] = dist;
230 nearest_neighbor_assist(p, tn->left.get(),
unsigned((dir+1)%p.N));
235 nearest_neighbor_assist(p, t, dir);
239 void kdtree::clear_tree() { tree = std::unique_ptr<kdtree_elt_base>(); }
242 const base_node &min,
243 const base_node &max) {
245 if (tree == 0) { tree = build_tree_(pts.begin(), pts.end(), 0);
if (!tree)
return; }
246 base_node bmin(min), bmax(max);
247 for (
size_type i=0; i < bmin.size(); ++i)
if (bmin[i] > bmax[i])
return;
248 points_in_box_data_ p;
249 p.bmin = bmin.const_begin(); p.bmax = bmax.const_begin();
250 p.ipts = &ipts; p.N = N;
251 points_in_box_(p, tree.get(), 0);
254 scalar_type kdtree::nearest_neighbor(index_node_pair &ipt,
255 const base_node &pos) {
259 tree = build_tree_(pts.begin(), pts.end(), 0);
260 if (!tree)
return scalar_type(-1);
262 nearest_neighbor_data_ p;
263 p.pos = pos.const_begin();
266 p.dist2 = scalar_type(-1);
268 p.vec_to_tree_elm = tmp.begin();
269 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