Kd_tree_search.h
1 /* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
2  * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
3  * Author(s): Clement Jamin
4  *
5  * Copyright (C) 2016 Inria
6  *
7  * Modification(s):
8  * - 2019/08 Vincent Rouvreau: Fix issue #10 for CGAL and Eigen3
9  * - YYYY/MM Author: Description of the modification
10  */
11 
12 #ifndef KD_TREE_SEARCH_H_
13 #define KD_TREE_SEARCH_H_
14 
15 #include <gudhi/Debug_utils.h>
16 
17 #include <CGAL/Orthogonal_k_neighbor_search.h>
18 #include <CGAL/Orthogonal_incremental_neighbor_search.h>
19 #include <CGAL/Search_traits.h>
20 #include <CGAL/Search_traits_adapter.h>
21 #include <CGAL/property_map.h>
22 #include <CGAL/version.h> // for CGAL_VERSION_NR
23 
24 #include <Eigen/src/Core/util/Macros.h> // for EIGEN_VERSION_AT_LEAST
25 
26 #include <boost/property_map/property_map.hpp>
27 #include <boost/iterator/counting_iterator.hpp>
28 
29 #include <cstddef>
30 #include <vector>
31 
32 // Make compilation fail - required for external projects - https://github.com/GUDHI/gudhi-devel/issues/10
33 #if CGAL_VERSION_NR < 1041101000
34 # error Kd_tree_search is only available for CGAL >= 4.11
35 #endif
36 
37 #if !EIGEN_VERSION_AT_LEAST(3,1,0)
38 # error Kd_tree_search is only available for Eigen3 >= 3.1.0 installed with CGAL
39 #endif
40 
41 namespace Gudhi {
42 namespace spatial_searching {
43 
69 template <typename Search_traits, typename Point_range>
71  typedef boost::iterator_property_map<
72  typename Point_range::const_iterator,
73  CGAL::Identity_property_map<std::ptrdiff_t> > Point_property_map;
74 
75  public:
77  typedef Search_traits Traits;
79  typedef typename Traits::FT FT;
81  typedef typename Point_range::value_type Point;
82 
83  typedef CGAL::Search_traits<
84  FT, Point,
85  typename Traits::Cartesian_const_iterator_d,
86  typename Traits::Construct_cartesian_const_iterator_d,
87  typename Traits::Dimension> Traits_base;
88 
89  typedef CGAL::Search_traits_adapter<
90  std::ptrdiff_t,
91  Point_property_map,
92  Traits_base> STraits;
93  typedef CGAL::Distance_adapter<
94  std::ptrdiff_t,
95  Point_property_map,
96  CGAL::Euclidean_distance<Traits_base> > Orthogonal_distance;
97 
98  typedef CGAL::Orthogonal_k_neighbor_search<STraits> K_neighbor_search;
99  typedef typename K_neighbor_search::Tree Tree;
100  typedef typename K_neighbor_search::Distance Distance;
104  typedef K_neighbor_search KNS_range;
105 
106  typedef CGAL::Orthogonal_incremental_neighbor_search<
107  STraits, Distance, CGAL::Sliding_midpoint<STraits>, Tree>
108  Incremental_neighbor_search;
112  typedef Incremental_neighbor_search INS_range;
113 
114  // Because CGAL::Fuzzy_sphere takes the radius and not its square
115  struct Sphere_for_kdtree_search
116  {
117  typedef typename Traits::Point_d Point_d;
118  typedef typename Traits::FT FT;
119  typedef typename Traits::Dimension D;
120  typedef D Dimension;
121 
122  private:
123  STraits traits;
124  Point_d c;
125  FT sqradmin, sqradmax;
126  bool use_max;
127 
128  public:
129  // `prefer_max` means that we prefer outputting more points at squared distance between r2min and r2max,
130  // while `!prefer_max` means we prefer fewer.
131  Sphere_for_kdtree_search(Point_d const& c_, FT const& r2min, FT const& r2max, bool prefer_max=true, STraits const& traits_ = {})
132  : traits(traits_), c(c_), sqradmin(r2min), sqradmax(r2max), use_max(prefer_max)
133  { GUDHI_CHECK(r2min >= 0 && r2max >= r2min, "0 <= r2min <= r2max"); }
134 
135  bool contains(std::ptrdiff_t i) const {
136  const Point_d& p = get(traits.point_property_map(), i);
137  auto ccci = traits.construct_cartesian_const_iterator_d_object();
138  return contains_point_given_as_coordinates(ccci(p), ccci(p, 0));
139  }
140 
141  template <typename Coord_iterator>
142  bool contains_point_given_as_coordinates(Coord_iterator pi, Coord_iterator CGAL_UNUSED) const {
143  FT distance = 0;
144  auto ccci = traits.construct_cartesian_const_iterator_d_object();
145  auto ci = ccci(c);
146  auto ce = ccci(c, 0);
147  FT const& limit = use_max ? sqradmax : sqradmin;
148  while (ci != ce) {
149  distance += CGAL::square(*pi++ - *ci++);
150  // I think ClĂ©ment advised to check the distance at every step instead of
151  // just at the end, especially when the dimension becomes large. Distance
152  // isn't part of the concept anyway.
153  if (distance > limit) return false;
154  }
155  return true;
156  }
157 
158  bool inner_range_intersects(CGAL::Kd_tree_rectangle<FT, D> const& rect) const {
159  auto ccci = traits.construct_cartesian_const_iterator_d_object();
160  FT distance = 0;
161  auto ci = ccci(c);
162  auto ce = ccci(c, 0);
163  for (int i = 0; ci != ce; ++i, ++ci) {
164  distance += CGAL::square(CGAL::max<FT>(CGAL::max<FT>(*ci - rect.max_coord(i), rect.min_coord(i) - *ci), 0 ));
165  if (distance > sqradmin) return false;
166  }
167  return true;
168  }
169 
170 
171  bool outer_range_contains(CGAL::Kd_tree_rectangle<FT, D> const& rect) const {
172  auto ccci = traits.construct_cartesian_const_iterator_d_object();
173  FT distance = 0;
174  auto ci = ccci(c);
175  auto ce = ccci(c, 0);
176  for (int i = 0; ci != ce; ++i, ++ci) {
177  distance += CGAL::square(CGAL::max<FT>(*ci - rect.min_coord(i), rect.max_coord(i) - *ci));
178  if (distance > sqradmax) return false;
179  }
180  return true;
181  }
182  };
183 
187  Kd_tree_search(Point_range const& points)
188  : m_points(points),
189  m_tree(boost::counting_iterator<std::ptrdiff_t>(0),
190  boost::counting_iterator<std::ptrdiff_t>(points.size()),
191  typename Tree::Splitter(),
192  STraits(std::begin(points))) {
193  // Build the tree now (we don't want to wait for the first query)
194  m_tree.build();
195  }
196 
202  template <typename Point_indices_range>
204  Point_range const& points,
205  Point_indices_range const& only_these_points)
206  : m_points(points),
207  m_tree(
208  only_these_points.begin(), only_these_points.end(),
209  typename Tree::Splitter(),
210  STraits(std::begin(points))) {
211  // Build the tree now (we don't want to wait for the first query)
212  m_tree.build();
213  }
214 
221  Point_range const& points,
222  std::size_t begin_idx, std::size_t past_the_end_idx)
223  : m_points(points),
224  m_tree(
225  boost::counting_iterator<std::ptrdiff_t>(begin_idx),
226  boost::counting_iterator<std::ptrdiff_t>(past_the_end_idx),
227  typename Tree::Splitter(),
228  STraits(std::begin(points))) {
229  // Build the tree now (we don't want to wait for the first query)
230  m_tree.build();
231  }
232 
233  // Be careful, this function invalidates the tree,
234  // which will be recomputed at the next query
235  void insert(std::ptrdiff_t point_idx) {
236  m_tree.insert(point_idx);
237  }
238 
246  Point const& p,
247  unsigned int k,
248  bool sorted = true,
249  FT eps = FT(0)) const {
250  // Initialize the search structure, and search all N points
251  // Note that we need to pass the Distance explicitly since it needs to
252  // know the property map
253  K_neighbor_search search(
254  m_tree,
255  p,
256  k,
257  eps,
258  true,
259  Orthogonal_distance(std::begin(m_points)), sorted);
260 
261  return search;
262  }
263 
271  INS_range incremental_nearest_neighbors(Point const& p, FT eps = FT(0)) const {
272  // Initialize the search structure, and search all N points
273  // Note that we need to pass the Distance explicitly since it needs to
274  // know the property map
275  Incremental_neighbor_search search(
276  m_tree,
277  p,
278  eps,
279  true,
280  Orthogonal_distance(std::begin(m_points)) );
281 
282  return search;
283  }
284 
292  Point const& p,
293  unsigned int k,
294  bool sorted = true,
295  FT eps = FT(0)) const {
296  // Initialize the search structure, and search all N points
297  // Note that we need to pass the Distance explicitly since it needs to
298  // know the property map
299  K_neighbor_search search(
300  m_tree,
301  p,
302  k,
303  eps,
304  false,
305  Orthogonal_distance(std::begin(m_points)), sorted);
306 
307  return search;
308  }
309 
317  INS_range incremental_furthest_neighbors(Point const& p, FT eps = FT(0)) const {
318  // Initialize the search structure, and search all N points
319  // Note that we need to pass the Distance explicitly since it needs to
320  // know the property map
321  Incremental_neighbor_search search(
322  m_tree,
323  p,
324  eps,
325  false,
326  Orthogonal_distance(std::begin(m_points)) );
327 
328  return search;
329  }
330 
337  template <typename OutputIterator>
338  void all_near_neighbors(Point const& p,
339  FT const& radius,
340  OutputIterator it,
341  FT eps = FT(0)) const {
342  all_near_neighbors2(p, CGAL::square(radius - eps), CGAL::square(radius + eps), it);
343  }
344 
353  template <typename OutputIterator>
354  void all_near_neighbors2(Point const& p,
355  FT const& sq_radius_min,
356  FT const& sq_radius_max,
357  OutputIterator it) const {
358  m_tree.search(it, Sphere_for_kdtree_search(p, sq_radius_min, sq_radius_max, true, m_tree.traits()));
359  }
360 
361  int tree_depth() const {
362  return m_tree.root()->depth();
363  }
364 
365  private:
366  Point_range const& m_points;
367  Tree m_tree;
368 };
369 
370 } // namespace spatial_searching
371 } // namespace Gudhi
372 
373 #endif // KD_TREE_SEARCH_H_
Spatial tree data structure to perform (approximate) nearest and furthest neighbor search...
Definition: Kd_tree_search.h:70
void all_near_neighbors(Point const &p, FT const &radius, OutputIterator it, FT eps=FT(0)) const
Search for all the neighbors in a ball.
Definition: Kd_tree_search.h:338
void all_near_neighbors2(Point const &p, FT const &sq_radius_min, FT const &sq_radius_max, OutputIterator it) const
Search for all the neighbors in a ball. This is similar to all_near_neighbors but takes directly the ...
Definition: Kd_tree_search.h:354
Kd_tree_search(Point_range const &points, std::size_t begin_idx, std::size_t past_the_end_idx)
Constructor.
Definition: Kd_tree_search.h:220
Kd_tree_search(Point_range const &points, Point_indices_range const &only_these_points)
Constructor.
Definition: Kd_tree_search.h:203
Incremental_neighbor_search INS_range
The range returned by an incremental nearest or furthest neighbor search. Its value type is std::pair...
Definition: Kd_tree_search.h:112
K_neighbor_search KNS_range
The range returned by a k-nearest or k-furthest neighbor search. Its value type is std::pair<std::siz...
Definition: Kd_tree_search.h:104
INS_range incremental_furthest_neighbors(Point const &p, FT eps=FT(0)) const
Search incrementally for the furthest neighbors from a query point.
Definition: Kd_tree_search.h:317
KNS_range k_nearest_neighbors(Point const &p, unsigned int k, bool sorted=true, FT eps=FT(0)) const
Search for the k-nearest neighbors from a query point.
Definition: Kd_tree_search.h:245
Kd_tree_search(Point_range const &points)
Constructor.
Definition: Kd_tree_search.h:187
Definition: SimplicialComplexForAlpha.h:14
INS_range incremental_nearest_neighbors(Point const &p, FT eps=FT(0)) const
Search incrementally for the nearest neighbors from a query point.
Definition: Kd_tree_search.h:271
KNS_range k_furthest_neighbors(Point const &p, unsigned int k, bool sorted=true, FT eps=FT(0)) const
Search for the k-furthest points from a query point.
Definition: Kd_tree_search.h:291
Traits::FT FT
Number type used for distances.
Definition: Kd_tree_search.h:79
Point_range::value_type Point
The point type.
Definition: Kd_tree_search.h:81
Search_traits Traits
The Traits.
Definition: Kd_tree_search.h:77
GUDHI  Version 3.4.0  - C++ library for Topological Data Analysis (TDA) and Higher Dimensional Geometry Understanding.  - Copyright : MIT Generated on Tue Dec 15 2020 16:00:41 for GUDHI by Doxygen 1.8.13