stuv.go (14900B)
1 // Copyright 2014 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 package s2 16 17 import ( 18 "math" 19 20 "github.com/golang/geo/r3" 21 ) 22 23 // 24 // This file contains documentation of the various coordinate systems used 25 // throughout the library. Most importantly, S2 defines a framework for 26 // decomposing the unit sphere into a hierarchy of "cells". Each cell is a 27 // quadrilateral bounded by four geodesics. The top level of the hierarchy is 28 // obtained by projecting the six faces of a cube onto the unit sphere, and 29 // lower levels are obtained by subdividing each cell into four children 30 // recursively. Cells are numbered such that sequentially increasing cells 31 // follow a continuous space-filling curve over the entire sphere. The 32 // transformation is designed to make the cells at each level fairly uniform 33 // in size. 34 // 35 ////////////////////////// S2 Cell Decomposition ///////////////////////// 36 // 37 // The following methods define the cube-to-sphere projection used by 38 // the Cell decomposition. 39 // 40 // In the process of converting a latitude-longitude pair to a 64-bit cell 41 // id, the following coordinate systems are used: 42 // 43 // (id) 44 // An CellID is a 64-bit encoding of a face and a Hilbert curve position 45 // on that face. The Hilbert curve position implicitly encodes both the 46 // position of a cell and its subdivision level (see s2cellid.go). 47 // 48 // (face, i, j) 49 // Leaf-cell coordinates. "i" and "j" are integers in the range 50 // [0,(2**30)-1] that identify a particular leaf cell on the given face. 51 // The (i, j) coordinate system is right-handed on each face, and the 52 // faces are oriented such that Hilbert curves connect continuously from 53 // one face to the next. 54 // 55 // (face, s, t) 56 // Cell-space coordinates. "s" and "t" are real numbers in the range 57 // [0,1] that identify a point on the given face. For example, the point 58 // (s, t) = (0.5, 0.5) corresponds to the center of the top-level face 59 // cell. This point is also a vertex of exactly four cells at each 60 // subdivision level greater than zero. 61 // 62 // (face, si, ti) 63 // Discrete cell-space coordinates. These are obtained by multiplying 64 // "s" and "t" by 2**31 and rounding to the nearest unsigned integer. 65 // Discrete coordinates lie in the range [0,2**31]. This coordinate 66 // system can represent the edge and center positions of all cells with 67 // no loss of precision (including non-leaf cells). In binary, each 68 // coordinate of a level-k cell center ends with a 1 followed by 69 // (30 - k) 0s. The coordinates of its edges end with (at least) 70 // (31 - k) 0s. 71 // 72 // (face, u, v) 73 // Cube-space coordinates in the range [-1,1]. To make the cells at each 74 // level more uniform in size after they are projected onto the sphere, 75 // we apply a nonlinear transformation of the form u=f(s), v=f(t). 76 // The (u, v) coordinates after this transformation give the actual 77 // coordinates on the cube face (modulo some 90 degree rotations) before 78 // it is projected onto the unit sphere. 79 // 80 // (face, u, v, w) 81 // Per-face coordinate frame. This is an extension of the (face, u, v) 82 // cube-space coordinates that adds a third axis "w" in the direction of 83 // the face normal. It is always a right-handed 3D coordinate system. 84 // Cube-space coordinates can be converted to this frame by setting w=1, 85 // while (u,v,w) coordinates can be projected onto the cube face by 86 // dividing by w, i.e. (face, u/w, v/w). 87 // 88 // (x, y, z) 89 // Direction vector (Point). Direction vectors are not necessarily unit 90 // length, and are often chosen to be points on the biunit cube 91 // [-1,+1]x[-1,+1]x[-1,+1]. They can be be normalized to obtain the 92 // corresponding point on the unit sphere. 93 // 94 // (lat, lng) 95 // Latitude and longitude (LatLng). Latitudes must be between -90 and 96 // 90 degrees inclusive, and longitudes must be between -180 and 180 97 // degrees inclusive. 98 // 99 // Note that the (i, j), (s, t), (si, ti), and (u, v) coordinate systems are 100 // right-handed on all six faces. 101 // 102 // 103 // There are a number of different projections from cell-space (s,t) to 104 // cube-space (u,v): linear, quadratic, and tangent. They have the following 105 // tradeoffs: 106 // 107 // Linear - This is the fastest transformation, but also produces the least 108 // uniform cell sizes. Cell areas vary by a factor of about 5.2, with the 109 // largest cells at the center of each face and the smallest cells in 110 // the corners. 111 // 112 // Tangent - Transforming the coordinates via Atan makes the cell sizes 113 // more uniform. The areas vary by a maximum ratio of 1.4 as opposed to a 114 // maximum ratio of 5.2. However, each call to Atan is about as expensive 115 // as all of the other calculations combined when converting from points to 116 // cell ids, i.e. it reduces performance by a factor of 3. 117 // 118 // Quadratic - This is an approximation of the tangent projection that 119 // is much faster and produces cells that are almost as uniform in size. 120 // It is about 3 times faster than the tangent projection for converting 121 // cell ids to points or vice versa. Cell areas vary by a maximum ratio of 122 // about 2.1. 123 // 124 // Here is a table comparing the cell uniformity using each projection. Area 125 // Ratio is the maximum ratio over all subdivision levels of the largest cell 126 // area to the smallest cell area at that level, Edge Ratio is the maximum 127 // ratio of the longest edge of any cell to the shortest edge of any cell at 128 // the same level, and Diag Ratio is the ratio of the longest diagonal of 129 // any cell to the shortest diagonal of any cell at the same level. 130 // 131 // Area Edge Diag 132 // Ratio Ratio Ratio 133 // ----------------------------------- 134 // Linear: 5.200 2.117 2.959 135 // Tangent: 1.414 1.414 1.704 136 // Quadratic: 2.082 1.802 1.932 137 // 138 // The worst-case cell aspect ratios are about the same with all three 139 // projections. The maximum ratio of the longest edge to the shortest edge 140 // within the same cell is about 1.4 and the maximum ratio of the diagonals 141 // within the same cell is about 1.7. 142 // 143 // For Go we have chosen to use only the Quadratic approach. Other language 144 // implementations may offer other choices. 145 146 const ( 147 // maxSiTi is the maximum value of an si- or ti-coordinate. 148 // It is one shift more than maxSize. The range of valid (si,ti) 149 // values is [0..maxSiTi]. 150 maxSiTi = maxSize << 1 151 ) 152 153 // siTiToST converts an si- or ti-value to the corresponding s- or t-value. 154 // Value is capped at 1.0 because there is no DCHECK in Go. 155 func siTiToST(si uint32) float64 { 156 if si > maxSiTi { 157 return 1.0 158 } 159 return float64(si) / float64(maxSiTi) 160 } 161 162 // stToSiTi converts the s- or t-value to the nearest si- or ti-coordinate. 163 // The result may be outside the range of valid (si,ti)-values. Value of 164 // 0.49999999999999994 (math.NextAfter(0.5, -1)), will be incorrectly rounded up. 165 func stToSiTi(s float64) uint32 { 166 if s < 0 { 167 return uint32(s*maxSiTi - 0.5) 168 } 169 return uint32(s*maxSiTi + 0.5) 170 } 171 172 // stToUV converts an s or t value to the corresponding u or v value. 173 // This is a non-linear transformation from [-1,1] to [-1,1] that 174 // attempts to make the cell sizes more uniform. 175 // This uses what the C++ version calls 'the quadratic transform'. 176 func stToUV(s float64) float64 { 177 if s >= 0.5 { 178 return (1 / 3.) * (4*s*s - 1) 179 } 180 return (1 / 3.) * (1 - 4*(1-s)*(1-s)) 181 } 182 183 // uvToST is the inverse of the stToUV transformation. Note that it 184 // is not always true that uvToST(stToUV(x)) == x due to numerical 185 // errors. 186 func uvToST(u float64) float64 { 187 if u >= 0 { 188 return 0.5 * math.Sqrt(1+3*u) 189 } 190 return 1 - 0.5*math.Sqrt(1-3*u) 191 } 192 193 // face returns face ID from 0 to 5 containing the r. For points on the 194 // boundary between faces, the result is arbitrary but deterministic. 195 func face(r r3.Vector) int { 196 f := r.LargestComponent() 197 switch { 198 case f == r3.XAxis && r.X < 0: 199 f += 3 200 case f == r3.YAxis && r.Y < 0: 201 f += 3 202 case f == r3.ZAxis && r.Z < 0: 203 f += 3 204 } 205 return int(f) 206 } 207 208 // validFaceXYZToUV given a valid face for the given point r (meaning that 209 // dot product of r with the face normal is positive), returns 210 // the corresponding u and v values, which may lie outside the range [-1,1]. 211 func validFaceXYZToUV(face int, r r3.Vector) (float64, float64) { 212 switch face { 213 case 0: 214 return r.Y / r.X, r.Z / r.X 215 case 1: 216 return -r.X / r.Y, r.Z / r.Y 217 case 2: 218 return -r.X / r.Z, -r.Y / r.Z 219 case 3: 220 return r.Z / r.X, r.Y / r.X 221 case 4: 222 return r.Z / r.Y, -r.X / r.Y 223 } 224 return -r.Y / r.Z, -r.X / r.Z 225 } 226 227 // xyzToFaceUV converts a direction vector (not necessarily unit length) to 228 // (face, u, v) coordinates. 229 func xyzToFaceUV(r r3.Vector) (f int, u, v float64) { 230 f = face(r) 231 u, v = validFaceXYZToUV(f, r) 232 return f, u, v 233 } 234 235 // faceUVToXYZ turns face and UV coordinates into an unnormalized 3 vector. 236 func faceUVToXYZ(face int, u, v float64) r3.Vector { 237 switch face { 238 case 0: 239 return r3.Vector{1, u, v} 240 case 1: 241 return r3.Vector{-u, 1, v} 242 case 2: 243 return r3.Vector{-u, -v, 1} 244 case 3: 245 return r3.Vector{-1, -v, -u} 246 case 4: 247 return r3.Vector{v, -1, -u} 248 default: 249 return r3.Vector{v, u, -1} 250 } 251 } 252 253 // faceXYZToUV returns the u and v values (which may lie outside the range 254 // [-1, 1]) if the dot product of the point p with the given face normal is positive. 255 func faceXYZToUV(face int, p Point) (u, v float64, ok bool) { 256 switch face { 257 case 0: 258 if p.X <= 0 { 259 return 0, 0, false 260 } 261 case 1: 262 if p.Y <= 0 { 263 return 0, 0, false 264 } 265 case 2: 266 if p.Z <= 0 { 267 return 0, 0, false 268 } 269 case 3: 270 if p.X >= 0 { 271 return 0, 0, false 272 } 273 case 4: 274 if p.Y >= 0 { 275 return 0, 0, false 276 } 277 default: 278 if p.Z >= 0 { 279 return 0, 0, false 280 } 281 } 282 283 u, v = validFaceXYZToUV(face, p.Vector) 284 return u, v, true 285 } 286 287 // faceXYZtoUVW transforms the given point P to the (u,v,w) coordinate frame of the given 288 // face where the w-axis represents the face normal. 289 func faceXYZtoUVW(face int, p Point) Point { 290 // The result coordinates are simply the dot products of P with the (u,v,w) 291 // axes for the given face (see faceUVWAxes). 292 switch face { 293 case 0: 294 return Point{r3.Vector{p.Y, p.Z, p.X}} 295 case 1: 296 return Point{r3.Vector{-p.X, p.Z, p.Y}} 297 case 2: 298 return Point{r3.Vector{-p.X, -p.Y, p.Z}} 299 case 3: 300 return Point{r3.Vector{-p.Z, -p.Y, -p.X}} 301 case 4: 302 return Point{r3.Vector{-p.Z, p.X, -p.Y}} 303 default: 304 return Point{r3.Vector{p.Y, p.X, -p.Z}} 305 } 306 } 307 308 // faceSiTiToXYZ transforms the (si, ti) coordinates to a (not necessarily 309 // unit length) Point on the given face. 310 func faceSiTiToXYZ(face int, si, ti uint32) Point { 311 return Point{faceUVToXYZ(face, stToUV(siTiToST(si)), stToUV(siTiToST(ti)))} 312 } 313 314 // xyzToFaceSiTi transforms the (not necessarily unit length) Point to 315 // (face, si, ti) coordinates and the level the Point is at. 316 func xyzToFaceSiTi(p Point) (face int, si, ti uint32, level int) { 317 face, u, v := xyzToFaceUV(p.Vector) 318 si = stToSiTi(uvToST(u)) 319 ti = stToSiTi(uvToST(v)) 320 321 // If the levels corresponding to si,ti are not equal, then p is not a cell 322 // center. The si,ti values of 0 and maxSiTi need to be handled specially 323 // because they do not correspond to cell centers at any valid level; they 324 // are mapped to level -1 by the code at the end. 325 level = maxLevel - findLSBSetNonZero64(uint64(si|maxSiTi)) 326 if level < 0 || level != maxLevel-findLSBSetNonZero64(uint64(ti|maxSiTi)) { 327 return face, si, ti, -1 328 } 329 330 // In infinite precision, this test could be changed to ST == SiTi. However, 331 // due to rounding errors, uvToST(xyzToFaceUV(faceUVToXYZ(stToUV(...)))) is 332 // not idempotent. On the other hand, the center is computed exactly the same 333 // way p was originally computed (if it is indeed the center of a Cell); 334 // the comparison can be exact. 335 if p.Vector == faceSiTiToXYZ(face, si, ti).Normalize() { 336 return face, si, ti, level 337 } 338 339 return face, si, ti, -1 340 } 341 342 // uNorm returns the right-handed normal (not necessarily unit length) for an 343 // edge in the direction of the positive v-axis at the given u-value on 344 // the given face. (This vector is perpendicular to the plane through 345 // the sphere origin that contains the given edge.) 346 func uNorm(face int, u float64) r3.Vector { 347 switch face { 348 case 0: 349 return r3.Vector{u, -1, 0} 350 case 1: 351 return r3.Vector{1, u, 0} 352 case 2: 353 return r3.Vector{1, 0, u} 354 case 3: 355 return r3.Vector{-u, 0, 1} 356 case 4: 357 return r3.Vector{0, -u, 1} 358 default: 359 return r3.Vector{0, -1, -u} 360 } 361 } 362 363 // vNorm returns the right-handed normal (not necessarily unit length) for an 364 // edge in the direction of the positive u-axis at the given v-value on 365 // the given face. 366 func vNorm(face int, v float64) r3.Vector { 367 switch face { 368 case 0: 369 return r3.Vector{-v, 0, 1} 370 case 1: 371 return r3.Vector{0, -v, 1} 372 case 2: 373 return r3.Vector{0, -1, -v} 374 case 3: 375 return r3.Vector{v, -1, 0} 376 case 4: 377 return r3.Vector{1, v, 0} 378 default: 379 return r3.Vector{1, 0, v} 380 } 381 } 382 383 // faceUVWAxes are the U, V, and W axes for each face. 384 var faceUVWAxes = [6][3]Point{ 385 {Point{r3.Vector{0, 1, 0}}, Point{r3.Vector{0, 0, 1}}, Point{r3.Vector{1, 0, 0}}}, 386 {Point{r3.Vector{-1, 0, 0}}, Point{r3.Vector{0, 0, 1}}, Point{r3.Vector{0, 1, 0}}}, 387 {Point{r3.Vector{-1, 0, 0}}, Point{r3.Vector{0, -1, 0}}, Point{r3.Vector{0, 0, 1}}}, 388 {Point{r3.Vector{0, 0, -1}}, Point{r3.Vector{0, -1, 0}}, Point{r3.Vector{-1, 0, 0}}}, 389 {Point{r3.Vector{0, 0, -1}}, Point{r3.Vector{1, 0, 0}}, Point{r3.Vector{0, -1, 0}}}, 390 {Point{r3.Vector{0, 1, 0}}, Point{r3.Vector{1, 0, 0}}, Point{r3.Vector{0, 0, -1}}}, 391 } 392 393 // faceUVWFaces are the precomputed neighbors of each face. 394 var faceUVWFaces = [6][3][2]int{ 395 {{4, 1}, {5, 2}, {3, 0}}, 396 {{0, 3}, {5, 2}, {4, 1}}, 397 {{0, 3}, {1, 4}, {5, 2}}, 398 {{2, 5}, {1, 4}, {0, 3}}, 399 {{2, 5}, {3, 0}, {1, 4}}, 400 {{4, 1}, {3, 0}, {2, 5}}, 401 } 402 403 // uvwAxis returns the given axis of the given face. 404 func uvwAxis(face, axis int) Point { 405 return faceUVWAxes[face][axis] 406 } 407 408 // uvwFaces returns the face in the (u,v,w) coordinate system on the given axis 409 // in the given direction. 410 func uvwFace(face, axis, direction int) int { 411 return faceUVWFaces[face][axis][direction] 412 } 413 414 // uAxis returns the u-axis for the given face. 415 func uAxis(face int) Point { 416 return uvwAxis(face, 0) 417 } 418 419 // vAxis returns the v-axis for the given face. 420 func vAxis(face int) Point { 421 return uvwAxis(face, 1) 422 } 423 424 // Return the unit-length normal for the given face. 425 func unitNorm(face int) Point { 426 return uvwAxis(face, 2) 427 }