xc
node.hpp
Go to the documentation of this file.
1 
7 #ifndef INCLUDE_KDTREE_NODE_HPP
8 #define INCLUDE_KDTREE_NODE_HPP
9 
10 #ifdef KDTREE_DEFINE_OSTREAM_OPERATORS
11 # include <ostream>
12 #endif
13 
14 #include <cstddef>
15 #include <cmath>
16 
17 namespace kd_tree
18 {
19  struct _Node_base
20  {
21  typedef _Node_base* _Base_ptr;
22  typedef _Node_base const* _Base_const_ptr;
23 
24  _Base_ptr _M_parent;
25  _Base_ptr _M_left;
26  _Base_ptr _M_right;
27 
28  _Node_base(_Base_ptr const __PARENT = NULL,
29  _Base_ptr const __LEFT = NULL,
30  _Base_ptr const __RIGHT = NULL)
31  : _M_parent(__PARENT), _M_left(__LEFT), _M_right(__RIGHT) {}
32 
33  static _Base_ptr
34  _S_minimum(_Base_ptr __x)
35  {
36  while (__x->_M_left) __x = __x->_M_left;
37  return __x;
38  }
39 
40  static _Base_ptr
41  _S_maximum(_Base_ptr __x)
42  {
43  while (__x->_M_right) __x = __x->_M_right;
44  return __x;
45  }
46  };
47 
48  template <typename _Val>
49  struct _Node : public _Node_base
50  {
52  typedef _Node* _Link_type;
53 
54  _Val _M_value;
55 
56  _Node(_Val const& __VALUE = _Val(),
57  _Base_ptr const __PARENT = NULL,
58  _Base_ptr const __LEFT = NULL,
59  _Base_ptr const __RIGHT = NULL)
60  : _Node_base(__PARENT, __LEFT, __RIGHT), _M_value(__VALUE) {}
61 
62 #ifdef KDTREE_DEFINE_OSTREAM_OPERATORS
63 
64  template <typename Char, typename Traits>
65  friend
66  std::basic_ostream<Char, Traits>&
67  operator<<(typename std::basic_ostream<Char, Traits>& out,
68  _Node_base const& node)
69  {
70  out << &node;
71  out << " parent: " << node._M_parent;
72  out << "; left: " << node._M_left;
73  out << "; right: " << node._M_right;
74  return out;
75  }
76 
77  template <typename Char, typename Traits>
78  friend
79  std::basic_ostream<Char, Traits>&
80  operator<<(typename std::basic_ostream<Char, Traits>& out,
81  _Node<_Val> const& node)
82  {
83  out << &node;
84  out << ' ' << node._M_value;
85  out << "; parent: " << node._M_parent;
86  out << "; left: " << node._M_left;
87  out << "; right: " << node._M_right;
88  return out;
89  }
90 
91 #endif
92  };
93 
94  template <typename _Val, typename _Acc, typename _Cmp>
96  {
97  public:
98  _Node_compare(size_t const __DIM, _Acc const& acc, _Cmp const& cmp)
99  : _M_DIM(__DIM), _M_acc(acc), _M_cmp(cmp) {}
100 
101  bool
102  operator()(_Val const& __A, _Val const& __B) const
103  {
104  return _M_cmp(_M_acc(__A, _M_DIM), _M_acc(__B, _M_DIM));
105  }
106 
107  private:
108  size_t _M_DIM; // don't make this const so that an assignment operator can be auto-generated
109  _Acc _M_acc;
110  _Cmp _M_cmp;
111  };
112 
119  template <typename _ValA, typename _ValB, typename _Cmp,
120  typename _Acc>
121  inline
122  bool
123  _S_node_compare (const size_t __dim,
124  const _Cmp& __cmp, const _Acc& __acc,
125  const _ValA& __a, const _ValB& __b)
126  {
127  return __cmp(__acc(__a, __dim), __acc(__b, __dim));
128  }
129 
135  template <typename _ValA, typename _ValB, typename _Dist,
136  typename _Acc>
137  inline
138  typename _Dist::distance_type
139  _S_node_distance (const size_t __dim,
140  const _Dist& __dist, const _Acc& __acc,
141  const _ValA& __a, const _ValB& __b)
142  {
143  return __dist(__acc(__a, __dim), __acc(__b, __dim));
144  }
145 
152  template <typename _ValA, typename _ValB, typename _Dist,
153  typename _Acc>
154  inline
155  typename _Dist::distance_type
156  _S_accumulate_node_distance (const size_t __dim,
157  const _Dist& __dist, const _Acc& __acc,
158  const _ValA& __a, const _ValB& __b)
159  {
160  typename _Dist::distance_type d = 0;
161  for (size_t i=0; i<__dim; ++i)
162  d += __dist(__acc(__a, i), __acc(__b, i));
163  return d;
164  }
165 
171  template <typename _Val, typename _Cmp, typename _Acc>
172  inline
173  _Node_base*
174  _S_node_descend (const size_t __dim,
175  const _Cmp& __cmp, const _Acc& __acc,
176  const _Val& __val, const _Node_base* __node)
177  {
178  if (_S_node_compare(__dim, __cmp, __acc, __val, static_cast<const _Node<_Val>* >(__node)->_M_value))
179  return __node->_M_left;
180  else
181  return __node->_M_right;
182  }
183 
192  template <class SearchVal,
193  typename _Val, typename _Cmp,
194  typename _Acc, typename _Dist,
195  typename _Predicate>
196  inline
197  std::pair<const _Node<_Val>*,
198  std::pair<size_t, typename _Dist::distance_type> >
199  _S_node_nearest (const size_t __k, size_t __dim, SearchVal const& __val,
200  const _Node<_Val>* __node, const _Node_base* __end,
201  const _Node<_Val>* __best, typename _Dist::distance_type __max,
202  const _Cmp& __cmp, const _Acc& __acc, const _Dist& __dist,
203  _Predicate __p)
204  {
205  const _Node_base* pcur = __node;
206  const _Node_base* cur = _S_node_descend(__dim % __k, __cmp, __acc, __val, __node);
207  size_t cur_dim = __dim+1;
208  // find the smallest __max distance in direct descent
209  while (cur)
210  {
211  if (__p(static_cast<const _Node<_Val>* >(cur)->_M_value))
212  {
213  typename _Dist::distance_type d = 0;
214  for (size_t i=0; i != __k; ++i)
215  d += _S_node_distance(i, __dist, __acc, __val, static_cast<const _Node<_Val>* >(cur)->_M_value);
216  d = sqrt(d);
217  if (d <= __max)
218  // ("bad candidate notes")
219  // Changed: removed this test: || ( d == __max && cur < __best ))
220  // Can't do this optimisation without checking that the current 'best' is not the root AND is not a valid candidate...
221  // This is because find_nearest() etc will call this function with the best set to _M_root EVEN IF _M_root is not a valid answer (eg too far away or doesn't pass the predicate test)
222  {
223  __best = static_cast<const _Node<_Val>* >(cur);
224  __max = d;
225  __dim = cur_dim;
226  }
227  }
228  pcur = cur;
229  cur = _S_node_descend(cur_dim % __k, __cmp, __acc, __val, cur);
230  ++cur_dim;
231  }
232  // swap cur to prev, only prev is a valid node.
233  cur = pcur;
234  --cur_dim;
235  pcur = NULL;
236  // Probe all node's children not visited yet (siblings of the visited nodes).
237  const _Node_base* probe = cur;
238  const _Node_base* pprobe = probe;
239  const _Node_base* near_node;
240  const _Node_base* far_node;
241  size_t probe_dim = cur_dim;
242  if (_S_node_compare(probe_dim % __k, __cmp, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value))
243  near_node = probe->_M_right;
244  else
245  near_node = probe->_M_left;
246  if (near_node
247  // only visit node's children if node's plane intersect hypersphere
248  && (sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value)) <= __max))
249  {
250  probe = near_node;
251  ++probe_dim;
252  }
253  while (cur != __end)
254  {
255  while (probe != cur)
256  {
257  if (_S_node_compare(probe_dim % __k, __cmp, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value))
258  {
259  near_node = probe->_M_left;
260  far_node = probe->_M_right;
261  }
262  else
263  {
264  near_node = probe->_M_right;
265  far_node = probe->_M_left;
266  }
267  if (pprobe == probe->_M_parent) // going downward ...
268  {
269  if (__p(static_cast<const _Node<_Val>* >(probe)->_M_value))
270  {
271  typename _Dist::distance_type d = 0;
272  for (size_t i=0; i < __k; ++i)
273  d += _S_node_distance(i, __dist, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value);
274  d = sqrt(d);
275  if (d <= __max) // CHANGED, see the above notes ("bad candidate notes")
276  {
277  __best = static_cast<const _Node<_Val>* >(probe);
278  __max = d;
279  __dim = probe_dim;
280  }
281  }
282  pprobe = probe;
283  if (near_node)
284  {
285  probe = near_node;
286  ++probe_dim;
287  }
288  else if (far_node &&
289  // only visit node's children if node's plane intersect hypersphere
290  sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value)) <= __max)
291  {
292  probe = far_node;
293  ++probe_dim;
294  }
295  else
296  {
297  probe = probe->_M_parent;
298  --probe_dim;
299  }
300  }
301  else // ... and going upward.
302  {
303  if (pprobe == near_node && far_node
304  // only visit node's children if node's plane intersect hypersphere
305  && sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value)) <= __max)
306  {
307  pprobe = probe;
308  probe = far_node;
309  ++probe_dim;
310  }
311  else
312  {
313  pprobe = probe;
314  probe = probe->_M_parent;
315  --probe_dim;
316  }
317  }
318  }
319  pcur = cur;
320  cur = cur->_M_parent;
321  --cur_dim;
322  pprobe = cur;
323  probe = cur;
324  probe_dim = cur_dim;
325  if (cur != __end)
326  {
327  if (pcur == cur->_M_left)
328  near_node = cur->_M_right;
329  else
330  near_node = cur->_M_left;
331  if (near_node
332  // only visit node's children if node's plane intersect hypersphere
333  && (sqrt(_S_node_distance(cur_dim % __k, __dist, __acc, __val, static_cast<const _Node<_Val>* >(cur)->_M_value)) <= __max))
334  {
335  probe = near_node;
336  ++probe_dim;
337  }
338  }
339  }
340  return std::pair<const _Node<_Val>*,
341  std::pair<size_t, typename _Dist::distance_type> >
342  (__best, std::pair<size_t, typename _Dist::distance_type>
343  (__dim, __max));
344  }
345 
346 
347 } // namespace kd_tree
348 
349 #endif // include guard
350 
351 /* COPYRIGHT --
352  *
353  * This file is part of libkdtree++, a C++ template KD-Tree sorting container.
354  * libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net>
355  * and Sylvain Bougerel <sylvain.bougerel.devel@gmail.com> distributed under the
356  * terms of the Artistic License 2.0. See the ./COPYING file in the source tree
357  * root for more information.
358  *
359  * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
360  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
361  * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
362  */
bool _S_node_compare(const size_t __dim, const _Cmp &__cmp, const _Acc &__acc, const _ValA &__a, const _ValB &__b)
Definition: node.hpp:123
std::pair< const _Node< _Val > *, std::pair< size_t, typename _Dist::distance_type > > _S_node_nearest(const size_t __k, size_t __dim, SearchVal const &__val, const _Node< _Val > *__node, const _Node_base *__end, const _Node< _Val > *__best, typename _Dist::distance_type __max, const _Cmp &__cmp, const _Acc &__acc, const _Dist &__dist, _Predicate __p)
Definition: node.hpp:199
Definition: node.hpp:95
Definition: node.hpp:49
_Dist::distance_type _S_accumulate_node_distance(const size_t __dim, const _Dist &__dist, const _Acc &__acc, const _ValA &__a, const _ValB &__b)
Definition: node.hpp:156
_Node_base * _S_node_descend(const size_t __dim, const _Cmp &__cmp, const _Acc &__acc, const _Val &__val, const _Node_base *__node)
Definition: node.hpp:174
Definition: node.hpp:19
_Dist::distance_type _S_node_distance(const size_t __dim, const _Dist &__dist, const _Acc &__acc, const _ValA &__a, const _ValB &__b)
Definition: node.hpp:139
Definition: allocator.hpp:14