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 +/