Coverage Report

Created: 2026-06-30 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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_