/src/s2geometry/src/s2/s2cell.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 | | #ifndef S2_S2CELL_H_ |
19 | | #define S2_S2CELL_H_ |
20 | | |
21 | | #include <cmath> |
22 | | #include <cstdint> |
23 | | #include <vector> |
24 | | |
25 | | #include "s2/_fp_contract_off.h" // IWYU pragma: keep |
26 | | #include "s2/r2rect.h" |
27 | | #include "s2/s1chord_angle.h" |
28 | | #include "s2/s2cell_id.h" |
29 | | #include "s2/s2coords.h" |
30 | | #include "s2/s2point.h" |
31 | | #include "s2/s2region.h" |
32 | | #include "s2/util/coding/coder.h" |
33 | | #include "s2/util/math/vector.h" |
34 | | |
35 | | class S2Cap; |
36 | | class S2LatLng; |
37 | | class S2LatLngRect; |
38 | | |
39 | | // An S2Cell is an S2Region object that represents a cell. Unlike S2CellIds, |
40 | | // it supports efficient containment and intersection tests. However, it is |
41 | | // also a more expensive representation (currently 48 bytes rather than 8). |
42 | | |
43 | | // This class is intended to be copied by value as desired. It uses |
44 | | // the default copy constructor and assignment operator, however it is |
45 | | // not a "plain old datatype" (POD) because it has virtual functions. |
46 | | class S2Cell final : public S2Region { |
47 | | public: |
48 | | // Canonical identifiers for the boundaries of the cell. It's promised that |
49 | | // both GetVertex() and GetBoundUV().GetVertex() return vertices in this |
50 | | // order. |
51 | | // |
52 | | // That is, for a given boundary k, the edge defining the boundary is: |
53 | | // {GetVertex(k), GetVertex(k+1)} |
54 | | // |
55 | | // The boundaries are defined in UV coordinates. The orientation may be |
56 | | // rotated relative to other face cells, but are consistent within a face |
57 | | // (i.e. a cell's left edge is its left-ward neighbor's right edge). |
58 | | // |
59 | | enum Boundary { |
60 | | // clang-format off |
61 | | kBottomEdge = 0, |
62 | | kRightEdge = 1, |
63 | | kTopEdge = 2, |
64 | | kLeftEdge = 3 |
65 | | // clang-format on |
66 | | }; |
67 | | |
68 | | // The default constructor is required in order to use freelists. |
69 | | // Cells should otherwise always be constructed explicitly. |
70 | 0 | S2Cell() = default; |
71 | | |
72 | | // An S2Cell always corresponds to a particular S2CellId. The other |
73 | | // constructors are just convenience methods. |
74 | | explicit S2Cell(S2CellId id); |
75 | | |
76 | | // Convenience constructors. The S2LatLng must be normalized. |
77 | 0 | explicit S2Cell(const S2Point& p) : S2Cell(S2CellId(p)) {} |
78 | 0 | explicit S2Cell(const S2LatLng& ll) : S2Cell(S2CellId(ll)) {} |
79 | | |
80 | | // Returns the cell corresponding to the given S2 cube face. |
81 | 0 | static S2Cell FromFace(int face) { |
82 | 0 | return S2Cell(S2CellId::FromFace(face)); |
83 | 0 | } |
84 | | |
85 | | // Returns a cell given its face (range 0..5), Hilbert curve position within |
86 | | // that face (an unsigned integer with S2CellId::kPosBits bits), and level |
87 | | // (range 0..kMaxLevel). The given position will be modified to correspond |
88 | | // to the Hilbert curve position at the center of the returned cell. This |
89 | | // is a static function rather than a constructor in order to indicate what |
90 | | // the arguments represent. |
91 | 0 | static S2Cell FromFacePosLevel(int face, uint64_t pos, int level) { |
92 | 0 | return S2Cell(S2CellId::FromFacePosLevel(face, pos, level)); |
93 | 0 | } |
94 | | |
95 | 0 | S2CellId id() const { return id_; } |
96 | 0 | int face() const { return face_; } |
97 | 0 | int level() const { return level_; } |
98 | 0 | int orientation() const { return orientation_; } |
99 | 0 | bool is_leaf() const { return level_ == S2CellId::kMaxLevel; } |
100 | | |
101 | | // These are equivalent to the S2CellId methods, but have a more efficient |
102 | | // implementation since the level has been precomputed. |
103 | | int GetSizeIJ() const; |
104 | | double GetSizeST() const; |
105 | | |
106 | | // Returns the k-th vertex of the cell (k = 0,1,2,3). Vertices are returned |
107 | | // in CCW order (lower left, lower right, upper right, upper left in the UV |
108 | | // plane). The points returned by GetVertexRaw are not normalized. |
109 | | // For convenience, the argument is reduced modulo 4 to the range [0..3]. |
110 | 0 | S2Point GetVertex(int k) const { return GetVertexRaw(k).Normalize(); } |
111 | 0 | S2Point GetVertexRaw(int k) const { |
112 | 0 | return S2::FaceUVtoXYZ(face_, uv_.GetVertex(k)); |
113 | 0 | } |
114 | | |
115 | | // Returns either U or V for the given edge, whichever is constant along it. |
116 | | // |
117 | | // E.g. boundaries 0 and 2 are constant in the V axis so we return those |
118 | | // coordinates, but boundaries 1 and 3 are constant in the U axis, so we |
119 | | // return those coordinates. |
120 | | // |
121 | | // For convenience, the argument is reduced modulo 4 to the range [0..3]. |
122 | 0 | double GetUVCoordOfEdge(int k) const { |
123 | 0 | k %= 4; |
124 | 0 | if (k % 2 == 0) { |
125 | 0 | return GetBoundUV().GetVertex(k).y(); |
126 | 0 | } |
127 | 0 | return GetBoundUV().GetVertex(k).x(); |
128 | 0 | } |
129 | | |
130 | | // Returns either I or J for the given edge, whichever is constant along it. |
131 | | // |
132 | | // E.g. boundaries 0 and 2 are constant in the J axis so we return those |
133 | | // coordinates, but boundaries 1 and 3 are constant in the I axis, so we |
134 | | // return those coordinates. |
135 | | // |
136 | | // The returned value is not clamped to S2::kLimitIJ-1 as in S2::StToIJ, so |
137 | | // that cell edges at the maximum extent of a face are properly returned as |
138 | | // S2::kLimitIJ. |
139 | | // |
140 | | // For convenience, the argument is reduced modulo 4 to the range [0..3]. |
141 | 0 | int32_t GetIJCoordOfEdge(int k) const { |
142 | 0 | // We can just convert UV->ST->IJ for this because the IJ coordinates only |
143 | 0 | // have 30 bits of resolution in each axis. The error in the conversion |
144 | 0 | // will be a couple of epsilon which is <<< 2^-30, so if we use a proper |
145 | 0 | // round-to-nearest operation, we'll always round to the correct IJ value. |
146 | 0 | // |
147 | 0 | // But, we need to explicitly use round here since Mathutil::FastIntRound |
148 | 0 | // rounds differently on different platforms. If we land on 0, we may end |
149 | 0 | // up rounding to -1. |
150 | 0 | // |
151 | 0 | // Intel CPUs that support SSE4.1 have the ROUNDSD instruction, and ARM CPUs |
152 | 0 | // with VFP have the VCVT instruction, both of which can implement correct |
153 | 0 | // rounding efficiently regardless of the current FPU rounding mode. |
154 | 0 | return std::round(S2::kLimitIJ * S2::UVtoST(GetUVCoordOfEdge(k))); |
155 | 0 | } |
156 | | |
157 | | // Returns the inward-facing normal of the great circle passing through the |
158 | | // edge from vertex k to vertex k+1 (mod 4). The normals returned by |
159 | | // GetEdgeRaw are not necessarily unit length, but their length is bounded by |
160 | | // sqrt(2) since the worst case is two components of magnitude 1. |
161 | | // |
162 | | // The vertices returned by GetVertex are not guaranteed to actually be on the |
163 | | // boundary of the cell exactly. Instead, they're the nearest representable |
164 | | // point to the corner. |
165 | | // |
166 | | // Cell edge normals returned by GetEdgeRaw, however, are computed exactly and |
167 | | // can be used with exact predicates to determine spatial relationships to the |
168 | | // cell exactly. |
169 | | // |
170 | | // GetEdge() normalizes it's return value and thus may no longer be exact. |
171 | | // |
172 | | // For convenience, the argument is reduced modulo 4 to the range [0..3]. |
173 | 0 | S2Point GetEdge(int k) const { return GetEdgeRaw(k).Normalize(); } |
174 | | S2Point GetEdgeRaw(int k) const; |
175 | | |
176 | | // If this is not a leaf cell, sets children[0..3] to the four children of |
177 | | // this cell (in traversal order) and return true. Otherwise returns false. |
178 | | // This method is equivalent to the following: |
179 | | // |
180 | | // for (pos=0, id=child_begin(); id != child_end(); id = id.next(), ++pos) |
181 | | // children[pos] = S2Cell(id); |
182 | | // |
183 | | // except that it is more than two times faster. |
184 | | bool Subdivide(S2Cell children[4]) const; |
185 | | |
186 | | // Returns the direction vector corresponding to the center in (s,t)-space of |
187 | | // the given cell. This is the point at which the cell is divided into four |
188 | | // subcells; it is not necessarily the centroid of the cell in (u,v)-space |
189 | | // or (x,y,z)-space. The point returned by GetCenterRaw is not necessarily |
190 | | // unit length. |
191 | 0 | S2Point GetCenter() const { return GetCenterRaw().Normalize(); } |
192 | | S2Point GetCenterRaw() const; |
193 | | |
194 | | // Returns the average area for cells at the given level. |
195 | | static double AverageArea(int level); |
196 | | |
197 | | // Returns the average area of cells at this level in steradians. This is |
198 | | // accurate to within a factor of 1.7 (for S2_QUADRATIC_PROJECTION) and is |
199 | | // extremely cheap to compute. |
200 | 0 | double AverageArea() const { return AverageArea(level_); } |
201 | | |
202 | | // Returns the approximate area of this cell in steradians. This method is |
203 | | // accurate to within 3% percent for all cell sizes and accurate to within |
204 | | // 0.1% for cells at level 5 or higher (i.e. squares 350km to a side or |
205 | | // smaller on the Earth's surface). It is moderately cheap to compute. |
206 | | double ApproxArea() const; |
207 | | |
208 | | // Returns the area of this cell as accurately as possible. This method is |
209 | | // more expensive but it is accurate to 6 digits of precision even for leaf |
210 | | // cells (whose area is approximately 1e-18). |
211 | | double ExactArea() const; |
212 | | |
213 | | // Returns the bounds of this cell in (u,v)-space. |
214 | 0 | R2Rect GetBoundUV() const { return uv_; } |
215 | | |
216 | | // Returns the distance from the cell to the given point. Returns zero if |
217 | | // the point is inside the cell. |
218 | | S1ChordAngle GetDistance(const S2Point& target) const; |
219 | | |
220 | | // Return the distance from the cell boundary to the given point. |
221 | | S1ChordAngle GetBoundaryDistance(const S2Point& target) const; |
222 | | |
223 | | // Returns the maximum distance from the cell (including its interior) to the |
224 | | // given point. |
225 | | S1ChordAngle GetMaxDistance(const S2Point& target) const; |
226 | | |
227 | | // Returns the minimum distance from the cell to the given edge AB. Returns |
228 | | // zero if the edge intersects the cell interior. |
229 | | S1ChordAngle GetDistance(const S2Point& a, const S2Point& b) const; |
230 | | |
231 | | // Returns the maximum distance from the cell (including its interior) to the |
232 | | // given edge AB. |
233 | | S1ChordAngle GetMaxDistance(const S2Point& a, const S2Point& b) const; |
234 | | |
235 | | // Returns the distance from the cell to the given cell. Returns zero if |
236 | | // one cell contains the other. |
237 | | S1ChordAngle GetDistance(const S2Cell& target) const; |
238 | | |
239 | | // Returns the maximum distance from the cell (including its interior) to the |
240 | | // given target cell. |
241 | | S1ChordAngle GetMaxDistance(const S2Cell& target) const; |
242 | | |
243 | | //////////////////////////////////////////////////////////////////////// |
244 | | // S2Region interface (see s2region.h for details): |
245 | | |
246 | | S2Cell* Clone() const override; |
247 | | S2Cap GetCapBound() const override; |
248 | | S2LatLngRect GetRectBound() const override; |
249 | | void GetCellUnionBound(std::vector<S2CellId>* cell_ids) const override; |
250 | | bool Contains(const S2Cell& cell) const override; |
251 | | bool MayIntersect(const S2Cell& cell) const override; |
252 | | |
253 | | // Returns true if the cell contains the given point "p". Note that unlike |
254 | | // S2Loop/S2Polygon, S2Cells are considered to be closed sets. This means |
255 | | // that points along an S2Cell edge (or at a vertex) belong to the adjacent |
256 | | // cell(s) as well. |
257 | | // |
258 | | // If instead you want every point to be contained by exactly one S2Cell, |
259 | | // you will need to convert the S2Cells to S2Loops (which implement point |
260 | | // containment this way). |
261 | | // |
262 | | // The point "p" does not need to be normalized. |
263 | | bool Contains(const S2Point& p) const override; |
264 | | |
265 | | // Appends a serialized representation of the S2Cell to "encoder". |
266 | | // |
267 | | // REQUIRES: "encoder" uses the default constructor, so that its buffer |
268 | | // can be enlarged as necessary by calling Ensure(int). |
269 | | void Encode(Encoder* encoder) const; |
270 | | |
271 | | // Decodes an S2Cell encoded with Encode(). Returns true on success. |
272 | | bool Decode(Decoder* decoder); |
273 | | |
274 | | private: |
275 | | // Returns the latitude or longitude of the cell vertex given by (i,j), |
276 | | // where "i" and "j" are either 0 or 1. |
277 | | double GetLatitude(int i, int j) const; |
278 | | double GetLongitude(int i, int j) const; |
279 | | |
280 | | S1ChordAngle VertexChordDist(const S2Point& p, int i, int j) const; |
281 | | bool UEdgeIsClosest(const S2Point& target, int v_end) const; |
282 | | bool VEdgeIsClosest(const S2Point& target, int u_end) const; |
283 | | |
284 | | // Returns the distance from the given point to the interior of the cell if |
285 | | // "to_interior" is true, and to the boundary of the cell otherwise. |
286 | | S1ChordAngle GetDistanceInternal(const S2Point& target_xyz, |
287 | | bool to_interior) const; |
288 | | |
289 | | // This structure occupies 44 bytes plus one pointer for the vtable. |
290 | | int8_t face_; |
291 | | int8_t level_; |
292 | | int8_t orientation_; |
293 | | S2CellId id_; |
294 | | R2Rect uv_; |
295 | | }; |
296 | | |
297 | 0 | inline bool operator==(const S2Cell& x, const S2Cell& y) { |
298 | 0 | return x.id() == y.id(); |
299 | 0 | } |
300 | | |
301 | 0 | inline bool operator!=(const S2Cell& x, const S2Cell& y) { |
302 | 0 | return x.id() != y.id(); |
303 | 0 | } |
304 | | |
305 | 0 | inline bool operator<(const S2Cell& x, const S2Cell& y) { |
306 | 0 | return x.id() < y.id(); |
307 | 0 | } |
308 | | |
309 | 0 | inline bool operator>(const S2Cell& x, const S2Cell& y) { |
310 | 0 | return x.id() > y.id(); |
311 | 0 | } |
312 | | |
313 | 0 | inline bool operator<=(const S2Cell& x, const S2Cell& y) { |
314 | 0 | return x.id() <= y.id(); |
315 | 0 | } |
316 | | |
317 | 0 | inline bool operator>=(const S2Cell& x, const S2Cell& y) { |
318 | 0 | return x.id() >= y.id(); |
319 | 0 | } |
320 | | |
321 | 0 | inline int S2Cell::GetSizeIJ() const { |
322 | 0 | return S2CellId::GetSizeIJ(level()); |
323 | 0 | } |
324 | | |
325 | 0 | inline double S2Cell::GetSizeST() const { |
326 | 0 | return S2CellId::GetSizeST(level()); |
327 | 0 | } |
328 | | |
329 | | #endif // S2_S2CELL_H_ |