Coverage Report

Created: 2026-06-30 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/s2geometry/src/s2/s2metrics.h
Line
Count
Source
1
// Copyright 2005 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
// The following are various constants that describe the shapes and sizes of
19
// S2Cells (see s2coords.h and s2cell_id.h).  They are useful for deciding
20
// which cell level to use in order to satisfy a given condition (e.g. that
21
// cell vertices must be no further than "x" apart).  All of the raw constants
22
// are differential quantities; you can use the GetValue(level) method to
23
// compute the corresponding length or area on the unit sphere for cells at a
24
// given level.  The minimum and maximum bounds are valid for cells at all
25
// levels, but they may be somewhat conservative for very large cells
26
// (e.g. face cells).
27
28
#ifndef S2_S2METRICS_H_
29
#define S2_S2METRICS_H_
30
31
#include <algorithm>
32
#include <cmath>
33
34
#include "absl/log/absl_check.h"
35
#include "s2/_fp_contract_off.h"  // IWYU pragma: keep
36
#include "s2/s2coords.h"
37
#include "s2/util/math/mathutil.h"
38
39
namespace S2 {
40
41
// Defines a cell metric of the given dimension (1 == length, 2 == area).
42
template <int dim> class Metric {
43
 public:
44
12
  explicit constexpr Metric(double deriv) : deriv_(deriv) {}
S2::Metric<1>::Metric(double)
Line
Count
Source
44
10
  explicit constexpr Metric(double deriv) : deriv_(deriv) {}
S2::Metric<2>::Metric(double)
Line
Count
Source
44
2
  explicit constexpr Metric(double deriv) : deriv_(deriv) {}
45
46
  // The "deriv" value of a metric is a derivative, and must be multiplied by
47
  // a length or area in (s,t)-space to get a useful value.
48
4
  double deriv() const { return deriv_; }
49
50
  // Return the value of a metric for cells at the given level. The value is
51
  // either a length or an area on the unit sphere, depending on the
52
  // particular metric.
53
0
  double GetValue(int level) const { return ldexp(deriv_, - dim * level); }
Unexecuted instantiation: S2::Metric<1>::GetValue(int) const
Unexecuted instantiation: S2::Metric<2>::GetValue(int) const
54
55
  // Return the level at which the metric has approximately the given value.
56
  // For example, S2::kAvgEdge.GetClosestLevel(0.1) returns the level at which
57
  // the average cell edge length is approximately 0.1. The return value is
58
  // always a valid level.
59
  int GetClosestLevel(double value) const;
60
61
  // Return the minimum level such that the metric is at most the given value,
62
  // or S2CellId::kMaxLevel if there is no such level. For example,
63
  // S2::kMaxDiag.GetLevelForMaxValue(0.1) returns the minimum level such
64
  // that all cell diagonal lengths are 0.1 or smaller.  Requires that the
65
  // value is a number (i.e. not NaN).  The return value is always a valid
66
  // level.
67
  int GetLevelForMaxValue(double value) const;
68
69
  // Return the maximum level such that the metric is at least the given value,
70
  // or 0 if there is no such level.  For example,
71
  // S2::kMinWidth.GetLevelForMinValue(0.1) returns the maximum level such that
72
  // all cells have a minimum width of 0.1 or larger.  Requires that the value
73
  // is a number (i.e. not NaN). The return value is always a valid level.
74
  int GetLevelForMinValue(double value) const;
75
76
 private:
77
  const double deriv_;
78
79
  Metric(const Metric&) = delete;
80
  void operator=(const Metric&) = delete;
81
};
82
using LengthMetric = Metric<1>;
83
using AreaMetric = Metric<2>;
84
85
// Each cell is bounded by four planes passing through its four edges and
86
// the center of the sphere.  These metrics relate to the angle between each
87
// pair of opposite bounding planes, or equivalently, between the planes
88
// corresponding to two different s-values or two different t-values.  For
89
// example, the maximum angle between opposite bounding planes for a cell at
90
// level k is kMaxAngleSpan.GetValue(k), and the average angle span for all
91
// cells at level k is approximately kAvgAngleSpan.GetValue(k).
92
extern const LengthMetric kMinAngleSpan;
93
extern const LengthMetric kMaxAngleSpan;
94
extern const LengthMetric kAvgAngleSpan;
95
96
// The width of geometric figure is defined as the distance between two
97
// parallel bounding lines in a given direction.  For cells, the minimum
98
// width is always attained between two opposite edges, and the maximum
99
// width is attained between two opposite vertices.  However, for our
100
// purposes we redefine the width of a cell as the perpendicular distance
101
// between a pair of opposite edges.  A cell therefore has two widths, one
102
// in each direction.  The minimum width according to this definition agrees
103
// with the classic geometric one, but the maximum width is different.  (The
104
// maximum geometric width corresponds to kMaxDiag defined below.)
105
//
106
// For a cell at level k, the distance between opposite edges is at least
107
// kMinWidth.GetValue(k) and at most kMaxWidth.GetValue(k).  The average
108
// width in both directions for all cells at level k is approximately
109
// kAvgWidth.GetValue(k).
110
//
111
// The width is useful for bounding the minimum or maximum distance from a
112
// point on one edge of a cell to the closest point on the opposite edge.
113
// For example, this is useful when "growing" regions by a fixed distance.
114
//
115
// Note that because S2Cells are not usually rectangles, the minimum width of
116
// a cell is generally smaller than its minimum edge length.  (The interior
117
// angles of an S2Cell range from 60 to 120 degrees.)
118
extern const LengthMetric kMinWidth;
119
extern const LengthMetric kMaxWidth;
120
extern const LengthMetric kAvgWidth;
121
122
// The minimum edge length of any cell at level k is at least
123
// kMinEdge.GetValue(k), and the maximum is at most kMaxEdge.GetValue(k).
124
// The average edge length is approximately kAvgEdge.GetValue(k).
125
//
126
// The edge length metrics can also be used to bound the minimum, maximum,
127
// or average distance from the center of one cell to the center of one of
128
// its edge neighbors.  In particular, it can be used to bound the distance
129
// between adjacent cell centers along the space-filling Hilbert curve for
130
// cells at any given level.
131
extern const LengthMetric kMinEdge;
132
extern const LengthMetric kMaxEdge;
133
extern const LengthMetric kAvgEdge;
134
135
// The minimum diagonal length of any cell at level k is at least
136
// kMinDiag.GetValue(k), and the maximum is at most kMaxDiag.GetValue(k).
137
// The average diagonal length is approximately kAvgDiag.GetValue(k).
138
//
139
// The maximum diagonal also happens to be the maximum diameter of any cell,
140
// and also the maximum geometric width (see the discussion above).  So for
141
// example, the distance from an arbitrary point to the closest cell center
142
// at a given level is at most half the maximum diagonal length.
143
extern const LengthMetric kMinDiag;
144
extern const LengthMetric kMaxDiag;
145
extern const LengthMetric kAvgDiag;
146
147
// The minimum area of any cell at level k is at least kMinArea.GetValue(k),
148
// and the maximum is at most kMaxArea.GetValue(k).  The average area of all
149
// cells at level k is exactly kAvgArea.GetValue(k).
150
extern const AreaMetric kMinArea;
151
extern const AreaMetric kMaxArea;
152
extern const AreaMetric kAvgArea;
153
154
// This is the maximum edge aspect ratio over all cells at any level, where
155
// the edge aspect ratio of a cell is defined as the ratio of its longest
156
// edge length to its shortest edge length.
157
extern const double kMaxEdgeAspect;
158
159
// This is the maximum diagonal aspect ratio over all cells at any level,
160
// where the diagonal aspect ratio of a cell is defined as the ratio of its
161
// longest diagonal length to its shortest diagonal length.
162
extern const double kMaxDiagAspect;
163
164
165
//////////////////   Implementation details follow   ////////////////////
166
167
168
template <int dim>
169
0
int S2::Metric<dim>::GetLevelForMaxValue(double value) const {
170
0
  ABSL_DCHECK(!std::isnan(value));
171
  // Catches non-positive values, including NaN.  Be robust to NaN in case
172
  // we hit one in prod, since we can do this cheaply.
173
0
  if (!(value > 0)) return S2::kMaxCellLevel;
174
175
  // This code is equivalent to computing a floating-point "level" value and
176
  // rounding up.  ilogb() returns the exponent corresponding to a fraction in
177
  // the range [1,2).
178
0
  int level = ilogb(value / deriv_);
179
0
  level = std::clamp(-(level >> (dim - 1)), 0, S2::kMaxCellLevel);
180
0
  ABSL_DCHECK(level == S2::kMaxCellLevel || GetValue(level) <= value);
181
0
  ABSL_DCHECK(level == 0 || GetValue(level - 1) > value);
182
0
  return level;
183
0
}
184
185
template <int dim>
186
0
int S2::Metric<dim>::GetLevelForMinValue(double value) const {
187
0
  ABSL_DCHECK(!std::isnan(value));
188
  // Catches non-positive values, including NaN.  The natural extension
189
  // of this function to NaN would return 0, not kMaxCellLevel, since
190
  // there is no level where the metric is >= NaN.
191
0
  if (!(value > 0)) return S2::kMaxCellLevel;
192
193
  // This code is equivalent to computing a floating-point "level" value and
194
  // rounding down.
195
0
  int level = ilogb(deriv_ / value);
196
0
  level = std::clamp(level >> (dim - 1), 0, S2::kMaxCellLevel);
197
0
  ABSL_DCHECK(level == 0 || GetValue(level) >= value);
198
0
  ABSL_DCHECK(level == kMaxCellLevel || GetValue(level + 1) < value);
199
0
  return level;
200
0
}
201
202
template <int dim>
203
int Metric<dim>::GetClosestLevel(double value) const {
204
  return GetLevelForMaxValue((dim == 1 ? M_SQRT2 : 2) * value);
205
}
206
207
}  // namespace S2
208
209
#endif  // S2_S2METRICS_H_