Loading...
Searching...
No Matches
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
41namespace Gudhi {
42namespace spatial_searching {
43
69template <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) 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
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
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>
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>
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
Point_range::value_type Point
The point type.
Definition: Kd_tree_search.h:81
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
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
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
Traits::FT FT
Number type used for distances.
Definition: Kd_tree_search.h:79
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
Kd_tree_search(Point_range const &points)
Constructor.
Definition: Kd_tree_search.h:187
Search_traits Traits
The Traits.
Definition: Kd_tree_search.h:77
Kd_tree_search(Point_range const &points, Point_indices_range const &only_these_points)
Constructor.
Definition: Kd_tree_search.h:203
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, std::size_t begin_idx, std::size_t past_the_end_idx)
Constructor.
Definition: Kd_tree_search.h:220
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
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
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