Skip to content

Instantly share code, notes, and snippets.

@nknize
Created December 5, 2018 22:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nknize/68a7b0e15686a7c7570ecc8258fad441 to your computer and use it in GitHub Desktop.
Save nknize/68a7b0e15686a7c7570ecc8258fad441 to your computer and use it in GitHub Desktop.
Encodes LatLonShape.Triangle w/ shortcut implementations for points and lines
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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 org.apache.lucene.document;
import org.apache.lucene.geo.GeoEncodingUtils;
import org.apache.lucene.util.NumericUtils;
public class TriangleEncoder {
public static int BYTES = LatLonShape.BYTES;
////////////////////
// encode methods //
////////////////////
/** encodes as minLat, minLon, maxLat, maxLon, bits, lat, lon */
public static void encode(int minX, int minY, int maxX, int maxY,
int[] x, int[] y, byte[] bytes) {
// encode bbox
NumericUtils.intToSortableBytes(minY, bytes, 0 * BYTES);
NumericUtils.intToSortableBytes(minX, bytes, 1 * BYTES);
NumericUtils.intToSortableBytes(maxY, bytes, 2 * BYTES);
NumericUtils.intToSortableBytes(maxX, bytes, 3 * BYTES);
if (isPoint(minX, minY, maxX, maxY)) {
// its a point; no need to continue
return;
}
int[] boxX = new int[] {minX, maxX, minX, maxX};
int[] boxY = new int[] {minY, minY, maxY, maxY};
if (x[0] == x[2] && y[0] == y[2]) {
// its a line; encode line value
encodeLine(boxX, boxY, x, y, bytes);
} else {
encodePolygon(boxX, boxY, x, y, bytes);
}
}
private static void encodeLine(int[] boxX, int[] boxY, int[] x, int[] y, byte[] bytes) {
int shared = Integer.MIN_VALUE;
outer: for (int i = 0; i < 4; ++i) {
if (boxX[i] == x[0] && boxY[i] == y[0]) {
shared = i;
break;
}
}
assert shared != Integer.MIN_VALUE : "no triangle vertex is shared with bounding box - impossible";
// encode the shared vertex
NumericUtils.intToSortableBytes(shared << 1, bytes, 4 * BYTES);
// encode explicit vertex index 1
NumericUtils.intToSortableBytes(y[1], bytes, 5 * BYTES);
NumericUtils.intToSortableBytes(x[1], bytes, 6 * BYTES);
}
private static void encodePolygon(int[] boxX, int[] boxY, int[] x, int[] y, byte[] bytes) {
// 1. its a polygon; encode polygon value as LSB
int flags = 1;
int numSharedVertices = 0;
int commonTriangleVertex = Integer.MIN_VALUE;
int commonBoxVertex = Integer.MIN_VALUE;
// 2. encode shared vertices (4 bits in Z curve order)
for (int t = 0; t < 3; ++t) {
for (int i = 0; i < 4; ++i) {
if (boxX[i] == x[t] && boxY[i] == y[t]) {
// set the vertex bit
flags = flags | (1 << (t + 1));
++numSharedVertices;
// for the single vertex case; keep track of triangle and box vertex
commonTriangleVertex = t;
commonBoxVertex = i;
break;
}
}
}
NumericUtils.intToSortableBytes(flags, bytes, 4 * BYTES);
// 3.
if (numSharedVertices == 3) {
return;
} else if (numSharedVertices == 2) {
// set last two dimensions as the third point:
NumericUtils.intToSortableBytes(y[2], bytes, 5 * BYTES);
NumericUtils.intToSortableBytes(x[2], bytes, 6 * BYTES);
return;
}
// complex case: encode remaining two points
// separate remaining two points:
int[][] triPts = new int[2][2];
int[] boxPt = new int[] {boxY[commonBoxVertex], boxX[commonBoxVertex]};
int i = 0;
for (int t = 0; t < 3; ++t) {
if (t != commonTriangleVertex) {
if (y[t] == )
triPts[i++] = new int[]{y[t], x[t]};
}
}
int y, x;
for ()
NumericUtils.intToSortableBytes();
}
private static boolean isPoint(int minX, int minY, int maxX, int maxY) {
return minX == maxX && minY == maxY;
}
private static boolean isLine(int minX, int minY, int maxX, int maxY, byte[] encoded) {
// if horizontal or vertical line; return true:
if ((minX == maxX && minY != maxY) || (minY == maxY && minX != maxX)) {
return true;
}
// otherwise check the type bit: (0 == line, 1 == polygon)
return (NumericUtils.sortableBytesToInt(encoded, 4 * BYTES) & 0x1) == 0;
}
////////////////////
// decode methods //
////////////////////
public static int decodeX(int minX, int minY, int maxX, int maxY, byte[] encoded, int vertex) {
if (isPoint(minX, minY, maxX, maxY)) {
return minX;
} else if (isLine(minX, minY, maxX, maxY, encoded)) {
return decodeLineX(minX, maxX, encoded, vertex);
}
return decodePolygonX(minX, minY, encoded, vertex);
}
public static int decodeY(int minX, int minY, int maxX, int maxY, byte[] encoded, int vertex) {
if (isPoint(minX, minY, maxX, maxY)) {
return minY;
} else if (isLine(minX, minY, maxX, maxY, encoded)) {
return decodeLineY(minY, maxY, encoded, vertex);
}
return decodePolygonX(minX, minY, encoded, vertex);
}
public static double decodeLon(int minX, int minY, int maxX, int maxY, byte[] encoded, int vertex) {
return GeoEncodingUtils.decodeLongitude(decodeX(minX, minY, maxX, maxY, encoded, vertex));
}
public static double decodeLat(int minX, int minY, int maxX, int maxY, byte[] encoded, int vertex) {
return GeoEncodingUtils.decodeLatitude(decodeY(minX, minY, maxX, maxY, encoded, vertex));
}
/** decodes x value of line vertex; 0 and 2 map to same vertex, 1 maps to explicit point at offset 6 * BYTES */
private static int decodeLineX(int minX, int maxX, byte[] encoded, int vertex) {
// decode the shared vertex index
int sharedVrtxIdx = NumericUtils.sortableBytesToInt(encoded, 4 * BYTES) >>> 1;
if (vertex == 0 || vertex == 2) {
return decodeSharedVertexX(minX, maxX, sharedVrtxIdx);
}
return NumericUtils.sortableBytesToInt(encoded, 6 * BYTES);
}
/** decodes y value of line vertex; 0 and 2 map to same vertex, 1 maps to explicit point at offset 5 * BYTES */
private static int decodeLineY(int minY, int maxY, byte[] encoded, int vertex) {
// decode the shared vertex index
int sharedVrtxIdx = NumericUtils.sortableBytesToInt(encoded, 4 * BYTES) >>> 1;
if (vertex == 0 || vertex == 2) {
return decodeSharedVertexY(minY, maxY, sharedVrtxIdx);
}
return NumericUtils.sortableBytesToInt(encoded, 5 * BYTES);
}
private static int decodePolygonX(int minX, int maxX, byte[] encoded, int vertex) {
return 0;
}
private static int decodePolygonY(int minY, int maxY, byte[] encoded, int vertex) {
return 0;
}
/** decodes the x value of the shared vertex */
private static int decodeSharedVertexX(int minX, int maxX, int sharedVertex) {
return ((sharedVertex & 0x1) == 0) ? minX : maxX;
}
/** decodes the y value of the shared vertex identified by the sharedVertex parameter */
private static int decodeSharedVertexY(int minY, int maxY, int sharedVertex) {
return ((sharedVertex & 0x10) == 0) ? minY : maxY;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment