gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }