blob: a2d9c060a8cc08d69ceae21806e9e435f9731c12 [file] [log] [blame]
diff --git a/lucene/core/src/java/org/apache/lucene/geo/GeoEncodingUtils.java b/lucene/core/src/java/org/apache/lucene/geo/GeoEncodingUtils.java
new file mode 100644
index 0000000..671f779
--- /dev/null
+++ b/lucene/core/src/java/org/apache/lucene/geo/GeoEncodingUtils.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.geo;
+
+import org.apache.lucene.util.NumericUtils;
+
+import static org.apache.lucene.geo.GeoUtils.MAX_LAT_INCL;
+import static org.apache.lucene.geo.GeoUtils.MAX_LON_INCL;
+import static org.apache.lucene.geo.GeoUtils.MIN_LON_INCL;
+import static org.apache.lucene.geo.GeoUtils.MIN_LAT_INCL;
+import static org.apache.lucene.geo.GeoUtils.checkLatitude;
+import static org.apache.lucene.geo.GeoUtils.checkLongitude;
+
+/**
+ * reusable geopoint encoding methods
+ *
+ * @lucene.experimental
+ */
+public final class GeoEncodingUtils {
+ /** number of bits used for quantizing latitude and longitude values */
+ public static final short BITS = 32;
+
+ private static final double LAT_SCALE = (0x1L<<BITS)/180.0D;
+ private static final double LAT_DECODE = 1/LAT_SCALE;
+ private static final double LON_SCALE = (0x1L<<BITS)/360.0D;
+ private static final double LON_DECODE = 1/LON_SCALE;
+
+ // No instance:
+ private GeoEncodingUtils() {
+ }
+
+ /**
+ * Quantizes double (64 bit) latitude into 32 bits (rounding down: in the direction of -90)
+ * @param latitude latitude value: must be within standard +/-90 coordinate bounds.
+ * @return encoded value as a 32-bit {@code int}
+ * @throws IllegalArgumentException if latitude is out of bounds
+ */
+ public static int encodeLatitude(double latitude) {
+ checkLatitude(latitude);
+ // the maximum possible value cannot be encoded without overflow
+ if (latitude == 90.0D) {
+ latitude = Math.nextDown(latitude);
+ }
+ return (int) Math.floor(latitude / LAT_DECODE);
+ }
+
+ /**
+ * Quantizes double (64 bit) latitude into 32 bits (rounding up: in the direction of +90)
+ * @param latitude latitude value: must be within standard +/-90 coordinate bounds.
+ * @return encoded value as a 32-bit {@code int}
+ * @throws IllegalArgumentException if latitude is out of bounds
+ */
+ public static int encodeLatitudeCeil(double latitude) {
+ GeoUtils.checkLatitude(latitude);
+ // the maximum possible value cannot be encoded without overflow
+ if (latitude == 90.0D) {
+ latitude = Math.nextDown(latitude);
+ }
+ return (int) Math.ceil(latitude / LAT_DECODE);
+ }
+
+ /**
+ * Quantizes double (64 bit) longitude into 32 bits (rounding down: in the direction of -180)
+ * @param longitude longitude value: must be within standard +/-180 coordinate bounds.
+ * @return encoded value as a 32-bit {@code int}
+ * @throws IllegalArgumentException if longitude is out of bounds
+ */
+ public static int encodeLongitude(double longitude) {
+ checkLongitude(longitude);
+ // the maximum possible value cannot be encoded without overflow
+ if (longitude == 180.0D) {
+ longitude = Math.nextDown(longitude);
+ }
+ return (int) Math.floor(longitude / LON_DECODE);
+ }
+
+ /**
+ * Quantizes double (64 bit) longitude into 32 bits (rounding up: in the direction of +180)
+ * @param longitude longitude value: must be within standard +/-180 coordinate bounds.
+ * @return encoded value as a 32-bit {@code int}
+ * @throws IllegalArgumentException if longitude is out of bounds
+ */
+ public static int encodeLongitudeCeil(double longitude) {
+ GeoUtils.checkLongitude(longitude);
+ // the maximum possible value cannot be encoded without overflow
+ if (longitude == 180.0D) {
+ longitude = Math.nextDown(longitude);
+ }
+ return (int) Math.ceil(longitude / LON_DECODE);
+ }
+
+ /**
+ * Turns quantized value from {@link #encodeLatitude} back into a double.
+ * @param encoded encoded value: 32-bit quantized value.
+ * @return decoded latitude value.
+ */
+ public static double decodeLatitude(int encoded) {
+ double result = encoded * LAT_DECODE;
+ assert result >= MIN_LAT_INCL && result < MAX_LAT_INCL;
+ return result;
+ }
+
+ /**
+ * Turns quantized value from byte array back into a double.
+ * @param src byte array containing 4 bytes to decode at {@code offset}
+ * @param offset offset into {@code src} to decode from.
+ * @return decoded latitude value.
+ */
+ public static double decodeLatitude(byte[] src, int offset) {
+ return decodeLatitude(NumericUtils.sortableBytesToInt(src, offset));
+ }
+
+ /**
+ * Turns quantized value from {@link #encodeLongitude} back into a double.
+ * @param encoded encoded value: 32-bit quantized value.
+ * @return decoded longitude value.
+ */
+ public static double decodeLongitude(int encoded) {
+ double result = encoded * LON_DECODE;
+ assert result >= MIN_LON_INCL && result < MAX_LON_INCL;
+ return result;
+ }
+
+ /**
+ * Turns quantized value from byte array back into a double.
+ * @param src byte array containing 4 bytes to decode at {@code offset}
+ * @param offset offset into {@code src} to decode from.
+ * @return decoded longitude value.
+ */
+ public static double decodeLongitude(byte[] src, int offset) {
+ return decodeLongitude(NumericUtils.sortableBytesToInt(src, offset));
+ }
+}
diff --git a/lucene/core/src/test/org/apache/lucene/geo/TestGeoEncodingUtils.java b/lucene/core/src/test/org/apache/lucene/geo/TestGeoEncodingUtils.java
new file mode 100644
index 0000000..3b71c63
--- /dev/null
+++ b/lucene/core/src/test/org/apache/lucene/geo/TestGeoEncodingUtils.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.geo;
+
+import java.util.Random;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.lucene.util.TestUtil;
+
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLongitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitudeCeil;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitudeCeil;
+import static org.apache.lucene.geo.GeoUtils.MAX_LAT_INCL;
+import static org.apache.lucene.geo.GeoUtils.MAX_LON_INCL;
+import static org.apache.lucene.geo.GeoUtils.MIN_LAT_INCL;
+import static org.apache.lucene.geo.GeoUtils.MIN_LON_INCL;
+
+/**
+ Tests methods in {@link GeoEncodingUtils}
+ */
+public class TestGeoEncodingUtils extends LuceneTestCase {
+
+ /**
+ * step through some integers, ensuring they decode to their expected double values.
+ * double values start at -90 and increase by LATITUDE_DECODE for each integer.
+ * check edge cases within the double range and random doubles within the range too.
+ */
+ public void testLatitudeQuantization() throws Exception {
+ final double LATITUDE_DECODE = 180.0D/(0x1L<<32);
+ Random random = random();
+ for (int i = 0; i < 10000; i++) {
+ int encoded = random.nextInt();
+ double min = MIN_LAT_INCL + (encoded - (long)Integer.MIN_VALUE) * LATITUDE_DECODE;
+ double decoded = decodeLatitude(encoded);
+ // should exactly equal expected value
+ assertEquals(min, decoded, 0.0D);
+ // should round-trip
+ assertEquals(encoded, encodeLatitude(decoded));
+ assertEquals(encoded, encodeLatitudeCeil(decoded));
+ // test within the range
+ if (i != Integer.MAX_VALUE) {
+ // this is the next representable value
+ // all double values between [min .. max) should encode to the current integer
+ // all double values between (min .. max] should encodeCeil to the next integer.
+ double max = min + LATITUDE_DECODE;
+ assertEquals(max, decodeLatitude(encoded+1), 0.0D);
+ assertEquals(encoded+1, encodeLatitude(max));
+ assertEquals(encoded+1, encodeLatitudeCeil(max));
+
+ // first and last doubles in range that will be quantized
+ double minEdge = Math.nextUp(min);
+ double maxEdge = Math.nextDown(max);
+ assertEquals(encoded, encodeLatitude(minEdge));
+ assertEquals(encoded+1, encodeLatitudeCeil(minEdge));
+ assertEquals(encoded, encodeLatitude(maxEdge));
+ assertEquals(encoded+1, encodeLatitudeCeil(maxEdge));
+
+ // check random values within the double range
+ long minBits = NumericUtils.doubleToSortableLong(minEdge);
+ long maxBits = NumericUtils.doubleToSortableLong(maxEdge);
+ for (int j = 0; j < 100; j++) {
+ double value = NumericUtils.sortableLongToDouble(TestUtil.nextLong(random, minBits, maxBits));
+ // round down
+ assertEquals(encoded, encodeLatitude(value));
+ // round up
+ assertEquals(encoded+1, encodeLatitudeCeil(value));
+ }
+ }
+ }
+ }
+
+ /**
+ * step through some integers, ensuring they decode to their expected double values.
+ * double values start at -180 and increase by LONGITUDE_DECODE for each integer.
+ * check edge cases within the double range and a random doubles within the range too.
+ */
+ public void testLongitudeQuantization() throws Exception {
+ final double LONGITUDE_DECODE = 360.0D/(0x1L<<32);
+ Random random = random();
+ for (int i = 0; i < 10000; i++) {
+ int encoded = random.nextInt();
+ double min = MIN_LON_INCL + (encoded - (long)Integer.MIN_VALUE) * LONGITUDE_DECODE;
+ double decoded = decodeLongitude(encoded);
+ // should exactly equal expected value
+ assertEquals(min, decoded, 0.0D);
+ // should round-trip
+ assertEquals(encoded, encodeLongitude(decoded));
+ assertEquals(encoded, encodeLongitudeCeil(decoded));
+ // test within the range
+ if (i != Integer.MAX_VALUE) {
+ // this is the next representable value
+ // all double values between [min .. max) should encode to the current integer
+ // all double values between (min .. max] should encodeCeil to the next integer.
+ double max = min + LONGITUDE_DECODE;
+ assertEquals(max, decodeLongitude(encoded+1), 0.0D);
+ assertEquals(encoded+1, encodeLongitude(max));
+ assertEquals(encoded+1, encodeLongitudeCeil(max));
+
+ // first and last doubles in range that will be quantized
+ double minEdge = Math.nextUp(min);
+ double maxEdge = Math.nextDown(max);
+ assertEquals(encoded, encodeLongitude(minEdge));
+ assertEquals(encoded+1, encodeLongitudeCeil(minEdge));
+ assertEquals(encoded, encodeLongitude(maxEdge));
+ assertEquals(encoded+1, encodeLongitudeCeil(maxEdge));
+
+ // check random values within the double range
+ long minBits = NumericUtils.doubleToSortableLong(minEdge);
+ long maxBits = NumericUtils.doubleToSortableLong(maxEdge);
+ for (int j = 0; j < 100; j++) {
+ double value = NumericUtils.sortableLongToDouble(TestUtil.nextLong(random, minBits, maxBits));
+ // round down
+ assertEquals(encoded, encodeLongitude(value));
+ // round up
+ assertEquals(encoded+1, encodeLongitudeCeil(value));
+ }
+ }
+ }
+ }
+
+ // check edge/interesting cases explicitly
+ public void testEncodeEdgeCases() {
+ assertEquals(Integer.MIN_VALUE, encodeLatitude(MIN_LAT_INCL));
+ assertEquals(Integer.MIN_VALUE, encodeLatitudeCeil(MIN_LAT_INCL));
+ assertEquals(Integer.MAX_VALUE, encodeLatitude(MAX_LAT_INCL));
+ assertEquals(Integer.MAX_VALUE, encodeLatitudeCeil(MAX_LAT_INCL));
+
+ assertEquals(Integer.MIN_VALUE, encodeLongitude(MIN_LON_INCL));
+ assertEquals(Integer.MIN_VALUE, encodeLongitudeCeil(MIN_LON_INCL));
+ assertEquals(Integer.MAX_VALUE, encodeLongitude(MAX_LON_INCL));
+ assertEquals(Integer.MAX_VALUE, encodeLongitudeCeil(MAX_LON_INCL));
+ }
+}
diff --git a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonGrid.java b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonGrid.java
index 9b4e981..7cb047a 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonGrid.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonGrid.java
@@ -20,6 +20,11 @@ import org.apache.lucene.geo.Polygon;
import org.apache.lucene.index.PointValues.Relation;
import org.apache.lucene.util.FixedBitSet;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLongitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitude;
+
/**
* This is a temporary hack, until some polygon methods have better performance!
* <p>
@@ -99,10 +104,10 @@ final class LatLonGrid {
assert cellMaxLat >= cellMinLat;
assert cellMaxLon >= cellMinLon;
- Relation relation = Polygon.relate(polygons, LatLonPoint.decodeLatitude((int) cellMinLat),
- LatLonPoint.decodeLatitude((int) cellMaxLat),
- LatLonPoint.decodeLongitude((int) cellMinLon),
- LatLonPoint.decodeLongitude((int) cellMaxLon));
+ Relation relation = Polygon.relate(polygons, decodeLatitude((int) cellMinLat),
+ decodeLatitude((int) cellMaxLat),
+ decodeLongitude((int) cellMinLon),
+ decodeLongitude((int) cellMaxLon));
if (relation != Relation.CELL_CROSSES_QUERY) {
// we know the answer for this region, fill the cell range
for (int i = minLatIndex; i < maxLatIndex; i++) {
@@ -140,8 +145,8 @@ final class LatLonGrid {
}
// the grid is unsure (boundary): do a real test.
- double docLatitude = LatLonPoint.decodeLatitude(latitude);
- double docLongitude = LatLonPoint.decodeLongitude(longitude);
+ double docLatitude = decodeLatitude(latitude);
+ double docLongitude = decodeLongitude(longitude);
return Polygon.contains(polygons, docLatitude, docLongitude);
}
diff --git a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPoint.java b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPoint.java
index 0b96936..b1e0b44 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPoint.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPoint.java
@@ -16,7 +16,6 @@
*/
package org.apache.lucene.document;
-import org.apache.lucene.geo.GeoUtils;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.index.DocValuesType;
@@ -32,6 +31,13 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
import org.apache.lucene.geo.Polygon;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLongitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitudeCeil;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitudeCeil;
+
/**
* An indexed location field.
* <p>
@@ -123,117 +129,13 @@ public class LatLonPoint extends Field {
/**
* Returns a 64-bit long, where the upper 32 bits are the encoded latitude,
* and the lower 32 bits are the encoded longitude.
- * @see #decodeLatitude(int)
- * @see #decodeLongitude(int)
+ * @see org.apache.lucene.geo.GeoEncodingUtils#decodeLatitude(int)
+ * @see org.apache.lucene.geo.GeoEncodingUtils#decodeLongitude(int)
*/
@Override
public Number numericValue() {
return currentValue;
}
-
- // public helper methods (e.g. for queries)
-
- /**
- * Quantizes double (64 bit) latitude into 32 bits (rounding down: in the direction of -90)
- * @param latitude latitude value: must be within standard +/-90 coordinate bounds.
- * @return encoded value as a 32-bit {@code int}
- * @throws IllegalArgumentException if latitude is out of bounds
- */
- public static int encodeLatitude(double latitude) {
- GeoUtils.checkLatitude(latitude);
- // the maximum possible value cannot be encoded without overflow
- if (latitude == 90.0D) {
- latitude = Math.nextDown(latitude);
- }
- return (int) Math.floor(latitude / LATITUDE_DECODE);
- }
-
- /**
- * Quantizes double (64 bit) latitude into 32 bits (rounding up: in the direction of +90)
- * @param latitude latitude value: must be within standard +/-90 coordinate bounds.
- * @return encoded value as a 32-bit {@code int}
- * @throws IllegalArgumentException if latitude is out of bounds
- */
- public static int encodeLatitudeCeil(double latitude) {
- GeoUtils.checkLatitude(latitude);
- // the maximum possible value cannot be encoded without overflow
- if (latitude == 90.0D) {
- latitude = Math.nextDown(latitude);
- }
- return (int) Math.ceil(latitude / LATITUDE_DECODE);
- }
-
- /**
- * Quantizes double (64 bit) longitude into 32 bits (rounding down: in the direction of -180)
- * @param longitude longitude value: must be within standard +/-180 coordinate bounds.
- * @return encoded value as a 32-bit {@code int}
- * @throws IllegalArgumentException if longitude is out of bounds
- */
- public static int encodeLongitude(double longitude) {
- GeoUtils.checkLongitude(longitude);
- // the maximum possible value cannot be encoded without overflow
- if (longitude == 180.0D) {
- longitude = Math.nextDown(longitude);
- }
- return (int) Math.floor(longitude / LONGITUDE_DECODE);
- }
-
- /**
- * Quantizes double (64 bit) longitude into 32 bits (rounding up: in the direction of +180)
- * @param longitude longitude value: must be within standard +/-180 coordinate bounds.
- * @return encoded value as a 32-bit {@code int}
- * @throws IllegalArgumentException if longitude is out of bounds
- */
- public static int encodeLongitudeCeil(double longitude) {
- GeoUtils.checkLongitude(longitude);
- // the maximum possible value cannot be encoded without overflow
- if (longitude == 180.0D) {
- longitude = Math.nextDown(longitude);
- }
- return (int) Math.ceil(longitude / LONGITUDE_DECODE);
- }
-
- /**
- * Turns quantized value from {@link #encodeLatitude} back into a double.
- * @param encoded encoded value: 32-bit quantized value.
- * @return decoded latitude value.
- */
- public static double decodeLatitude(int encoded) {
- double result = encoded * LATITUDE_DECODE;
- assert result >= GeoUtils.MIN_LAT_INCL && result < GeoUtils.MAX_LAT_INCL;
- return result;
- }
-
- /**
- * Turns quantized value from byte array back into a double.
- * @param src byte array containing 4 bytes to decode at {@code offset}
- * @param offset offset into {@code src} to decode from.
- * @return decoded latitude value.
- */
- public static double decodeLatitude(byte[] src, int offset) {
- return decodeLatitude(NumericUtils.sortableBytesToInt(src, offset));
- }
-
- /**
- * Turns quantized value from {@link #encodeLongitude} back into a double.
- * @param encoded encoded value: 32-bit quantized value.
- * @return decoded longitude value.
- */
- public static double decodeLongitude(int encoded) {
- double result = encoded * LONGITUDE_DECODE;
- assert result >= GeoUtils.MIN_LON_INCL && result < GeoUtils.MAX_LON_INCL;
- return result;
- }
-
- /**
- * Turns quantized value from byte array back into a double.
- * @param src byte array containing 4 bytes to decode at {@code offset}
- * @param offset offset into {@code src} to decode from.
- * @return decoded longitude value.
- */
- public static double decodeLongitude(byte[] src, int offset) {
- return decodeLongitude(NumericUtils.sortableBytesToInt(src, offset));
- }
/** sugar encodes a single point as a byte array */
private static byte[] encode(double latitude, double longitude) {
diff --git a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointDistanceComparator.java b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointDistanceComparator.java
index 58db5e5..0306489 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointDistanceComparator.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointDistanceComparator.java
@@ -29,6 +29,11 @@ import org.apache.lucene.search.Scorer;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.util.SloppyMath;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLongitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitude;
+
/**
* Compares documents by distance from an origin point
* <p>
@@ -85,17 +90,17 @@ class LatLonPointDistanceComparator extends FieldComparator<Double> implements L
Rectangle box = Rectangle.fromPointDistance(latitude, longitude, haversin2(bottom));
// pre-encode our box to our integer encoding, so we don't have to decode
// to double values for uncompetitive hits. This has some cost!
- minLat = LatLonPoint.encodeLatitude(box.minLat);
- maxLat = LatLonPoint.encodeLatitude(box.maxLat);
+ minLat = encodeLatitude(box.minLat);
+ maxLat = encodeLatitude(box.maxLat);
if (box.crossesDateline()) {
// box1
minLon = Integer.MIN_VALUE;
- maxLon = LatLonPoint.encodeLongitude(box.maxLon);
+ maxLon = encodeLongitude(box.maxLon);
// box2
- minLon2 = LatLonPoint.encodeLongitude(box.minLon);
+ minLon2 = encodeLongitude(box.minLon);
} else {
- minLon = LatLonPoint.encodeLongitude(box.minLon);
- maxLon = LatLonPoint.encodeLongitude(box.maxLon);
+ minLon = encodeLongitude(box.minLon);
+ maxLon = encodeLongitude(box.maxLon);
// disable box2
minLon2 = Integer.MAX_VALUE;
}
@@ -132,8 +137,8 @@ class LatLonPointDistanceComparator extends FieldComparator<Double> implements L
}
// only compute actual distance if its inside "competitive bounding box"
- double docLatitude = LatLonPoint.decodeLatitude(latitudeBits);
- double docLongitude = LatLonPoint.decodeLongitude(longitudeBits);
+ double docLatitude = decodeLatitude(latitudeBits);
+ double docLongitude = decodeLongitude(longitudeBits);
cmp = Math.max(cmp, Double.compare(bottom, SloppyMath.haversinSortKey(latitude, longitude, docLatitude, docLongitude)));
// once we compete in the PQ, no need to continue.
if (cmp > 0) {
@@ -178,8 +183,8 @@ class LatLonPointDistanceComparator extends FieldComparator<Double> implements L
int numValues = currentDocs.count();
for (int i = 0; i < numValues; i++) {
long encoded = currentDocs.valueAt(i);
- double docLatitude = LatLonPoint.decodeLatitude((int)(encoded >> 32));
- double docLongitude = LatLonPoint.decodeLongitude((int)(encoded & 0xFFFFFFFF));
+ double docLatitude = decodeLatitude((int)(encoded >> 32));
+ double docLongitude = decodeLongitude((int)(encoded & 0xFFFFFFFF));
minValue = Math.min(minValue, SloppyMath.haversinSortKey(latitude, longitude, docLatitude, docLongitude));
}
return minValue;
diff --git a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointDistanceQuery.java b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointDistanceQuery.java
index 1b667dd..843421b 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointDistanceQuery.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointDistanceQuery.java
@@ -45,6 +45,11 @@ import org.apache.lucene.util.SloppyMath;
import org.apache.lucene.util.SparseFixedBitSet;
import org.apache.lucene.util.StringHelper;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLongitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitude;
+
/**
* Distance query for {@link LatLonPoint}.
*/
@@ -81,19 +86,19 @@ final class LatLonPointDistanceQuery extends Query {
// second set of longitude ranges to check (for cross-dateline case)
final byte minLon2[] = new byte[Integer.BYTES];
- NumericUtils.intToSortableBytes(LatLonPoint.encodeLatitude(box.minLat), minLat, 0);
- NumericUtils.intToSortableBytes(LatLonPoint.encodeLatitude(box.maxLat), maxLat, 0);
+ NumericUtils.intToSortableBytes(encodeLatitude(box.minLat), minLat, 0);
+ NumericUtils.intToSortableBytes(encodeLatitude(box.maxLat), maxLat, 0);
// crosses dateline: split
if (box.crossesDateline()) {
// box1
NumericUtils.intToSortableBytes(Integer.MIN_VALUE, minLon, 0);
- NumericUtils.intToSortableBytes(LatLonPoint.encodeLongitude(box.maxLon), maxLon, 0);
+ NumericUtils.intToSortableBytes(encodeLongitude(box.maxLon), maxLon, 0);
// box2
- NumericUtils.intToSortableBytes(LatLonPoint.encodeLongitude(box.minLon), minLon2, 0);
+ NumericUtils.intToSortableBytes(encodeLongitude(box.minLon), minLon2, 0);
} else {
- NumericUtils.intToSortableBytes(LatLonPoint.encodeLongitude(box.minLon), minLon, 0);
- NumericUtils.intToSortableBytes(LatLonPoint.encodeLongitude(box.maxLon), maxLon, 0);
+ NumericUtils.intToSortableBytes(encodeLongitude(box.minLon), minLon, 0);
+ NumericUtils.intToSortableBytes(encodeLongitude(box.maxLon), maxLon, 0);
// disable box2
NumericUtils.intToSortableBytes(Integer.MAX_VALUE, minLon2, 0);
}
@@ -191,10 +196,10 @@ final class LatLonPointDistanceQuery extends Query {
return Relation.CELL_OUTSIDE_QUERY;
}
- double latMin = LatLonPoint.decodeLatitude(minPackedValue, 0);
- double lonMin = LatLonPoint.decodeLongitude(minPackedValue, Integer.BYTES);
- double latMax = LatLonPoint.decodeLatitude(maxPackedValue, 0);
- double lonMax = LatLonPoint.decodeLongitude(maxPackedValue, Integer.BYTES);
+ double latMin = decodeLatitude(minPackedValue, 0);
+ double lonMin = decodeLongitude(minPackedValue, Integer.BYTES);
+ double latMax = decodeLatitude(maxPackedValue, 0);
+ double lonMax = decodeLongitude(maxPackedValue, Integer.BYTES);
if ((longitude < lonMin || longitude > lonMax) && (axisLat+ Rectangle.AXISLAT_ERROR < latMin || axisLat- Rectangle.AXISLAT_ERROR > latMax)) {
// circle not fully inside / crossing axis
@@ -240,8 +245,8 @@ final class LatLonPointDistanceQuery extends Query {
int count = docValues.count();
for (int i = 0; i < count; i++) {
long encoded = docValues.valueAt(i);
- double docLatitude = LatLonPoint.decodeLatitude((int)(encoded >> 32));
- double docLongitude = LatLonPoint.decodeLongitude((int)(encoded & 0xFFFFFFFF));
+ double docLatitude = decodeLatitude((int)(encoded >> 32));
+ double docLongitude = decodeLongitude((int)(encoded & 0xFFFFFFFF));
// first check the partial distance, if its more than that, it can't be <= radiusMeters
double h1 = SloppyMath.haversinSortKey(latitude, longitude, docLatitude, docLongitude);
diff --git a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java
index 670db3d..7c504e2 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java
@@ -45,6 +45,11 @@ import org.apache.lucene.util.SparseFixedBitSet;
import org.apache.lucene.util.StringHelper;
import org.apache.lucene.geo.Polygon;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLongitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitude;
+
/** Finds all previously indexed points that fall within the specified polygons.
*
* <p>The field must be indexed with using {@link org.apache.lucene.document.LatLonPoint} added per document.
@@ -88,10 +93,10 @@ final class LatLonPointInPolygonQuery extends Query {
final byte maxLat[] = new byte[Integer.BYTES];
final byte minLon[] = new byte[Integer.BYTES];
final byte maxLon[] = new byte[Integer.BYTES];
- NumericUtils.intToSortableBytes(LatLonPoint.encodeLatitude(box.minLat), minLat, 0);
- NumericUtils.intToSortableBytes(LatLonPoint.encodeLatitude(box.maxLat), maxLat, 0);
- NumericUtils.intToSortableBytes(LatLonPoint.encodeLongitude(box.minLon), minLon, 0);
- NumericUtils.intToSortableBytes(LatLonPoint.encodeLongitude(box.maxLon), maxLon, 0);
+ NumericUtils.intToSortableBytes(encodeLatitude(box.minLat), minLat, 0);
+ NumericUtils.intToSortableBytes(encodeLatitude(box.maxLat), maxLat, 0);
+ NumericUtils.intToSortableBytes(encodeLongitude(box.minLon), minLon, 0);
+ NumericUtils.intToSortableBytes(encodeLongitude(box.maxLon), maxLon, 0);
// TODO: make this fancier, but currently linear with number of vertices
float cumulativeCost = 0;
@@ -100,10 +105,10 @@ final class LatLonPointInPolygonQuery extends Query {
}
final float matchCost = cumulativeCost;
- final LatLonGrid grid = new LatLonGrid(LatLonPoint.encodeLatitude(box.minLat),
- LatLonPoint.encodeLatitude(box.maxLat),
- LatLonPoint.encodeLongitude(box.minLon),
- LatLonPoint.encodeLongitude(box.maxLon), polygons);
+ final LatLonGrid grid = new LatLonGrid(encodeLatitude(box.minLat),
+ encodeLatitude(box.maxLat),
+ encodeLongitude(box.minLon),
+ encodeLongitude(box.maxLon), polygons);
return new ConstantScoreWeight(this) {
@@ -164,10 +169,10 @@ final class LatLonPointInPolygonQuery extends Query {
return Relation.CELL_OUTSIDE_QUERY;
}
- double cellMinLat = LatLonPoint.decodeLatitude(minPackedValue, 0);
- double cellMinLon = LatLonPoint.decodeLongitude(minPackedValue, Integer.BYTES);
- double cellMaxLat = LatLonPoint.decodeLatitude(maxPackedValue, 0);
- double cellMaxLon = LatLonPoint.decodeLongitude(maxPackedValue, Integer.BYTES);
+ double cellMinLat = decodeLatitude(minPackedValue, 0);
+ double cellMinLon = decodeLongitude(minPackedValue, Integer.BYTES);
+ double cellMaxLat = decodeLatitude(maxPackedValue, 0);
+ double cellMaxLon = decodeLongitude(maxPackedValue, Integer.BYTES);
return Polygon.relate(polygons, cellMinLat, cellMaxLat, cellMinLon, cellMaxLon);
}
diff --git a/lucene/sandbox/src/test/org/apache/lucene/document/TestLatLonGrid.java b/lucene/sandbox/src/test/org/apache/lucene/document/TestLatLonGrid.java
index 2de5a43..0b739ae 100644
--- a/lucene/sandbox/src/test/org/apache/lucene/document/TestLatLonGrid.java
+++ b/lucene/sandbox/src/test/org/apache/lucene/document/TestLatLonGrid.java
@@ -22,6 +22,11 @@ import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.TestUtil;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLongitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitude;
+
/** tests against LatLonGrid (avoiding indexing/queries) */
public class TestLatLonGrid extends LuceneTestCase {
@@ -30,18 +35,18 @@ public class TestLatLonGrid extends LuceneTestCase {
for (int i = 0; i < 100; i++) {
Polygon polygon = GeoTestUtil.nextPolygon();
Rectangle box = Rectangle.fromPolygon(new Polygon[] { polygon });
- int minLat = LatLonPoint.encodeLatitude(box.minLat);
- int maxLat = LatLonPoint.encodeLatitude(box.maxLat);
- int minLon = LatLonPoint.encodeLongitude(box.minLon);
- int maxLon = LatLonPoint.encodeLongitude(box.maxLon);
+ int minLat = encodeLatitude(box.minLat);
+ int maxLat = encodeLatitude(box.maxLat);
+ int minLon = encodeLongitude(box.minLon);
+ int maxLon = encodeLongitude(box.maxLon);
LatLonGrid grid = new LatLonGrid(minLat, maxLat, minLon, maxLon, polygon);
// we are in integer space... but exhaustive testing is slow!
for (int j = 0; j < 10000; j++) {
int lat = TestUtil.nextInt(random(), minLat, maxLat);
int lon = TestUtil.nextInt(random(), minLon, maxLon);
- boolean expected = polygon.contains(LatLonPoint.decodeLatitude(lat),
- LatLonPoint.decodeLongitude(lon));
+ boolean expected = polygon.contains(decodeLatitude(lat),
+ decodeLongitude(lon));
boolean actual = grid.contains(lat, lon);
assertEquals(expected, actual);
}
diff --git a/lucene/sandbox/src/test/org/apache/lucene/document/TestLatLonPoint.java b/lucene/sandbox/src/test/org/apache/lucene/document/TestLatLonPoint.java
index fb8e0dc..acc9186 100644
--- a/lucene/sandbox/src/test/org/apache/lucene/document/TestLatLonPoint.java
+++ b/lucene/sandbox/src/test/org/apache/lucene/document/TestLatLonPoint.java
@@ -16,13 +16,12 @@
*/
package org.apache.lucene.document;
-import java.util.Random;
-
import org.apache.lucene.util.LuceneTestCase;
-import org.apache.lucene.util.NumericUtils;
-import org.apache.lucene.util.TestUtil;
-/** Simple tests for {@link LatLonPoint} */
+/**
+ * Simple tests for {@link LatLonPoint}
+ * TODO: move this lone test and remove class?
+ * */
public class TestLatLonPoint extends LuceneTestCase {
public void testToString() throws Exception {
@@ -38,113 +37,4 @@ public class TestLatLonPoint extends LuceneTestCase {
// sort field
assertEquals("<distance:\"field\" latitude=18.0 longitude=19.0>", LatLonPoint.newDistanceSort("field", 18.0, 19.0).toString());
}
-
- /**
- * step through some integers, ensuring they decode to their expected double values.
- * double values start at -90 and increase by LATITUDE_DECODE for each integer.
- * check edge cases within the double range and random doubles within the range too.
- */
- public void testLatitudeQuantization() throws Exception {
- Random random = random();
- for (int i = 0; i < 10000; i++) {
- int encoded = random.nextInt();
- double min = -90.0 + (encoded - (long)Integer.MIN_VALUE) * LatLonPoint.LATITUDE_DECODE;
- double decoded = LatLonPoint.decodeLatitude(encoded);
- // should exactly equal expected value
- assertEquals(min, decoded, 0.0D);
- // should round-trip
- assertEquals(encoded, LatLonPoint.encodeLatitude(decoded));
- assertEquals(encoded, LatLonPoint.encodeLatitudeCeil(decoded));
- // test within the range
- if (i != Integer.MAX_VALUE) {
- // this is the next representable value
- // all double values between [min .. max) should encode to the current integer
- // all double values between (min .. max] should encodeCeil to the next integer.
- double max = min + LatLonPoint.LATITUDE_DECODE;
- assertEquals(max, LatLonPoint.decodeLatitude(encoded+1), 0.0D);
- assertEquals(encoded+1, LatLonPoint.encodeLatitude(max));
- assertEquals(encoded+1, LatLonPoint.encodeLatitudeCeil(max));
-
- // first and last doubles in range that will be quantized
- double minEdge = Math.nextUp(min);
- double maxEdge = Math.nextDown(max);
- assertEquals(encoded, LatLonPoint.encodeLatitude(minEdge));
- assertEquals(encoded+1, LatLonPoint.encodeLatitudeCeil(minEdge));
- assertEquals(encoded, LatLonPoint.encodeLatitude(maxEdge));
- assertEquals(encoded+1, LatLonPoint.encodeLatitudeCeil(maxEdge));
-
- // check random values within the double range
- long minBits = NumericUtils.doubleToSortableLong(minEdge);
- long maxBits = NumericUtils.doubleToSortableLong(maxEdge);
- for (int j = 0; j < 100; j++) {
- double value = NumericUtils.sortableLongToDouble(TestUtil.nextLong(random, minBits, maxBits));
- // round down
- assertEquals(encoded, LatLonPoint.encodeLatitude(value));
- // round up
- assertEquals(encoded+1, LatLonPoint.encodeLatitudeCeil(value));
- }
- }
- }
- }
-
- /**
- * step through some integers, ensuring they decode to their expected double values.
- * double values start at -180 and increase by LONGITUDE_DECODE for each integer.
- * check edge cases within the double range and a random doubles within the range too.
- */
- public void testLongitudeQuantization() throws Exception {
- Random random = random();
- for (int i = 0; i < 10000; i++) {
- int encoded = random.nextInt();
- double min = -180.0 + (encoded - (long)Integer.MIN_VALUE) * LatLonPoint.LONGITUDE_DECODE;
- double decoded = LatLonPoint.decodeLongitude(encoded);
- // should exactly equal expected value
- assertEquals(min, decoded, 0.0D);
- // should round-trip
- assertEquals(encoded, LatLonPoint.encodeLongitude(decoded));
- assertEquals(encoded, LatLonPoint.encodeLongitudeCeil(decoded));
- // test within the range
- if (i != Integer.MAX_VALUE) {
- // this is the next representable value
- // all double values between [min .. max) should encode to the current integer
- // all double values between (min .. max] should encodeCeil to the next integer.
- double max = min + LatLonPoint.LONGITUDE_DECODE;
- assertEquals(max, LatLonPoint.decodeLongitude(encoded+1), 0.0D);
- assertEquals(encoded+1, LatLonPoint.encodeLongitude(max));
- assertEquals(encoded+1, LatLonPoint.encodeLongitudeCeil(max));
-
- // first and last doubles in range that will be quantized
- double minEdge = Math.nextUp(min);
- double maxEdge = Math.nextDown(max);
- assertEquals(encoded, LatLonPoint.encodeLongitude(minEdge));
- assertEquals(encoded+1, LatLonPoint.encodeLongitudeCeil(minEdge));
- assertEquals(encoded, LatLonPoint.encodeLongitude(maxEdge));
- assertEquals(encoded+1, LatLonPoint.encodeLongitudeCeil(maxEdge));
-
- // check random values within the double range
- long minBits = NumericUtils.doubleToSortableLong(minEdge);
- long maxBits = NumericUtils.doubleToSortableLong(maxEdge);
- for (int j = 0; j < 100; j++) {
- double value = NumericUtils.sortableLongToDouble(TestUtil.nextLong(random, minBits, maxBits));
- // round down
- assertEquals(encoded, LatLonPoint.encodeLongitude(value));
- // round up
- assertEquals(encoded+1, LatLonPoint.encodeLongitudeCeil(value));
- }
- }
- }
- }
-
- // check edge/interesting cases explicitly
- public void testEncodeEdgeCases() {
- assertEquals(Integer.MIN_VALUE, LatLonPoint.encodeLatitude(-90.0));
- assertEquals(Integer.MIN_VALUE, LatLonPoint.encodeLatitudeCeil(-90.0));
- assertEquals(Integer.MAX_VALUE, LatLonPoint.encodeLatitude(90.0));
- assertEquals(Integer.MAX_VALUE, LatLonPoint.encodeLatitudeCeil(90.0));
-
- assertEquals(Integer.MIN_VALUE, LatLonPoint.encodeLongitude(-180.0));
- assertEquals(Integer.MIN_VALUE, LatLonPoint.encodeLongitudeCeil(-180.0));
- assertEquals(Integer.MAX_VALUE, LatLonPoint.encodeLongitude(180.0));
- assertEquals(Integer.MAX_VALUE, LatLonPoint.encodeLongitudeCeil(180.0));
- }
}
diff --git a/lucene/sandbox/src/test/org/apache/lucene/document/TestLatLonPointDistanceSort.java b/lucene/sandbox/src/test/org/apache/lucene/document/TestLatLonPointDistanceSort.java
index 5ce819c..138190a 100644
--- a/lucene/sandbox/src/test/org/apache/lucene/document/TestLatLonPointDistanceSort.java
+++ b/lucene/sandbox/src/test/org/apache/lucene/document/TestLatLonPointDistanceSort.java
@@ -35,6 +35,11 @@ import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.SloppyMath;
import org.apache.lucene.util.TestUtil;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.decodeLongitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitude;
+import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitude;
+
/** Simple tests for {@link LatLonPoint#newDistanceSort} */
public class TestLatLonPointDistanceSort extends LuceneTestCase {
@@ -191,8 +196,8 @@ public class TestLatLonPointDistanceSort extends LuceneTestCase {
double latRaw = GeoTestUtil.nextLatitude();
double lonRaw = GeoTestUtil.nextLongitude();
// pre-normalize up front, so we can just use quantized value for testing and do simple exact comparisons
- double lat = LatLonPoint.decodeLatitude(LatLonPoint.encodeLatitude(latRaw));
- double lon = LatLonPoint.decodeLongitude(LatLonPoint.encodeLongitude(lonRaw));
+ double lat = decodeLatitude(encodeLatitude(latRaw));
+ double lon = decodeLongitude(encodeLongitude(lonRaw));
doc.add(new LatLonPoint("field", lat, lon));
doc.add(new StoredField("lat", lat));
diff --git a/lucene/sandbox/src/test/org/apache/lucene/search/TestLatLonPointQueries.java b/lucene/sandbox/src/test/org/apache/lucene/search/TestLatLonPointQueries.java
index 08b9ebf..8c909e6 100644
--- a/lucene/sandbox/src/test/org/apache/lucene/search/TestLatLonPointQueries.java
+++ b/lucene/sandbox/src/test/org/apache/lucene/search/TestLatLonPointQueries.java
@@ -20,6 +20,7 @@ import org.apache.lucene.document.Document;
import org.apache.lucene.document.LatLonPoint;
import org.apache.lucene.spatial.util.BaseGeoPointTestCase;
import org.apache.lucene.geo.Polygon;
+import org.apache.lucene.geo.GeoEncodingUtils;
public class TestLatLonPointQueries extends BaseGeoPointTestCase {
@@ -45,11 +46,11 @@ public class TestLatLonPointQueries extends BaseGeoPointTestCase {
@Override
protected double quantizeLat(double latRaw) {
- return LatLonPoint.decodeLatitude(LatLonPoint.encodeLatitude(latRaw));
+ return GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(latRaw));
}
@Override
protected double quantizeLon(double lonRaw) {
- return LatLonPoint.decodeLongitude(LatLonPoint.encodeLongitude(lonRaw));
+ return GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(lonRaw));
}
}