/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_ |