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 // This file contains documentation of the various coordinate systems used
19 // throughout the library.  Most importantly, S2 defines a framework for
20 // decomposing the unit sphere into a hierarchy of "cells".  Each cell is a
21 // quadrilateral bounded by four geodesics.  The top level of the hierarchy is
22 // obtained by projecting the six faces of a cube onto the unit sphere, and
23 // lower levels are obtained by subdividing each cell into four children
24 // recursively.  Cells are numbered such that sequentially increasing cells
25 // follow a continuous space-filling curve over the entire sphere.  The
26 // transformation is designed to make the cells at each level fairly uniform
27 // in size.
28 //
29 //
30 ////////////////////////// S2Cell Decomposition /////////////////////////
31 //
32 // The following methods define the cube-to-sphere projection used by
33 // the S2Cell decomposition.
34 //
35 // In the process of converting a latitude-longitude pair to a 64-bit cell
36 // id, the following coordinate systems are used:
37 //
38 //  (id)
39 //    An S2CellId is a 64-bit encoding of a face and a Hilbert curve position
40 //    on that face.  The Hilbert curve position implicitly encodes both the
41 //    position of a cell and its subdivision level (see s2cell_id.h).
42 //
43 //  (face, i, j)
44 //    Leaf-cell coordinates.  "i" and "j" are integers in the range
45 //    [0,(2**30)-1] that identify a particular leaf cell on the given face.
46 //    The (i, j) coordinate system is right-handed on each face, and the
47 //    faces are oriented such that Hilbert curves connect continuously from
48 //    one face to the next.
49 //
50 //  (face, s, t)
51 //    Cell-space coordinates.  "s" and "t" are real numbers in the range
52 //    [0,1] that identify a point on the given face.  For example, the point
53 //    (s, t) = (0.5, 0.5) corresponds to the center of the top-level face
54 //    cell.  This point is also a vertex of exactly four cells at each
55 //    subdivision level greater than zero.
56 //
57 //  (face, si, ti)
58 //    Discrete cell-space coordinates.  These are obtained by multiplying
59 //    "s" and "t" by 2**31 and rounding to the nearest unsigned integer.
60 //    Discrete coordinates lie in the range [0,2**31].  This coordinate
61 //    system can represent the edge and center positions of all cells with
62 //    no loss of precision (including non-leaf cells).  In binary, each
63 //    coordinate of a level-k cell center ends with a 1 followed by
64 //    (30 - k) 0s.  The coordinates of its edges end with (at least)
65 //    (31 - k) 0s.
66 //
67 //  (face, u, v)
68 //    Cube-space coordinates in the range [-1,1].  To make the cells at each
69 //    level more uniform in size after they are projected onto the sphere,
70 //    we apply a nonlinear transformation of the form u=f(s), v=f(t).
71 //    The (u, v) coordinates after this transformation give the actual
72 //    coordinates on the cube face (modulo some 90 degree rotations) before
73 //    it is projected onto the unit sphere.
74 //
75 //  (face, u, v, w)
76 //    Per-face coordinate frame.  This is an extension of the (face, u, v)
77 //    cube-space coordinates that adds a third axis "w" in the direction of
78 //    the face normal.  It is always a right-handed 3D coordinate system.
79 //    Cube-space coordinates can be converted to this frame by setting w=1,
80 //    while (u,v,w) coordinates can be projected onto the cube face by
81 //    dividing by w, i.e. (face, u/w, v/w).
82 //
83 //  (x, y, z)
84 //    Direction vector (S2Point).  Direction vectors are not necessarily unit
85 //    length, and are often chosen to be points on the biunit cube
86 //    [-1,+1]x[-1,+1]x[-1,+1].  They can be be normalized to obtain the
87 //    corresponding point on the unit sphere.
88 //
89 //  (lat, lng)
90 //    Latitude and longitude (S2LatLng).  Latitudes must be between -90 and
91 //    90 degrees inclusive, and longitudes must be between -180 and 180
92 //    degrees inclusive.
93 //
94 // Note that the (i, j), (s, t), (si, ti), and (u, v) coordinate systems are
95 // right-handed on all six faces.
96 
97 #ifndef S2_S2COORDS_H_
98 #define S2_S2COORDS_H_
99 
100 #include <algorithm>
101 #include <cmath>
102 
103 #include "s2/base/integral_types.h"
104 #include "s2/base/logging.h"
105 #include "s2/r2.h"
106 #include "s2/s2coords_internal.h"
107 #include "s2/s2point.h"
108 #include "s2/util/math/mathutil.h"
109 
110 // S2 is a namespace for constants and simple utility functions that are used
111 // throughout the S2 library.  The name "S2" is derived from the mathematical
112 // symbol for the two-dimensional unit sphere (note that the "2" refers to the
113 // dimension of the surface, not the space it is embedded in).
114 namespace S2 {
115 
116 // This is the number of levels needed to specify a leaf cell.  This
117 // constant is defined here so that the S2::Metric class and the conversion
118 // functions below can be implemented without including s2cell_id.h.  Please
119 // see s2cell_id.h for other useful constants and conversion functions.
120 const int kMaxCellLevel = 30;
121 
122 // The maximum index of a valid leaf cell plus one.  The range of valid leaf
123 // cell indices is [0..kLimitIJ-1].
124 const int kLimitIJ = 1 << kMaxCellLevel;  // == S2CellId::kMaxSize
125 
126 // The maximum value of an si- or ti-coordinate.  The range of valid (si,ti)
127 // values is [0..kMaxSiTi].
128 unsigned const int kMaxSiTi = 1U << (kMaxCellLevel + 1);
129 
130 // Convert an s- or t-value to the corresponding u- or v-value.  This is
131 // a non-linear transformation from [-1,1] to [-1,1] that attempts to
132 // make the cell sizes more uniform.
133 double STtoUV(double s);
134 
135 // The inverse of the STtoUV transformation.  Note that it is not always
136 // true that UVtoST(STtoUV(x)) == x due to numerical errors.
137 double UVtoST(double u);
138 
139 // Convert the i- or j-index of a leaf cell to the minimum corresponding s-
140 // or t-value contained by that cell.  The argument must be in the range
141 // [0..2**30], i.e. up to one position beyond the normal range of valid leaf
142 // cell indices.
143 double IJtoSTMin(int i);
144 
145 // Return the i- or j-index of the leaf cell containing the given
146 // s- or t-value.  If the argument is outside the range spanned by valid
147 // leaf cell indices, return the index of the closest valid leaf cell (i.e.,
148 // return values are clamped to the range of valid leaf cell indices).
149 int STtoIJ(double s);
150 
151 // Convert an si- or ti-value to the corresponding s- or t-value.
152 double SiTitoST(unsigned int si);
153 
154 // Return the si- or ti-coordinate that is nearest to the given s- or
155 // t-value.  The result may be outside the range of valid (si,ti)-values.
156 unsigned int STtoSiTi(double s);
157 
158 // Convert (face, u, v) coordinates to a direction vector (not
159 // necessarily unit length).
160 S2Point FaceUVtoXYZ(int face, double u, double v);
161 S2Point FaceUVtoXYZ(int face, const R2Point& uv);
162 
163 // If the dot product of p with the given face normal is positive,
164 // set the corresponding u and v values (which may lie outside the range
165 // [-1,1]) and return true.  Otherwise return false.
166 bool FaceXYZtoUV(int face, const S2Point& p,
167                         double* pu, double* pv);
168 bool FaceXYZtoUV(int face, const S2Point& p, R2Point* puv);
169 
170 // Given a *valid* face for the given point p (meaning that dot product
171 // of p with the face normal is positive), return the corresponding
172 // u and v values (which may lie outside the range [-1,1]).
173 void ValidFaceXYZtoUV(int face, const S2Point& p,
174                              double* pu, double* pv);
175 void ValidFaceXYZtoUV(int face, const S2Point& p, R2Point* puv);
176 
177 // Transform the given point P to the (u,v,w) coordinate frame of the given
178 // face (where the w-axis represents the face normal).
179 S2Point FaceXYZtoUVW(int face, const S2Point& p);
180 
181 // Return the face containing the given direction vector.  (For points on
182 // the boundary between faces, the result is arbitrary but repeatable.)
183 int GetFace(const S2Point& p);
184 
185 // Convert a direction vector (not necessarily unit length) to
186 // (face, u, v) coordinates.
187 int XYZtoFaceUV(const S2Point& p, double* pu, double* pv);
188 int XYZtoFaceUV(const S2Point& p, R2Point* puv);
189 
190 // Convert a direction vector (not necessarily unit length) to
191 // (face, si, ti) coordinates and, if p is exactly equal to the center of a
192 // cell, return the level of this cell (-1 otherwise).
193 int XYZtoFaceSiTi(const S2Point& p, int* face,
194                   unsigned int* si, unsigned int* ti);
195 
196 // Convert (face, si, ti) coordinates to a direction vector (not necessarily
197 // unit length).
198 S2Point FaceSiTitoXYZ(int face, unsigned int si, unsigned int ti);
199 
200 // Return the right-handed normal (not necessarily unit length) for an
201 // edge in the direction of the positive v-axis at the given u-value on
202 // the given face.  (This vector is perpendicular to the plane through
203 // the sphere origin that contains the given edge.)
204 S2Point GetUNorm(int face, double u);
205 
206 // Return the right-handed normal (not necessarily unit length) for an
207 // edge in the direction of the positive u-axis at the given v-value on
208 // the given face.
209 S2Point GetVNorm(int face, double v);
210 
211 // Return the unit-length normal, u-axis, or v-axis for the given face.
212 S2Point GetNorm(int face);
213 S2Point GetUAxis(int face);
214 S2Point GetVAxis(int face);
215 
216 // Return the given axis of the given face (u=0, v=1, w=2).
217 S2Point GetUVWAxis(int face, int axis);
218 
219 // With respect to the (u,v,w) coordinate system of a given face, return the
220 // face that lies in the given direction (negative=0, positive=1) of the
221 // given axis (u=0, v=1, w=2).  For example, GetUVWFace(4, 0, 1) returns the
222 // face that is adjacent to face 4 in the positive u-axis direction.
223 int GetUVWFace(int face, int axis, int direction);
224 
225 
226 //////////////////   Implementation details follow   ////////////////////
227 
228 
229 // We have implemented three different projections from cell-space (s,t) to
230 // cube-space (u,v): linear, quadratic, and tangent.  They have the following
231 // tradeoffs:
232 //
233 //   Linear - This is the fastest transformation, but also produces the least
234 //   uniform cell sizes.  Cell areas vary by a factor of about 5.2, with the
235 //   largest cells at the center of each face and the smallest cells in
236 //   the corners.
237 //
238 //   Tangent - Transforming the coordinates via atan() makes the cell sizes
239 //   more uniform.  The areas vary by a maximum ratio of 1.4 as opposed to a
240 //   maximum ratio of 5.2.  However, each call to atan() is about as expensive
241 //   as all of the other calculations combined when converting from points to
242 //   cell ids, i.e. it reduces performance by a factor of 3.
243 //
244 //   Quadratic - This is an approximation of the tangent projection that
245 //   is much faster and produces cells that are almost as uniform in size.
246 //   It is about 3 times faster than the tangent projection for converting
247 //   cell ids to points or vice versa.  Cell areas vary by a maximum ratio of
248 //   about 2.1.
249 //
250 // Here is a table comparing the cell uniformity using each projection.  "Area
251 // ratio" is the maximum ratio over all subdivision levels of the largest cell
252 // area to the smallest cell area at that level, "edge ratio" is the maximum
253 // ratio of the longest edge of any cell to the shortest edge of any cell at
254 // the same level, and "diag ratio" is the ratio of the longest diagonal of
255 // any cell to the shortest diagonal of any cell at the same level.  "ToPoint"
256 // and "FromPoint" are the times in microseconds required to convert cell ids
257 // to and from points (unit vectors) respectively.  "ToPointRaw" is the time
258 // to convert to a non-unit-length vector, which is all that is needed for
259 // some purposes.
260 //
261 //               Area    Edge    Diag   ToPointRaw  ToPoint  FromPoint
262 //              Ratio   Ratio   Ratio             (microseconds)
263 // -------------------------------------------------------------------
264 // Linear:      5.200   2.117   2.959      0.020     0.087     0.085
265 // Tangent:     1.414   1.414   1.704      0.237     0.299     0.258
266 // Quadratic:   2.082   1.802   1.932      0.033     0.096     0.108
267 //
268 // The worst-case cell aspect ratios are about the same with all three
269 // projections.  The maximum ratio of the longest edge to the shortest edge
270 // within the same cell is about 1.4 and the maximum ratio of the diagonals
271 // within the same cell is about 1.7.
272 //
273 // This data was produced using s2cell_test and s2cell_id_test.
274 
275 #define S2_LINEAR_PROJECTION    0
276 #define S2_TAN_PROJECTION       1
277 #define S2_QUADRATIC_PROJECTION 2
278 
279 #define S2_PROJECTION S2_QUADRATIC_PROJECTION
280 
281 #if S2_PROJECTION == S2_LINEAR_PROJECTION
282 
STtoUV(double s)283 inline double STtoUV(double s) {
284   return 2 * s - 1;
285 }
286 
UVtoST(double u)287 inline double UVtoST(double u) {
288   return 0.5 * (u + 1);
289 }
290 
291 #elif S2_PROJECTION == S2_TAN_PROJECTION
292 
STtoUV(double s)293 inline double STtoUV(double s) {
294   // Unfortunately, tan(M_PI_4) is slightly less than 1.0.  This isn't due to
295   // a flaw in the implementation of tan(), it's because the derivative of
296   // tan(x) at x=pi/4 is 2, and it happens that the two adjacent floating
297   // point numbers on either side of the infinite-precision value of pi/4 have
298   // tangents that are slightly below and slightly above 1.0 when rounded to
299   // the nearest double-precision result.
300 
301   s = std::tan(M_PI_2 * s - M_PI_4);
302   return s + (1.0 / (int64{1} << 53)) * s;
303 }
304 
UVtoST(double u)305 inline double UVtoST(double u) {
306   volatile double a = std::atan(u);
307   return (2 * M_1_PI) * (a + M_PI_4);
308 }
309 
310 #elif S2_PROJECTION == S2_QUADRATIC_PROJECTION
311 
STtoUV(double s)312 inline double STtoUV(double s) {
313   if (s >= 0.5) return (1/3.) * (4*s*s - 1);
314   else          return (1/3.) * (1 - 4*(1-s)*(1-s));
315 }
316 
UVtoST(double u)317 inline double UVtoST(double u) {
318   if (u >= 0) return 0.5 * std::sqrt(1 + 3*u);
319   else        return 1 - 0.5 * std::sqrt(1 - 3*u);
320 }
321 
322 #else
323 
324 #error Unknown value for S2_PROJECTION
325 
326 #endif
327 
IJtoSTMin(int i)328 inline double IJtoSTMin(int i) {
329   S2_DCHECK(i >= 0 && i <= kLimitIJ);
330   return (1.0 / kLimitIJ) * i;
331 }
332 
STtoIJ(double s)333 inline int STtoIJ(double s) {
334   return std::max(0, std::min(kLimitIJ - 1,
335                               MathUtil::FastIntRound(kLimitIJ * s - 0.5)));
336 }
337 
SiTitoST(unsigned int si)338 inline double SiTitoST(unsigned int si) {
339   S2_DCHECK_LE(si, kMaxSiTi);
340   return (1.0 / kMaxSiTi) * si;
341 }
342 
STtoSiTi(double s)343 inline unsigned int STtoSiTi(double s) {
344   // kMaxSiTi == 2^31, so the result doesn't fit in an int32 when s == 1.
345   return static_cast<unsigned int>(MathUtil::FastInt64Round(s * kMaxSiTi));
346 }
347 
FaceUVtoXYZ(int face,double u,double v)348 inline S2Point FaceUVtoXYZ(int face, double u, double v) {
349   switch (face) {
350     case 0:  return S2Point( 1,  u,  v);
351     case 1:  return S2Point(-u,  1,  v);
352     case 2:  return S2Point(-u, -v,  1);
353     case 3:  return S2Point(-1, -v, -u);
354     case 4:  return S2Point( v, -1, -u);
355     default: return S2Point( v,  u, -1);
356   }
357 }
358 
FaceUVtoXYZ(int face,const R2Point & uv)359 inline S2Point FaceUVtoXYZ(int face, const R2Point& uv) {
360   return FaceUVtoXYZ(face, uv[0], uv[1]);
361 }
362 
ValidFaceXYZtoUV(int face,const S2Point & p,double * pu,double * pv)363 inline void ValidFaceXYZtoUV(int face, const S2Point& p,
364                              double* pu, double* pv) {
365   S2_DCHECK_GT(p.DotProd(GetNorm(face)), 0);
366   switch (face) {
367     case 0:  *pu =  p[1] / p[0]; *pv =  p[2] / p[0]; break;
368     case 1:  *pu = -p[0] / p[1]; *pv =  p[2] / p[1]; break;
369     case 2:  *pu = -p[0] / p[2]; *pv = -p[1] / p[2]; break;
370     case 3:  *pu =  p[2] / p[0]; *pv =  p[1] / p[0]; break;
371     case 4:  *pu =  p[2] / p[1]; *pv = -p[0] / p[1]; break;
372     default: *pu = -p[1] / p[2]; *pv = -p[0] / p[2]; break;
373   }
374 }
375 
ValidFaceXYZtoUV(int face,const S2Point & p,R2Point * puv)376 inline void ValidFaceXYZtoUV(int face, const S2Point& p, R2Point* puv) {
377   ValidFaceXYZtoUV(face, p, &(*puv)[0], &(*puv)[1]);
378 }
379 
GetFace(const S2Point & p)380 inline int GetFace(const S2Point& p) {
381   int face = p.LargestAbsComponent();
382   if (p[face] < 0) face += 3;
383   return face;
384 }
385 
XYZtoFaceUV(const S2Point & p,double * pu,double * pv)386 inline int XYZtoFaceUV(const S2Point& p, double* pu, double* pv) {
387   int face = GetFace(p);
388   ValidFaceXYZtoUV(face, p, pu, pv);
389   return face;
390 }
391 
XYZtoFaceUV(const S2Point & p,R2Point * puv)392 inline int XYZtoFaceUV(const S2Point& p, R2Point* puv) {
393   return XYZtoFaceUV(p, &(*puv)[0], &(*puv)[1]);
394 }
395 
FaceXYZtoUV(int face,const S2Point & p,double * pu,double * pv)396 inline bool FaceXYZtoUV(int face, const S2Point& p,
397                         double* pu, double* pv) {
398   if (face < 3) {
399     if (p[face] <= 0) return false;
400   } else {
401     if (p[face-3] >= 0) return false;
402   }
403   ValidFaceXYZtoUV(face, p, pu, pv);
404   return true;
405 }
406 
FaceXYZtoUV(int face,const S2Point & p,R2Point * puv)407 inline bool FaceXYZtoUV(int face, const S2Point& p, R2Point* puv) {
408   return FaceXYZtoUV(face, p, &(*puv)[0], &(*puv)[1]);
409 }
410 
GetUNorm(int face,double u)411 inline S2Point GetUNorm(int face, double u) {
412   switch (face) {
413     case 0:  return S2Point( u, -1,  0);
414     case 1:  return S2Point( 1,  u,  0);
415     case 2:  return S2Point( 1,  0,  u);
416     case 3:  return S2Point(-u,  0,  1);
417     case 4:  return S2Point( 0, -u,  1);
418     default: return S2Point( 0, -1, -u);
419   }
420 }
421 
GetVNorm(int face,double v)422 inline S2Point GetVNorm(int face, double v) {
423   switch (face) {
424     case 0:  return S2Point(-v,  0,  1);
425     case 1:  return S2Point( 0, -v,  1);
426     case 2:  return S2Point( 0, -1, -v);
427     case 3:  return S2Point( v, -1,  0);
428     case 4:  return S2Point( 1,  v,  0);
429     default: return S2Point( 1,  0,  v);
430   }
431 }
432 
GetNorm(int face)433 inline S2Point GetNorm(int face) {
434   return GetUVWAxis(face, 2);
435 }
436 
GetUAxis(int face)437 inline S2Point GetUAxis(int face) {
438   return GetUVWAxis(face, 0);
439 }
440 
GetVAxis(int face)441 inline S2Point GetVAxis(int face) {
442   return GetUVWAxis(face, 1);
443 }
444 
GetUVWAxis(int face,int axis)445 inline S2Point GetUVWAxis(int face, int axis) {
446   const double* p = internal::kFaceUVWAxes[face][axis];
447   return S2Point(p[0], p[1], p[2]);
448 }
449 
GetUVWFace(int face,int axis,int direction)450 inline int GetUVWFace(int face, int axis, int direction) {
451   S2_DCHECK(face >= 0 && face <= 5);
452   S2_DCHECK(axis >= 0 && axis <= 2);
453   S2_DCHECK(direction >= 0 && direction <= 1);
454   return internal::kFaceUVWFaces[face][axis][direction];
455 }
456 
457 }  // namespace S2
458 
459 #endif  // S2_S2COORDS_H_
460