1 // Copyright 2011 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 // 17 // Given a sequence of S2Points assumed to be the center of level-k cells, 18 // compresses it into a stream using the following method: 19 // - decompose the points into (face, si, ti) tuples (see s2coords.h) 20 // - run-length encode the faces, combining face number and count into a 21 // varint32. See the Faces class in s2point_compression.cc. 22 // - right shift the (si, ti) to remove the part that's constant for all cells 23 // of level-k. The result is called the (pi, qi) space. 24 // - 2nd derivative encode the pi and qi sequences (linear prediction) 25 // - zig-zag encode all derivative values but the first, which cannot be 26 // negative 27 // - interleave the zig-zag encoded values 28 // - encode the first interleaved value in a fixed length encoding 29 // (varint would make this value larger) 30 // - encode the remaining interleaved values as varint64s, as the 31 // derivative encoding should make the values small. 32 // In addition, provides a lossless method to compress a sequence of points even 33 // if some points are not the center of level-k cells. These points are stored 34 // exactly, using 3 double precision values, after the above encoded string, 35 // together with their index in the sequence (this leads to some redundancy - it 36 // is expected that only a small fraction of the points are not cell centers). 37 // 38 // Require that the encoder was constructed with the no-arg constructor, as 39 // Ensure() will be called to allocate space. 40 41 // 42 // To encode leaf cells, this requires 8 bytes for the first vertex plus 43 // an average of 3.8 bytes for each additional vertex, when computed on 44 // Google's geographic repository. 45 46 module s2.s2point_compression; 47 48 import s2.s2point; 49 import s2.util.coding.coder; 50 51 /** 52 * The XYZ and face,si,ti coordinates of an S2Point and, if this point is equal 53 * to the center of an S2Cell, the level of this cell (-1 otherwise). 54 */ 55 struct S2XYZFaceSiTi { 56 S2Point xyz; 57 int face; 58 uint si; 59 uint ti; 60 int cellLevel; 61 } 62 63 /+ TODO 64 65 // Encode the points in the encoder, using an optimized compressed format for 66 // points at the center of a cell at 'level', plus 3 double values for the 67 // others. 68 void encodeS2PointsCompressed(ORangeT)( 69 in S2XYZFaceSiTi[] points, int level, Encoder!ORangeT encoder) { 70 int[2][] vertices_pi_qi = new int[2][points.length]; 71 int[] off_center; 72 Faces faces; 73 for (int i = 0; i < points.length; ++i) { 74 faces.addFace(points[i].face); 75 vertices_pi_qi[i][0] = SiTitoPiQi(points[i].si, level); 76 vertices_pi_qi[i][1] = SiTitoPiQi(points[i].ti, level); 77 if (points[i].cellLevel != level) { 78 off_center ~= i; 79 } 80 } 81 faces.encode(encoder); 82 encodePointsCompressed(vertices_pi_qi, level, encoder); 83 int num_off_center = off_center.length; 84 encoder.ensure(Encoder::kVarintMax32 + 85 (Encoder::kVarintMax32 + sizeof(S2Point)) * num_off_center); 86 encoder->put_varint32(num_off_center); 87 DCHECK_GE(encoder->avail(), 0); 88 for (int index : off_center) { 89 encoder->put_varint32(index); 90 encoder->putn(&points[index].xyz, sizeof(points[index].xyz)); 91 DCHECK_GE(encoder->avail(), 0); 92 } 93 } 94 95 // Decode points encoded with S2EncodePointsCompressed. Requires that the 96 // level is the level that was used in S2EncodePointsCompressed. Ensures 97 // that the decoded points equal the encoded points. Returns true on success. 98 bool decodeS2PointsCompressed(Decoder* decoder, int level, 99 absl::Span<S2Point> points); 100 101 +/