/src/s2geometry/src/s2/s2closest_point_query.h
Line | Count | Source |
1 | | // Copyright 2013 Google Inc. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS-IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | |
16 | | // Author: ericv@google.com (Eric Veach) |
17 | | // |
18 | | // See S2ClosestPointQuery (defined below) for an overview. |
19 | | |
20 | | #ifndef S2_S2CLOSEST_POINT_QUERY_H_ |
21 | | #define S2_S2CLOSEST_POINT_QUERY_H_ |
22 | | |
23 | | #include <vector> |
24 | | |
25 | | #include "s2/_fp_contract_off.h" // IWYU pragma: keep |
26 | | #include "s2/s1angle.h" |
27 | | #include "s2/s1chord_angle.h" |
28 | | #include "s2/s2cell.h" |
29 | | #include "s2/s2closest_point_query_base.h" |
30 | | #include "s2/s2min_distance_targets.h" |
31 | | #include "s2/s2point.h" |
32 | | #include "s2/s2point_index.h" |
33 | | #include "s2/s2shape_index.h" |
34 | | |
35 | | // Options that control the set of points returned. Note that by default |
36 | | // *all* points are returned, so you will always want to set either the |
37 | | // max_results() option or the max_distance() option (or both). |
38 | | // |
39 | | // This class is also available as S2ClosestPointQuery<Data>::Options. |
40 | | // (It is defined here to avoid depending on the "Data" template argument.) |
41 | | class S2ClosestPointQueryOptions : |
42 | | public S2ClosestPointQueryBaseOptions<S2MinDistance> { |
43 | | public: |
44 | | using Distance = S2MinDistance; |
45 | | using Base = S2ClosestPointQueryBaseOptions<Distance>; |
46 | | |
47 | | // See S2ClosestPointQueryBaseOptions for the full set of options. |
48 | | |
49 | | // Specifies that only points whose distance to the target is less than |
50 | | // "max_distance" should be returned. |
51 | | // |
52 | | // Note that points whose distance is exactly equal to "max_distance" are |
53 | | // not returned. Normally this doesn't matter, because distances are not |
54 | | // computed exactly in the first place, but if such points are needed then |
55 | | // see set_inclusive_max_distance() below. |
56 | | // |
57 | | // DEFAULT: Distance::Infinity() |
58 | | void set_max_distance(S1ChordAngle max_distance); |
59 | | |
60 | | // Like set_max_distance(), except that points whose distance is exactly |
61 | | // equal to "max_distance" are also returned. Equivalent to calling |
62 | | // set_max_distance(max_distance.Successor()). |
63 | | void set_inclusive_max_distance(S1ChordAngle max_distance); |
64 | | |
65 | | // Like set_inclusive_max_distance(), except that "max_distance" is also |
66 | | // increased by the maximum error in the distance calculation. This ensures |
67 | | // that all points whose true distance is less than or equal to |
68 | | // "max_distance" will be returned (along with some points whose true |
69 | | // distance is slightly greater). |
70 | | // |
71 | | // Algorithms that need to do exact distance comparisons can use this |
72 | | // option to find a set of candidate points that can then be filtered |
73 | | // further (e.g., using s2pred::CompareDistance). |
74 | | void set_conservative_max_distance(S1ChordAngle max_distance); |
75 | | |
76 | | // Versions of set_max_distance that take an S1Angle argument. (Note that |
77 | | // these functions require a conversion, and that the S1ChordAngle versions |
78 | | // are preferred.) |
79 | | void set_max_distance(S1Angle max_distance); |
80 | | void set_inclusive_max_distance(S1Angle max_distance); |
81 | | void set_conservative_max_distance(S1Angle max_distance); |
82 | | |
83 | | // See S2ClosestPointQueryBaseOptions for documentation. |
84 | | using Base::set_max_error; // S1Chordangle version |
85 | | void set_max_error(S1Angle max_error); // S1Angle version |
86 | | |
87 | | // Inherited options (see s2closest_point_query_base.h for details): |
88 | | using Base::set_max_results; |
89 | | using Base::set_region; |
90 | | using Base::set_use_brute_force; |
91 | | }; |
92 | | |
93 | | // S2ClosestPointQueryTarget represents the geometry to which the distance is |
94 | | // measured. There are subtypes for measuring the distance to a point, an |
95 | | // edge, an S2Cell, or an S2ShapeIndex (an arbitrary collection of geometry). |
96 | | using S2ClosestPointQueryTarget = S2MinDistanceTarget; |
97 | | |
98 | | // Target subtype that computes the closest distance to a point. |
99 | | // |
100 | | // This class is also available as S2ClosestPointQuery<Data>::PointTarget. |
101 | | // (It is defined here to avoid depending on the "Data" template argument.) |
102 | | class S2ClosestPointQueryPointTarget final : public S2MinDistancePointTarget { |
103 | | public: |
104 | | explicit S2ClosestPointQueryPointTarget(const S2Point& point); |
105 | | int max_brute_force_index_size() const override; |
106 | | }; |
107 | | |
108 | | // Target subtype that computes the closest distance to an edge. |
109 | | // |
110 | | // This class is also available as S2ClosestPointQuery<Data>::EdgeTarget. |
111 | | // (It is defined here to avoid depending on the "Data" template argument.) |
112 | | class S2ClosestPointQueryEdgeTarget final : public S2MinDistanceEdgeTarget { |
113 | | public: |
114 | | explicit S2ClosestPointQueryEdgeTarget(const S2Point& a, const S2Point& b); |
115 | | int max_brute_force_index_size() const override; |
116 | | }; |
117 | | |
118 | | // Target subtype that computes the closest distance to an S2Cell |
119 | | // (including the interior of the cell). |
120 | | // |
121 | | // This class is also available as S2ClosestPointQuery<Data>::CellTarget. |
122 | | // (It is defined here to avoid depending on the "Data" template argument.) |
123 | | class S2ClosestPointQueryCellTarget final : public S2MinDistanceCellTarget { |
124 | | public: |
125 | | explicit S2ClosestPointQueryCellTarget(const S2Cell& cell); |
126 | | int max_brute_force_index_size() const override; |
127 | | }; |
128 | | |
129 | | // Target subtype that computes the closest distance to an S2ShapeIndex |
130 | | // (an arbitrary collection of points, polylines, and/or polygons). |
131 | | // |
132 | | // By default, distances are measured to the boundary and interior of |
133 | | // polygons in the S2ShapeIndex rather than to polygon boundaries only. |
134 | | // If you wish to change this behavior, you may call |
135 | | // |
136 | | // target.set_include_interiors(false); |
137 | | // |
138 | | // (see S2MinDistanceShapeIndexTarget for details). |
139 | | // |
140 | | // This class is also available as S2ClosestPointQuery<Data>::ShapeIndexTarget. |
141 | | // (It is defined here to avoid depending on the "Data" template argument.) |
142 | | class S2ClosestPointQueryShapeIndexTarget final : |
143 | | public S2MinDistanceShapeIndexTarget { |
144 | | public: |
145 | | explicit S2ClosestPointQueryShapeIndexTarget(const S2ShapeIndex* index); |
146 | | int max_brute_force_index_size() const override; |
147 | | }; |
148 | | |
149 | | // Given a set of points stored in an S2PointIndex, S2ClosestPointQuery |
150 | | // provides methods that find the closest point(s) to a given query point |
151 | | // or query edge. Example usage: |
152 | | // |
153 | | // void Test(const vector<S2Point>& index_points, |
154 | | // const vector<S2Point>& target_points) { |
155 | | // // The template argument allows auxiliary data to be attached to each |
156 | | // // point (in this case, the array index). |
157 | | // S2PointIndex<int> index; |
158 | | // for (int i = 0; i < index_points.size(); ++i) { |
159 | | // index.Add(index_points[i], i); |
160 | | // } |
161 | | // S2ClosestPointQuery<int> query(&index); |
162 | | // query.mutable_options()->set_max_results(5); |
163 | | // for (const S2Point& target_point : target_points) { |
164 | | // S2ClosestPointQueryPointTarget target(target_point); |
165 | | // for (const auto& result : query.FindClosestPoints(&target)) { |
166 | | // // The Result class contains the following methods: |
167 | | // // distance() is the distance to the target. |
168 | | // // point() is the indexed point. |
169 | | // // data() is the auxiliary data. |
170 | | // DoSomething(target_point, result); |
171 | | // } |
172 | | // } |
173 | | // } |
174 | | // |
175 | | // You can find either the k closest points, or all points within a given |
176 | | // radius, or both (i.e., the k closest points up to a given maximum radius). |
177 | | // E.g. to find all the points within 5 kilometers, call |
178 | | // |
179 | | // query.mutable_options()->set_max_distance( |
180 | | // S2Earth::ToAngle(util::units::Kilometers(5))); |
181 | | // |
182 | | // By default *all* points are returned, so you should always specify either |
183 | | // max_results() or max_distance() or both. There is also a FindClosestPoint() |
184 | | // convenience method that returns only the closest point. |
185 | | // |
186 | | // You can restrict the results to an arbitrary S2Region, for example: |
187 | | // |
188 | | // S2LatLngRect rect(...); |
189 | | // query.mutable_options()->set_region(&rect); // Does *not* take ownership. |
190 | | // |
191 | | // To find the closest points to a query edge rather than a point, use: |
192 | | // |
193 | | // S2ClosestPointQueryEdgeTarget target(v0, v1); |
194 | | // query.FindClosestPoints(&target); |
195 | | // |
196 | | // Similarly you can find the closest points to an S2Cell by using an |
197 | | // S2ClosestPointQuery::CellTarget, and you can find the closest points to an |
198 | | // arbitrary collection of points, polylines, and polygons by using an |
199 | | // S2ClosestPointQuery::ShapeIndexTarget. |
200 | | // |
201 | | // The implementation is designed to be fast for both small and large |
202 | | // point sets. |
203 | | template <class Data> |
204 | | class S2ClosestPointQuery { |
205 | | public: |
206 | | // See S2ClosestPointQueryBase for full documentation. |
207 | | |
208 | | using Index = S2PointIndex<Data>; |
209 | | using PointData = typename Index::PointData; |
210 | | |
211 | | // S2MinDistance is a thin wrapper around S1ChordAngle that implements the |
212 | | // Distance concept required by S2ClosestPointQueryBase. |
213 | | using Distance = S2MinDistance; |
214 | | using Base = S2ClosestPointQueryBase<Distance, Data>; |
215 | | |
216 | | // Each "Result" object represents a closest point. Here are its main |
217 | | // methods (see S2ClosestPointQueryBase::Result for details): |
218 | | // |
219 | | // // The distance from the target to this point. |
220 | | // S1ChordAngle distance() const; |
221 | | // |
222 | | // // The point itself. |
223 | | // const S2Point& point() const; |
224 | | // |
225 | | // // The client-specified data associated with this point. |
226 | | // const Data& data() const; |
227 | | using Result = typename Base::Result; |
228 | | |
229 | | using Options = S2ClosestPointQueryOptions; |
230 | | |
231 | | // The available target types (see definitions above). |
232 | | using Target = S2ClosestPointQueryTarget; |
233 | | using PointTarget = S2ClosestPointQueryPointTarget; |
234 | | using EdgeTarget = S2ClosestPointQueryEdgeTarget; |
235 | | using CellTarget = S2ClosestPointQueryCellTarget; |
236 | | using ShapeIndexTarget = S2ClosestPointQueryShapeIndexTarget; |
237 | | |
238 | | // Convenience constructor that calls Init(). Options may be specified here |
239 | | // or changed at any time using the mutable_options() accessor method. |
240 | | explicit S2ClosestPointQuery(const Index* index, |
241 | | const Options& options = Options()); |
242 | | |
243 | | // Default constructor; requires Init() to be called. |
244 | | S2ClosestPointQuery(); |
245 | | ~S2ClosestPointQuery(); |
246 | | |
247 | | // Initializes the query. Options may be specified here or changed at any |
248 | | // time using the mutable_options() accessor method. |
249 | | // |
250 | | // REQUIRES: "index" must persist for the lifetime of this object. |
251 | | // REQUIRES: ReInit() must be called if "index" is modified. |
252 | | void Init(const Index* index, const Options& options = Options()); |
253 | | |
254 | | // Reinitializes the query. This method must be called whenever the |
255 | | // underlying index is modified. |
256 | | void ReInit(); |
257 | | |
258 | | // Returns a reference to the underlying S2PointIndex. |
259 | | const Index& index() const; |
260 | | |
261 | | // Returns the query options. Options can be modified between queries. |
262 | | const Options& options() const; |
263 | | Options* mutable_options(); |
264 | | |
265 | | // Returns the closest points to the given target that satisfy the current |
266 | | // options. This method may be called multiple times. |
267 | | std::vector<Result> FindClosestPoints(Target* target); |
268 | | |
269 | | // This version can be more efficient when this method is called many times, |
270 | | // since it does not require allocating a new vector on each call. |
271 | | void FindClosestPoints(Target* target, std::vector<Result>* results); |
272 | | |
273 | | //////////////////////// Convenience Methods //////////////////////// |
274 | | |
275 | | // Returns the closest point to the target. If no point satisfies the search |
276 | | // criteria, then a Result object with distance() == Infinity() and |
277 | | // is_empty() == true is returned. |
278 | | Result FindClosestPoint(Target* target); |
279 | | |
280 | | // Returns the minimum distance to the target. If the index or target is |
281 | | // empty, returns S1ChordAngle::Infinity(). |
282 | | // |
283 | | // Use IsDistanceLess() if you only want to compare the distance against a |
284 | | // threshold value, since it is often much faster. |
285 | | S1ChordAngle GetDistance(Target* target); |
286 | | |
287 | | // Returns true if the distance to "target" is less than "limit". |
288 | | // |
289 | | // This method is usually much faster than GetDistance(), since it is much |
290 | | // less work to determine whether the minimum distance is above or below a |
291 | | // threshold than it is to calculate the actual minimum distance. |
292 | | bool IsDistanceLess(Target* target, S1ChordAngle limit); |
293 | | |
294 | | // Like IsDistanceLess(), but also returns true if the distance to "target" |
295 | | // is exactly equal to "limit". |
296 | | bool IsDistanceLessOrEqual(Target* target, S1ChordAngle limit); |
297 | | |
298 | | // Like IsDistanceLessOrEqual(), except that "limit" is increased by the |
299 | | // maximum error in the distance calculation. This ensures that this |
300 | | // function returns true whenever the true, exact distance is less than |
301 | | // or equal to "limit". |
302 | | // |
303 | | // For example, suppose that we want to test whether two geometries might |
304 | | // intersect each other after they are snapped together using S2Builder |
305 | | // (using the IdentitySnapFunction with a given "snap_radius"). Since |
306 | | // S2Builder uses exact distance predicates (s2predicates.h), we need to |
307 | | // measure the distance between the two geometries conservatively. If the |
308 | | // distance is definitely greater than "snap_radius", then the geometries |
309 | | // are guaranteed to not intersect after snapping. |
310 | | bool IsConservativeDistanceLessOrEqual(Target* target, S1ChordAngle limit); |
311 | | |
312 | | private: |
313 | | Options options_; |
314 | | Base base_; |
315 | | }; |
316 | | |
317 | | |
318 | | ////////////////// Implementation details follow //////////////////// |
319 | | |
320 | | |
321 | | inline void S2ClosestPointQueryOptions::set_max_distance( |
322 | 0 | S1ChordAngle max_distance) { |
323 | 0 | Base::set_max_distance(Distance(max_distance)); |
324 | 0 | } |
325 | | |
326 | 0 | inline void S2ClosestPointQueryOptions::set_max_distance(S1Angle max_distance) { |
327 | 0 | Base::set_max_distance(Distance(max_distance)); |
328 | 0 | } |
329 | | |
330 | | inline void S2ClosestPointQueryOptions::set_inclusive_max_distance( |
331 | 0 | S1ChordAngle max_distance) { |
332 | 0 | set_max_distance(max_distance.Successor()); |
333 | 0 | } |
334 | | |
335 | | inline void S2ClosestPointQueryOptions::set_inclusive_max_distance( |
336 | 0 | S1Angle max_distance) { |
337 | 0 | set_inclusive_max_distance(S1ChordAngle(max_distance)); |
338 | 0 | } |
339 | | |
340 | 0 | inline void S2ClosestPointQueryOptions::set_max_error(S1Angle max_error) { |
341 | 0 | Base::set_max_error(S1ChordAngle(max_error)); |
342 | 0 | } |
343 | | |
344 | | inline S2ClosestPointQueryPointTarget::S2ClosestPointQueryPointTarget( |
345 | | const S2Point& point) |
346 | 0 | : S2MinDistancePointTarget(point) { |
347 | 0 | } |
348 | | |
349 | | inline S2ClosestPointQueryEdgeTarget::S2ClosestPointQueryEdgeTarget( |
350 | | const S2Point& a, const S2Point& b) |
351 | 0 | : S2MinDistanceEdgeTarget(a, b) { |
352 | 0 | } |
353 | | |
354 | | inline S2ClosestPointQueryCellTarget::S2ClosestPointQueryCellTarget( |
355 | | const S2Cell& cell) |
356 | | : S2MinDistanceCellTarget(cell) { |
357 | | } |
358 | | |
359 | | inline S2ClosestPointQueryShapeIndexTarget::S2ClosestPointQueryShapeIndexTarget( |
360 | | const S2ShapeIndex* index) |
361 | | : S2MinDistanceShapeIndexTarget(index) { |
362 | | } |
363 | | |
364 | | template <class Data> |
365 | | inline S2ClosestPointQuery<Data>::S2ClosestPointQuery(const Index* index, |
366 | 0 | const Options& options) { |
367 | 0 | Init(index, options); |
368 | 0 | } |
369 | | |
370 | | template <class Data> |
371 | | S2ClosestPointQuery<Data>::S2ClosestPointQuery() { |
372 | | // Prevent inline constructor bloat by defining here. |
373 | | } |
374 | | |
375 | | template <class Data> |
376 | 0 | S2ClosestPointQuery<Data>::~S2ClosestPointQuery() { |
377 | | // Prevent inline destructor bloat by defining here. |
378 | 0 | } |
379 | | |
380 | | template <class Data> |
381 | | void S2ClosestPointQuery<Data>::Init(const Index* index, |
382 | 0 | const Options& options) { |
383 | 0 | options_ = options; |
384 | 0 | base_.Init(index); |
385 | 0 | } |
386 | | |
387 | | template <class Data> |
388 | 0 | inline void S2ClosestPointQuery<Data>::ReInit() { |
389 | 0 | base_.ReInit(); |
390 | 0 | } |
391 | | |
392 | | template <class Data> |
393 | | inline const S2PointIndex<Data>& S2ClosestPointQuery<Data>::index() const { |
394 | | return base_.index(); |
395 | | } |
396 | | |
397 | | template <class Data> |
398 | | inline const S2ClosestPointQueryOptions& S2ClosestPointQuery<Data>::options() |
399 | | const { |
400 | | return options_; |
401 | | } |
402 | | |
403 | | template <class Data> |
404 | | inline S2ClosestPointQueryOptions* |
405 | | S2ClosestPointQuery<Data>::mutable_options() { |
406 | | return &options_; |
407 | | } |
408 | | |
409 | | template <class Data> |
410 | | inline std::vector<typename S2ClosestPointQuery<Data>::Result> |
411 | | S2ClosestPointQuery<Data>::FindClosestPoints(Target* target) { |
412 | | return base_.FindClosestPoints(target, options_); |
413 | | } |
414 | | |
415 | | template <class Data> |
416 | | inline void S2ClosestPointQuery<Data>::FindClosestPoints( |
417 | 0 | Target* target, std::vector<Result>* results) { |
418 | 0 | base_.FindClosestPoints(target, options_, results); |
419 | 0 | } |
420 | | |
421 | | template <class Data> |
422 | | inline typename S2ClosestPointQuery<Data>::Result |
423 | | S2ClosestPointQuery<Data>::FindClosestPoint(Target* target) { |
424 | | static_assert(sizeof(Options) <= 32, "Consider not copying Options here"); |
425 | | Options tmp_options = options_; |
426 | | tmp_options.set_max_results(1); |
427 | | return base_.FindClosestPoint(target, tmp_options); |
428 | | } |
429 | | |
430 | | template <class Data> |
431 | | inline S1ChordAngle S2ClosestPointQuery<Data>::GetDistance(Target* target) { |
432 | | return FindClosestPoint(target).distance(); |
433 | | } |
434 | | |
435 | | template <class Data> |
436 | | bool S2ClosestPointQuery<Data>::IsDistanceLess( |
437 | | Target* target, S1ChordAngle limit) { |
438 | | static_assert(sizeof(Options) <= 32, "Consider not copying Options here"); |
439 | | Options tmp_options = options_; |
440 | | tmp_options.set_max_results(1); |
441 | | tmp_options.set_max_distance(limit); |
442 | | tmp_options.set_max_error(S1ChordAngle::Straight()); |
443 | | return !base_.FindClosestPoint(target, tmp_options).is_empty(); |
444 | | } |
445 | | |
446 | | template <class Data> |
447 | | bool S2ClosestPointQuery<Data>::IsDistanceLessOrEqual( |
448 | | Target* target, S1ChordAngle limit) { |
449 | | static_assert(sizeof(Options) <= 32, "Consider not copying Options here"); |
450 | | Options tmp_options = options_; |
451 | | tmp_options.set_max_results(1); |
452 | | tmp_options.set_inclusive_max_distance(limit); |
453 | | tmp_options.set_max_error(S1ChordAngle::Straight()); |
454 | | return !base_.FindClosestPoint(target, tmp_options).is_empty(); |
455 | | } |
456 | | |
457 | | template <class Data> |
458 | | bool S2ClosestPointQuery<Data>::IsConservativeDistanceLessOrEqual( |
459 | | Target* target, S1ChordAngle limit) { |
460 | | static_assert(sizeof(Options) <= 32, "Consider not copying Options here"); |
461 | | Options tmp_options = options_; |
462 | | tmp_options.set_max_results(1); |
463 | | tmp_options.set_conservative_max_distance(limit); |
464 | | tmp_options.set_max_error(S1ChordAngle::Straight()); |
465 | | return !base_.FindClosestPoint(target, tmp_options).is_empty(); |
466 | | } |
467 | | |
468 | | #endif // S2_S2CLOSEST_POINT_QUERY_H_ |