summaryrefslogtreecommitdiff
path: root/vendor/github.com/golang/geo/s2/pointcompression.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/golang/geo/s2/pointcompression.go')
-rw-r--r--vendor/github.com/golang/geo/s2/pointcompression.go319
1 files changed, 0 insertions, 319 deletions
diff --git a/vendor/github.com/golang/geo/s2/pointcompression.go b/vendor/github.com/golang/geo/s2/pointcompression.go
deleted file mode 100644
index 018381799..000000000
--- a/vendor/github.com/golang/geo/s2/pointcompression.go
+++ /dev/null
@@ -1,319 +0,0 @@
-// Copyright 2017 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package s2
-
-import (
- "errors"
- "fmt"
-
- "github.com/golang/geo/r3"
-)
-
-// maxEncodedVertices is the maximum number of vertices, in a row, to be encoded or decoded.
-// On decode, this defends against malicious encodings that try and have us exceed RAM.
-const maxEncodedVertices = 50000000
-
-// xyzFaceSiTi represents the The XYZ and face,si,ti coordinates of a Point
-// and, if this point is equal to the center of a Cell, the level of this cell
-// (-1 otherwise). This is used for Loops and Polygons to store data in a more
-// compressed format.
-type xyzFaceSiTi struct {
- xyz Point
- face int
- si, ti uint32
- level int
-}
-
-const derivativeEncodingOrder = 2
-
-func appendFace(faces []faceRun, face int) []faceRun {
- if len(faces) == 0 || faces[len(faces)-1].face != face {
- return append(faces, faceRun{face, 1})
- }
- faces[len(faces)-1].count++
- return faces
-}
-
-// encodePointsCompressed uses an optimized compressed format to encode the given values.
-func encodePointsCompressed(e *encoder, vertices []xyzFaceSiTi, level int) {
- var faces []faceRun
- for _, v := range vertices {
- faces = appendFace(faces, v.face)
- }
- encodeFaces(e, faces)
-
- type piQi struct {
- pi, qi uint32
- }
- verticesPiQi := make([]piQi, len(vertices))
- for i, v := range vertices {
- verticesPiQi[i] = piQi{siTitoPiQi(v.si, level), siTitoPiQi(v.ti, level)}
- }
- piCoder, qiCoder := newNthDerivativeCoder(derivativeEncodingOrder), newNthDerivativeCoder(derivativeEncodingOrder)
- for i, v := range verticesPiQi {
- f := encodePointCompressed
- if i == 0 {
- // The first point will be just the (pi, qi) coordinates
- // of the Point. NthDerivativeCoder will not save anything
- // in that case, so we encode in fixed format rather than varint
- // to avoid the varint overhead.
- f = encodeFirstPointFixedLength
- }
- f(e, v.pi, v.qi, level, piCoder, qiCoder)
- }
-
- var offCenter []int
- for i, v := range vertices {
- if v.level != level {
- offCenter = append(offCenter, i)
- }
- }
- e.writeUvarint(uint64(len(offCenter)))
- for _, idx := range offCenter {
- e.writeUvarint(uint64(idx))
- e.writeFloat64(vertices[idx].xyz.X)
- e.writeFloat64(vertices[idx].xyz.Y)
- e.writeFloat64(vertices[idx].xyz.Z)
- }
-}
-
-func encodeFirstPointFixedLength(e *encoder, pi, qi uint32, level int, piCoder, qiCoder *nthDerivativeCoder) {
- // Do not ZigZagEncode the first point, since it cannot be negative.
- codedPi, codedQi := piCoder.encode(int32(pi)), qiCoder.encode(int32(qi))
- // Interleave to reduce overhead from two partial bytes to one.
- interleaved := interleaveUint32(uint32(codedPi), uint32(codedQi))
-
- // Write as little endian.
- bytesRequired := (level + 7) / 8 * 2
- for i := 0; i < bytesRequired; i++ {
- e.writeUint8(uint8(interleaved))
- interleaved >>= 8
- }
-}
-
-// encodePointCompressed encodes points into e.
-// Given a sequence of Points assumed to be the center of level-k cells,
-// compresses it into a stream using the following method:
-// - decompose the points into (face, si, ti) tuples.
-// - run-length encode the faces, combining face number and count into a
-// varint32. See the faceRun struct.
-// - right shift the (si, ti) to remove the part that's constant for all cells
-// of level-k. The result is called the (pi, qi) space.
-// - 2nd derivative encode the pi and qi sequences (linear prediction)
-// - zig-zag encode all derivative values but the first, which cannot be
-// negative
-// - interleave the zig-zag encoded values
-// - encode the first interleaved value in a fixed length encoding
-// (varint would make this value larger)
-// - encode the remaining interleaved values as varint64s, as the
-// derivative encoding should make the values small.
-// In addition, provides a lossless method to compress a sequence of points even
-// if some points are not the center of level-k cells. These points are stored
-// exactly, using 3 double precision values, after the above encoded string,
-// together with their index in the sequence (this leads to some redundancy - it
-// is expected that only a small fraction of the points are not cell centers).
-//
-// To encode leaf cells, this requires 8 bytes for the first vertex plus
-// an average of 3.8 bytes for each additional vertex, when computed on
-// Google's geographic repository.
-func encodePointCompressed(e *encoder, pi, qi uint32, level int, piCoder, qiCoder *nthDerivativeCoder) {
- // ZigZagEncode, as varint requires the maximum number of bytes for
- // negative numbers.
- zzPi := zigzagEncode(piCoder.encode(int32(pi)))
- zzQi := zigzagEncode(qiCoder.encode(int32(qi)))
- // Interleave to reduce overhead from two partial bytes to one.
- interleaved := interleaveUint32(zzPi, zzQi)
- e.writeUvarint(interleaved)
-}
-
-type faceRun struct {
- face, count int
-}
-
-func decodeFaceRun(d *decoder) faceRun {
- faceAndCount := d.readUvarint()
- ret := faceRun{
- face: int(faceAndCount % numFaces),
- count: int(faceAndCount / numFaces),
- }
- if ret.count <= 0 && d.err == nil {
- d.err = errors.New("non-positive count for face run")
- }
- return ret
-}
-
-func decodeFaces(numVertices int, d *decoder) []faceRun {
- var frs []faceRun
- for nparsed := 0; nparsed < numVertices; {
- fr := decodeFaceRun(d)
- if d.err != nil {
- return nil
- }
- frs = append(frs, fr)
- nparsed += fr.count
- }
- return frs
-}
-
-// encodeFaceRun encodes each faceRun as a varint64 with value numFaces * count + face.
-func encodeFaceRun(e *encoder, fr faceRun) {
- // It isn't necessary to encode the number of faces left for the last run,
- // but since this would only help if there were more than 21 faces, it will
- // be a small overall savings, much smaller than the bound encoding.
- coded := numFaces*uint64(fr.count) + uint64(fr.face)
- e.writeUvarint(coded)
-}
-
-func encodeFaces(e *encoder, frs []faceRun) {
- for _, fr := range frs {
- encodeFaceRun(e, fr)
- }
-}
-
-type facesIterator struct {
- faces []faceRun
- // How often have we yet shown the current face?
- numCurrentFaceShown int
- curFace int
-}
-
-func (fi *facesIterator) next() (ok bool) {
- if len(fi.faces) == 0 {
- return false
- }
- fi.curFace = fi.faces[0].face
- fi.numCurrentFaceShown++
-
- // Advance fs if needed.
- if fi.faces[0].count <= fi.numCurrentFaceShown {
- fi.faces = fi.faces[1:]
- fi.numCurrentFaceShown = 0
- }
-
- return true
-}
-
-func decodePointsCompressed(d *decoder, level int, target []Point) {
- faces := decodeFaces(len(target), d)
-
- piCoder := newNthDerivativeCoder(derivativeEncodingOrder)
- qiCoder := newNthDerivativeCoder(derivativeEncodingOrder)
-
- iter := facesIterator{faces: faces}
- for i := range target {
- decodeFn := decodePointCompressed
- if i == 0 {
- decodeFn = decodeFirstPointFixedLength
- }
- pi, qi := decodeFn(d, level, piCoder, qiCoder)
- if ok := iter.next(); !ok && d.err == nil {
- d.err = fmt.Errorf("ran out of faces at target %d", i)
- return
- }
- target[i] = Point{facePiQitoXYZ(iter.curFace, pi, qi, level)}
- }
-
- numOffCenter := int(d.readUvarint())
- if d.err != nil {
- return
- }
- if numOffCenter > len(target) {
- d.err = fmt.Errorf("numOffCenter = %d, should be at most len(target) = %d", numOffCenter, len(target))
- return
- }
- for i := 0; i < numOffCenter; i++ {
- idx := int(d.readUvarint())
- if d.err != nil {
- return
- }
- if idx >= len(target) {
- d.err = fmt.Errorf("off center index = %d, should be < len(target) = %d", idx, len(target))
- return
- }
- target[idx].X = d.readFloat64()
- target[idx].Y = d.readFloat64()
- target[idx].Z = d.readFloat64()
- }
-}
-
-func decodeFirstPointFixedLength(d *decoder, level int, piCoder, qiCoder *nthDerivativeCoder) (pi, qi uint32) {
- bytesToRead := (level + 7) / 8 * 2
- var interleaved uint64
- for i := 0; i < bytesToRead; i++ {
- rr := d.readUint8()
- interleaved |= (uint64(rr) << uint(i*8))
- }
-
- piCoded, qiCoded := deinterleaveUint32(interleaved)
-
- return uint32(piCoder.decode(int32(piCoded))), uint32(qiCoder.decode(int32(qiCoded)))
-}
-
-func zigzagEncode(x int32) uint32 {
- return (uint32(x) << 1) ^ uint32(x>>31)
-}
-
-func zigzagDecode(x uint32) int32 {
- return int32((x >> 1) ^ uint32((int32(x&1)<<31)>>31))
-}
-
-func decodePointCompressed(d *decoder, level int, piCoder, qiCoder *nthDerivativeCoder) (pi, qi uint32) {
- interleavedZigZagEncodedDerivPiQi := d.readUvarint()
- piZigzag, qiZigzag := deinterleaveUint32(interleavedZigZagEncodedDerivPiQi)
- return uint32(piCoder.decode(zigzagDecode(piZigzag))), uint32(qiCoder.decode(zigzagDecode(qiZigzag)))
-}
-
-// We introduce a new coordinate system (pi, qi), which is (si, ti)
-// with the bits that are constant for cells of that level shifted
-// off to the right.
-// si = round(s * 2^31)
-// pi = si >> (31 - level)
-// = floor(s * 2^level)
-// If the point has been snapped to the level, the bits that are
-// shifted off will be a 1 in the msb, then 0s after that, so the
-// fractional part discarded by the cast is (close to) 0.5.
-
-// stToPiQi returns the value transformed to the PiQi coordinate space.
-func stToPiQi(s float64, level uint) uint32 {
- return uint32(s * float64(int(1)<<level))
-}
-
-// siTiToPiQi returns the value transformed into the PiQi coordinate spade.
-// encodeFirstPointFixedLength encodes the return value using level bits,
-// so we clamp si to the range [0, 2**level - 1] before trying to encode
-// it. This is okay because if si == maxSiTi, then it is not a cell center
-// anyway and will be encoded separately as an off-center point.
-func siTitoPiQi(siTi uint32, level int) uint32 {
- s := uint(siTi)
- const max = maxSiTi - 1
- if s > max {
- s = max
- }
-
- return uint32(s >> (maxLevel + 1 - uint(level)))
-}
-
-// piQiToST returns the value transformed to ST space.
-func piQiToST(pi uint32, level int) float64 {
- // We want to recover the position at the center of the cell. If the point
- // was snapped to the center of the cell, then math.Modf(s * 2^level) == 0.5.
- // Inverting STtoPiQi gives:
- // s = (pi + 0.5) / 2^level.
- return (float64(pi) + 0.5) / float64(int(1)<<uint(level))
-}
-
-func facePiQitoXYZ(face int, pi, qi uint32, level int) r3.Vector {
- return faceUVToXYZ(face, stToUV(piQiToST(pi, level)), stToUV(piQiToST(qi, level))).Normalize()
-}