diff --git a/dev-tools/idea/lucene/sandbox/sandbox.iml b/dev-tools/idea/lucene/sandbox/sandbox.iml index 05caa9f1c27..47cf8da0241 100644 --- a/dev-tools/idea/lucene/sandbox/sandbox.iml +++ b/dev-tools/idea/lucene/sandbox/sandbox.iml @@ -23,6 +23,7 @@ + diff --git a/lucene/core/src/java/org/apache/lucene/util/SloppyMath.java b/lucene/core/src/java/org/apache/lucene/util/SloppyMath.java index 9a05704f05b..8da8276de35 100644 --- a/lucene/core/src/java/org/apache/lucene/util/SloppyMath.java +++ b/lucene/core/src/java/org/apache/lucene/util/SloppyMath.java @@ -180,15 +180,15 @@ public class SloppyMath { } // haversin - static final double TO_RADIANS = Math.PI / 180D; - static final double TO_DEGREES = 180D / Math.PI; + public static final double TO_RADIANS = Math.PI / 180D; + public static final double TO_DEGREES = 180D / Math.PI; // cos/asin private static final double ONE_DIV_F2 = 1/2.0; private static final double ONE_DIV_F3 = 1/6.0; private static final double ONE_DIV_F4 = 1/24.0; - static final double PIO2 = Math.PI / 2D; + public static final double PIO2 = Math.PI / 2D; private static final double PIO2_HI = Double.longBitsToDouble(0x3FF921FB54400000L); // 1.57079632673412561417e+00 first 33 bits of pi/2 private static final double PIO2_LO = Double.longBitsToDouble(0x3DD0B4611A626331L); // 6.07710050650619224932e-11 pi/2 - PIO2_HI private static final double TWOPI_HI = 4*PIO2_HI; diff --git a/lucene/sandbox/build.xml b/lucene/sandbox/build.xml index 93bc2754ece..d53a6ac9ed1 100644 --- a/lucene/sandbox/build.xml +++ b/lucene/sandbox/build.xml @@ -23,4 +23,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + 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 71d95272385..77f7d32eed4 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPoint.java +++ b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPoint.java @@ -17,8 +17,8 @@ package org.apache.lucene.document; import org.apache.lucene.util.BytesRef; -import org.apache.lucene.util.GeoUtils; import org.apache.lucene.util.NumericUtils; +import org.apache.lucene.spatial.util.GeoUtils; /** Add this to a document to index lat/lon point dimensionally */ public class LatLonPoint extends Field { diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/PointInPolygonQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/PointInPolygonQuery.java index 861a1099e80..8e099c4ca2e 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/PointInPolygonQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/PointInPolygonQuery.java @@ -26,9 +26,9 @@ import org.apache.lucene.index.PointValues; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.util.DocIdSetBuilder; -import org.apache.lucene.util.GeoRelationUtils; -import org.apache.lucene.util.GeoUtils; import org.apache.lucene.util.NumericUtils; +import org.apache.lucene.spatial.util.GeoRelationUtils; +import org.apache.lucene.spatial.util.GeoUtils; /** Finds all previously indexed points that fall within the specified polygon. * diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/PointInRectQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/PointInRectQuery.java index 6ef1703397d..1d95399c115 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/PointInRectQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/PointInRectQuery.java @@ -26,8 +26,8 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.util.DocIdSetBuilder; -import org.apache.lucene.util.GeoUtils; import org.apache.lucene.util.NumericUtils; +import org.apache.lucene.spatial.util.GeoUtils; /** Finds all previously indexed points that fall within the specified boundings box. * diff --git a/lucene/sandbox/src/java/org/apache/lucene/util/package.html b/lucene/sandbox/src/java/org/apache/lucene/util/package.html deleted file mode 100644 index 9a8856c38b2..00000000000 --- a/lucene/sandbox/src/java/org/apache/lucene/util/package.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - -This package contains utility APIs, currently for geospatial searching. - - 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 e898f1cfd48..5ae9503fd56 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/search/TestLatLonPointQueries.java +++ b/lucene/sandbox/src/test/org/apache/lucene/search/TestLatLonPointQueries.java @@ -18,9 +18,9 @@ package org.apache.lucene.search; import org.apache.lucene.document.LatLonPoint; import org.apache.lucene.document.Document; -import org.apache.lucene.util.BaseGeoPointTestCase; -import org.apache.lucene.util.GeoDistanceUtils; -import org.apache.lucene.util.GeoRect; +import org.apache.lucene.spatial.util.BaseGeoPointTestCase; +import org.apache.lucene.spatial.util.GeoDistanceUtils; +import org.apache.lucene.spatial.util.GeoRect; public class TestLatLonPointQueries extends BaseGeoPointTestCase { // todo deconflict GeoPoint and BKD encoding methods and error tolerance diff --git a/lucene/sandbox/src/java/org/apache/lucene/document/GeoPointField.java b/lucene/spatial/src/java/org/apache/lucene/spatial/document/GeoPointField.java similarity index 91% rename from lucene/sandbox/src/java/org/apache/lucene/document/GeoPointField.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/document/GeoPointField.java index ad1483db212..6386ee6c135 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/document/GeoPointField.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/document/GeoPointField.java @@ -14,11 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.document; +package org.apache.lucene.spatial.document; +import org.apache.lucene.document.Field; +import org.apache.lucene.document.FieldType; import org.apache.lucene.index.DocValuesType; import org.apache.lucene.index.IndexOptions; -import org.apache.lucene.util.GeoUtils; +import org.apache.lucene.spatial.util.GeoUtils; /** *

@@ -32,8 +34,8 @@ import org.apache.lucene.util.GeoUtils; * * *

To perform simple geospatial queries against a GeoPointField, - * see {@link org.apache.lucene.search.GeoPointInBBoxQuery}, {@link org.apache.lucene.search.GeoPointInPolygonQuery}, - * or {@link org.apache.lucene.search.GeoPointDistanceQuery} + * see {@link org.apache.lucene.spatial.search.GeoPointInBBoxQuery}, {@link org.apache.lucene.spatial.search.GeoPointInPolygonQuery}, + * or {@link org.apache.lucene.spatial.search.GeoPointDistanceQuery} * * NOTE: This indexes only high precision encoded terms which may result in visiting a high number * of terms for large queries. See LUCENE-6481 for a future improvement. @@ -41,6 +43,7 @@ import org.apache.lucene.util.GeoUtils; * @lucene.experimental */ public final class GeoPointField extends Field { + /** encoding step value for GeoPoint prefix terms */ public static final int PRECISION_STEP = 9; /** @@ -109,10 +112,12 @@ public final class GeoPointField extends Field { fieldsData = GeoUtils.mortonHash(lon, lat); } + /** access longitude value */ public double getLon() { return GeoUtils.mortonUnhashLon((long) fieldsData); } + /** access latitude value */ public double getLat() { return GeoUtils.mortonUnhashLat((long) fieldsData); } diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/document/package-info.java b/lucene/spatial/src/java/org/apache/lucene/spatial/document/package-info.java new file mode 100644 index 00000000000..2550fa1d27f --- /dev/null +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/document/package-info.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/** + * Geospatial Field Implementations for Core Lucene + */ +package org.apache.lucene.spatial.document; \ No newline at end of file diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/GeoBoundingBox.java b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoBoundingBox.java similarity index 82% rename from lucene/sandbox/src/java/org/apache/lucene/search/GeoBoundingBox.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoBoundingBox.java index c2c92eaed5b..f26f8b1a3e3 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/GeoBoundingBox.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoBoundingBox.java @@ -14,17 +14,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.search; +package org.apache.lucene.spatial.search; -import org.apache.lucene.util.GeoUtils; +import org.apache.lucene.spatial.util.GeoUtils; /** NOTE: package private; just used so {@link GeoPointInPolygonQuery} can communicate its bounding box to {@link GeoPointInBBoxQuery}. */ class GeoBoundingBox { + /** minimum longitude value (in degrees) */ public final double minLon; + /** minimum latitude value (in degrees) */ public final double maxLon; + /** maximum longitude value (in degrees) */ public final double minLat; + /** maximum latitude value (in degrees) */ public final double maxLat; + /** + * Constructs a bounding box by first validating the provided latitude and longitude coordinates + */ public GeoBoundingBox(double minLon, double maxLon, double minLat, double maxLat) { if (GeoUtils.isValidLon(minLon) == false) { throw new IllegalArgumentException("invalid minLon " + minLon); diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointDistanceQuery.java b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointDistanceQuery.java similarity index 86% rename from lucene/sandbox/src/java/org/apache/lucene/search/GeoPointDistanceQuery.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointDistanceQuery.java index a77798b9a84..27f78e85f57 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointDistanceQuery.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointDistanceQuery.java @@ -14,22 +14,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.search; +package org.apache.lucene.spatial.search; import org.apache.lucene.index.IndexReader; -import org.apache.lucene.util.GeoDistanceUtils; -import org.apache.lucene.util.GeoRect; -import org.apache.lucene.util.GeoUtils; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.spatial.util.GeoDistanceUtils; +import org.apache.lucene.spatial.util.GeoRect; +import org.apache.lucene.spatial.util.GeoUtils; /** Implements a simple point distance query on a GeoPoint field. This is based on - * {@link org.apache.lucene.search.GeoPointInBBoxQuery} and is implemented using a two phase approach. First, + * {@link GeoPointInBBoxQuery} and is implemented using a two phase approach. First, * like {@code GeoPointInBBoxQueryImpl} candidate terms are queried using the numeric ranges based on * the morton codes of the min and max lat/lon pairs that intersect the boundary of the point-radius * circle. Terms * passing this initial filter are then passed to a secondary {@code postFilter} method that verifies whether the * decoded lat/lon point fall within the specified query distance (see {@link org.apache.lucene.util.SloppyMath#haversin}. * All morton value comparisons are subject to the same precision tolerance defined in - * {@value org.apache.lucene.util.GeoUtils#TOLERANCE} and distance comparisons are subject to the accuracy of the + * {@value org.apache.lucene.spatial.util.GeoUtils#TOLERANCE} and distance comparisons are subject to the accuracy of the * haversine formula (from R.W. Sinnott, "Virtues of the Haversine", Sky and Telescope, vol. 68, no. 2, 1984, p. 159) * *

Note: This query currently uses haversine which is a sloppy distance calculation (see above reference). For large @@ -38,11 +41,17 @@ import org.apache.lucene.util.GeoUtils; * * @lucene.experimental */ public class GeoPointDistanceQuery extends GeoPointInBBoxQuery { + /** longitude value (in degrees) for query location */ protected final double centerLon; + /** latitude value (in degrees) for query location */ protected final double centerLat; + /** distance (in meters) from lon, lat center location */ protected final double radiusMeters; - /** NOTE: radius is in meters. */ + /** + * Constructs a Query for all {@link org.apache.lucene.spatial.document.GeoPointField} types within a + * distance (in meters) from a given point + **/ public GeoPointDistanceQuery(final String field, final double centerLon, final double centerLat, final double radiusMeters) { this(field, GeoUtils.circleToBBox(centerLon, centerLat, radiusMeters), centerLon, centerLat, radiusMeters); } @@ -156,14 +165,17 @@ public class GeoPointDistanceQuery extends GeoPointInBBoxQuery { .toString(); } + /** getter method for center longitude value */ public double getCenterLon() { return this.centerLon; } + /** getter method for center latitude value */ public double getCenterLat() { return this.centerLat; } + /** getter method for distance value (in meters) */ public double getRadiusMeters() { return this.radiusMeters; } diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointDistanceQueryImpl.java b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointDistanceQueryImpl.java similarity index 91% rename from lucene/sandbox/src/java/org/apache/lucene/search/GeoPointDistanceQueryImpl.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointDistanceQueryImpl.java index ef2155b4daa..07777997718 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointDistanceQueryImpl.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointDistanceQueryImpl.java @@ -14,17 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.search; +package org.apache.lucene.spatial.search; import java.io.IOException; -import org.apache.lucene.document.GeoPointField; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; +import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.util.AttributeSource; -import org.apache.lucene.util.GeoRect; -import org.apache.lucene.util.GeoRelationUtils; -import org.apache.lucene.util.GeoUtils; +import org.apache.lucene.spatial.document.GeoPointField; +import org.apache.lucene.spatial.util.GeoRect; +import org.apache.lucene.spatial.util.GeoRelationUtils; import org.apache.lucene.util.SloppyMath; /** Package private implementation for the public facing GeoPointDistanceQuery delegate class. @@ -48,7 +48,7 @@ final class GeoPointDistanceQueryImpl extends GeoPointInBBoxQueryImpl { } @Override - public void setRewriteMethod(RewriteMethod method) { + public void setRewriteMethod(MultiTermQuery.RewriteMethod method) { throw new UnsupportedOperationException("cannot change rewrite method"); } @@ -94,7 +94,7 @@ final class GeoPointDistanceQueryImpl extends GeoPointInBBoxQueryImpl { } /** - * The two-phase query approach. The parent {@link org.apache.lucene.search.GeoPointTermsEnum} class matches + * The two-phase query approach. The parent {@link GeoPointTermsEnum} class matches * encoded terms that fall within the minimum bounding box of the point-radius circle. Those documents that pass * the initial bounding box filter are then post filter compared to the provided distance using the * {@link org.apache.lucene.util.SloppyMath#haversin} method. diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointDistanceRangeQuery.java b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointDistanceRangeQuery.java similarity index 86% rename from lucene/sandbox/src/java/org/apache/lucene/search/GeoPointDistanceRangeQuery.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointDistanceRangeQuery.java index 5324a6d53a8..df76c0c9f2a 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointDistanceRangeQuery.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointDistanceRangeQuery.java @@ -14,13 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.search; +package org.apache.lucene.spatial.search; import org.apache.lucene.index.IndexReader; -import org.apache.lucene.util.GeoProjectionUtils; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Query; /** Implements a point distance range query on a GeoPoint field. This is based on - * {@code org.apache.lucene.search.GeoPointDistanceQuery} and is implemented using a + * {@code org.apache.lucene.spatial.search.GeoPointDistanceQuery} and is implemented using a * {@code org.apache.lucene.search.BooleanClause.MUST_NOT} clause to exclude any points that fall within * minRadiusMeters from the provided point. * @@ -29,6 +31,10 @@ import org.apache.lucene.util.GeoProjectionUtils; public final class GeoPointDistanceRangeQuery extends GeoPointDistanceQuery { protected final double minRadiusMeters; + /** + * Constructs a query for all {@link org.apache.lucene.spatial.document.GeoPointField} types within a minimum / maximum + * distance (in meters) range from a given point + */ public GeoPointDistanceRangeQuery(final String field, final double centerLon, final double centerLat, final double minRadiusMeters, final double maxRadius) { super(field, centerLon, centerLat, maxRadius); @@ -92,10 +98,12 @@ public final class GeoPointDistanceRangeQuery extends GeoPointDistanceQuery { .toString(); } + /** getter method for minimum distance */ public double getMinRadiusMeters() { return this.minRadiusMeters; } + /** getter method for maximum distance */ public double getMaxRadiusMeters() { return this.radiusMeters; } diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointInBBoxQuery.java b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointInBBoxQuery.java similarity index 85% rename from lucene/sandbox/src/java/org/apache/lucene/search/GeoPointInBBoxQuery.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointInBBoxQuery.java index 0926a4f94ea..75f38a9c990 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointInBBoxQuery.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointInBBoxQuery.java @@ -14,10 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.search; +package org.apache.lucene.spatial.search; import org.apache.lucene.index.IndexReader; -import org.apache.lucene.util.GeoUtils; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.FieldValueQuery; +import org.apache.lucene.search.LegacyNumericRangeQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.spatial.util.GeoUtils; /** Implements a simple bounding box query on a GeoPoint field. This is inspired by * {@link LegacyNumericRangeQuery} and is implemented using a @@ -26,7 +31,7 @@ import org.apache.lucene.util.GeoUtils; * passing this initial filter are passed to a final check that verifies whether * the decoded lat/lon falls within (or on the boundary) of the query bounding box. * The value comparisons are subject to a precision tolerance defined in - * {@value org.apache.lucene.util.GeoUtils#TOLERANCE} + * {@value org.apache.lucene.spatial.util.GeoUtils#TOLERANCE} * * NOTES: * 1. All latitude/longitude values must be in decimal degrees. @@ -45,6 +50,10 @@ public class GeoPointInBBoxQuery extends Query { protected final double maxLon; protected final double maxLat; + /** + * Constructs a query for all {@link org.apache.lucene.spatial.document.GeoPointField} types that fall within a + * defined bounding box + */ public GeoPointInBBoxQuery(final String field, final double minLon, final double minLat, final double maxLon, final double maxLat) { this.field = field; this.minLon = minLon; @@ -130,22 +139,27 @@ public class GeoPointInBBoxQuery extends Query { return result; } + /** getter method for retrieving the field name */ public final String getField() { return this.field; } + /** getter method for retrieving the minimum longitude (in degrees) */ public final double getMinLon() { return this.minLon; } + /** getter method for retrieving the minimum latitude (in degrees) */ public final double getMinLat() { return this.minLat; } + /** getter method for retrieving the maximum longitude (in degrees) */ public final double getMaxLon() { return this.maxLon; } + /** getter method for retrieving the maximum latitude (in degrees) */ public final double getMaxLat() { return this.maxLat; } diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointInBBoxQueryImpl.java b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointInBBoxQueryImpl.java similarity index 95% rename from lucene/sandbox/src/java/org/apache/lucene/search/GeoPointInBBoxQueryImpl.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointInBBoxQueryImpl.java index b385a542ff5..bd44b1ebcb1 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointInBBoxQueryImpl.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointInBBoxQueryImpl.java @@ -14,16 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.search; +package org.apache.lucene.spatial.search; import java.io.IOException; -import org.apache.lucene.document.GeoPointField; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; +import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.util.AttributeSource; -import org.apache.lucene.util.GeoRelationUtils; import org.apache.lucene.util.SloppyMath; +import org.apache.lucene.spatial.document.GeoPointField; +import org.apache.lucene.spatial.util.GeoRelationUtils; /** Package private implementation for the public facing GeoPointInBBoxQuery delegate class. * @@ -49,7 +50,7 @@ class GeoPointInBBoxQueryImpl extends GeoPointTermQuery { } @Override - public void setRewriteMethod(RewriteMethod method) { + public void setRewriteMethod(MultiTermQuery.RewriteMethod method) { throw new UnsupportedOperationException("cannot change rewrite method"); } diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointInPolygonQuery.java b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointInPolygonQuery.java similarity index 93% rename from lucene/sandbox/src/java/org/apache/lucene/search/GeoPointInPolygonQuery.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointInPolygonQuery.java index abdcf95baea..b1e864b81dd 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointInPolygonQuery.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointInPolygonQuery.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.search; +package org.apache.lucene.spatial.search; import java.io.IOException; import java.util.Arrays; @@ -22,9 +22,9 @@ import java.util.Arrays; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.util.AttributeSource; -import org.apache.lucene.util.GeoRect; -import org.apache.lucene.util.GeoRelationUtils; -import org.apache.lucene.util.GeoUtils; +import org.apache.lucene.spatial.util.GeoRect; +import org.apache.lucene.spatial.util.GeoRelationUtils; +import org.apache.lucene.spatial.util.GeoUtils; /** Implements a simple point in polygon query on a GeoPoint field. This is based on * {@code GeoPointInBBoxQueryImpl} and is implemented using a @@ -34,7 +34,7 @@ import org.apache.lucene.util.GeoUtils; * to a secondary filter that verifies whether the decoded lat/lon point falls within * (or on the boundary) of the bounding box query. Finally, the remaining candidate * term is passed to the final point in polygon check. All value comparisons are subject - * to the same precision tolerance defined in {@value org.apache.lucene.util.GeoUtils#TOLERANCE} + * to the same precision tolerance defined in {@value org.apache.lucene.spatial.util.GeoUtils#TOLERANCE} * *

NOTES: * 1. The polygon coordinates need to be in either clockwise or counter-clockwise order. @@ -52,7 +52,7 @@ public final class GeoPointInPolygonQuery extends GeoPointInBBoxQueryImpl { private final double[] y; /** - * Constructs a new GeoPolygonQuery that will match encoded {@link org.apache.lucene.document.GeoPointField} terms + * Constructs a new GeoPolygonQuery that will match encoded {@link org.apache.lucene.spatial.document.GeoPointField} terms * that fall within or on the boundary of the polygon defined by the input parameters. */ public GeoPointInPolygonQuery(final String field, final double[] polyLons, final double[] polyLats) { @@ -84,6 +84,7 @@ public final class GeoPointInPolygonQuery extends GeoPointInBBoxQueryImpl { return new GeoPolygonTermsEnum(terms.iterator(), this.minLon, this.minLat, this.maxLon, this.maxLat); } + /** throw exception if trying to change rewrite method */ @Override public void setRewriteMethod(RewriteMethod method) { throw new UnsupportedOperationException("cannot change rewrite method"); @@ -111,6 +112,7 @@ public final class GeoPointInPolygonQuery extends GeoPointInBBoxQueryImpl { return result; } + /** print out this polygon query */ @Override public String toString(String field) { assert x.length == y.length; @@ -165,10 +167,10 @@ public final class GeoPointInPolygonQuery extends GeoPointInBBoxQueryImpl { /** * The two-phase query approach. The parent - * {@link org.apache.lucene.search.GeoPointTermsEnum#accept} method is called to match + * {@link GeoPointTermsEnum#accept} method is called to match * encoded terms that fall within the bounding box of the polygon. Those documents that pass the initial * bounding box filter are then compared to the provided polygon using the - * {@link org.apache.lucene.util.GeoRelationUtils#pointInPolygon} method. + * {@link org.apache.lucene.spatial.util.GeoRelationUtils#pointInPolygon} method. */ @Override protected boolean postFilter(final double lon, final double lat) { diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointTermQuery.java b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointTermQuery.java similarity index 56% rename from lucene/sandbox/src/java/org/apache/lucene/search/GeoPointTermQuery.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointTermQuery.java index 5ec0774dd3d..894a1e92953 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointTermQuery.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointTermQuery.java @@ -14,10 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.search; +package org.apache.lucene.spatial.search; + +import java.io.IOException; import org.apache.lucene.index.IndexReader; -import org.apache.lucene.util.GeoUtils; +import org.apache.lucene.index.Terms; +import org.apache.lucene.index.TermsEnum; +import org.apache.lucene.search.MultiTermQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.spatial.util.GeoUtils; +import org.apache.lucene.util.AttributeSource; /** * TermQuery for GeoPointField for overriding {@link org.apache.lucene.search.MultiTermQuery} methods specific to @@ -27,9 +34,13 @@ import org.apache.lucene.util.GeoUtils; */ abstract class GeoPointTermQuery extends MultiTermQuery { // simple bounding box optimization - no objects used to avoid dependencies + /** minimum longitude value (in degrees) */ protected final double minLon; + /** minimum latitude value (in degrees) */ protected final double minLat; + /** maximum longitude value (in degrees) */ protected final double maxLon; + /** maximum latitude value (in degrees) */ protected final double maxLat; /** @@ -59,12 +70,45 @@ abstract class GeoPointTermQuery extends MultiTermQuery { this.rewriteMethod = GEO_CONSTANT_SCORE_REWRITE; } - public static final RewriteMethod GEO_CONSTANT_SCORE_REWRITE = new RewriteMethod() { + private static final RewriteMethod GEO_CONSTANT_SCORE_REWRITE = new RewriteMethod() { @Override public Query rewrite(IndexReader reader, MultiTermQuery query) { return new GeoPointTermQueryConstantScoreWrapper<>((GeoPointTermQuery)query); } }; + /** override package protected method */ + @Override + protected abstract TermsEnum getTermsEnum(final Terms terms, AttributeSource atts) throws IOException; + /** check if this instance equals another instance */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + GeoPointTermQuery that = (GeoPointTermQuery) o; + + if (Double.compare(that.minLon, minLon) != 0) return false; + if (Double.compare(that.minLat, minLat) != 0) return false; + if (Double.compare(that.maxLon, maxLon) != 0) return false; + return Double.compare(that.maxLat, maxLat) == 0; + } + + /** compute hashcode */ + @Override + public int hashCode() { + int result = super.hashCode(); + long temp; + temp = Double.doubleToLongBits(minLon); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(minLat); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(maxLon); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(maxLat); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } } diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointTermQueryConstantScoreWrapper.java b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointTermQueryConstantScoreWrapper.java similarity index 86% rename from lucene/sandbox/src/java/org/apache/lucene/search/GeoPointTermQueryConstantScoreWrapper.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointTermQueryConstantScoreWrapper.java index e00bb720967..8176aec41db 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointTermQueryConstantScoreWrapper.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointTermQueryConstantScoreWrapper.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.search; +package org.apache.lucene.spatial.search; import java.io.IOException; @@ -23,8 +23,17 @@ import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.Terms; +import org.apache.lucene.search.BulkScorer; +import org.apache.lucene.search.ConstantScoreScorer; +import org.apache.lucene.search.ConstantScoreWeight; +import org.apache.lucene.search.DocIdSet; +import org.apache.lucene.search.DocIdSetIterator; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.Scorer; +import org.apache.lucene.search.Weight; import org.apache.lucene.util.DocIdSetBuilder; -import org.apache.lucene.util.GeoUtils; +import org.apache.lucene.spatial.util.GeoUtils; /** * Custom ConstantScoreWrapper for {@code GeoPointTermQuery} that cuts over to DocValues @@ -63,18 +72,18 @@ final class GeoPointTermQueryConstantScoreWrapper return new ConstantScoreWeight(this) { private DocIdSet getDocIDs(LeafReaderContext context) throws IOException { - final Terms terms = context.reader().terms(query.field); + final Terms terms = context.reader().terms(query.getField()); if (terms == null) { return DocIdSet.EMPTY; } - final GeoPointTermsEnum termsEnum = (GeoPointTermsEnum)(query.getTermsEnum(terms)); + final GeoPointTermsEnum termsEnum = (GeoPointTermsEnum)(query.getTermsEnum(terms, null)); assert termsEnum != null; LeafReader reader = context.reader(); DocIdSetBuilder builder = new DocIdSetBuilder(reader.maxDoc()); PostingsEnum docs = null; - SortedNumericDocValues sdv = reader.getSortedNumericDocValues(query.field); + SortedNumericDocValues sdv = reader.getSortedNumericDocValues(query.getField()); while (termsEnum.next() != null) { docs = termsEnum.postings(docs, PostingsEnum.NONE); diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointTermsEnum.java b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointTermsEnum.java similarity index 97% rename from lucene/sandbox/src/java/org/apache/lucene/search/GeoPointTermsEnum.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointTermsEnum.java index e2f96d4cb6d..71eb26ed9ae 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/GeoPointTermsEnum.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/search/GeoPointTermsEnum.java @@ -14,19 +14,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.search; +package org.apache.lucene.spatial.search; import java.util.Collections; import java.util.LinkedList; import java.util.List; -import org.apache.lucene.document.GeoPointField; +import org.apache.lucene.spatial.document.GeoPointField; import org.apache.lucene.index.FilteredTermsEnum; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRefBuilder; -import org.apache.lucene.util.GeoRelationUtils; -import org.apache.lucene.util.GeoUtils; +import org.apache.lucene.spatial.util.GeoRelationUtils; +import org.apache.lucene.spatial.util.GeoUtils; import org.apache.lucene.util.LegacyNumericUtils; /** diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/search/package-info.java b/lucene/spatial/src/java/org/apache/lucene/spatial/search/package-info.java new file mode 100644 index 00000000000..8e8265c8546 --- /dev/null +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/search/package-info.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/** + * Geospatial Query Implementations for Core Lucene + */ +package org.apache.lucene.spatial.search; \ No newline at end of file diff --git a/lucene/sandbox/src/java/org/apache/lucene/util/GeoDistanceUtils.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoDistanceUtils.java similarity index 98% rename from lucene/sandbox/src/java/org/apache/lucene/util/GeoDistanceUtils.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoDistanceUtils.java index 91347094dc5..e845c9e0c3b 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/util/GeoDistanceUtils.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoDistanceUtils.java @@ -14,7 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.util; +package org.apache.lucene.spatial.util; + +import org.apache.lucene.util.SloppyMath; import static org.apache.lucene.util.SloppyMath.TO_RADIANS; @@ -27,6 +29,10 @@ public class GeoDistanceUtils { /** error threshold for point-distance queries (in percent) NOTE: Guideline from USGS is 0.005 **/ public static final double DISTANCE_PCT_ERR = 0.005; + // No instance: + private GeoDistanceUtils() { + } + /** * Compute the great-circle distance using original haversine implementation published by Sinnot in: * R.W. Sinnott, "Virtues of the Haversine", Sky and Telescope, vol. 68, no. 2, 1984, p. 159 diff --git a/lucene/sandbox/src/java/org/apache/lucene/util/GeoHashUtils.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoHashUtils.java similarity index 95% rename from lucene/sandbox/src/java/org/apache/lucene/util/GeoHashUtils.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoHashUtils.java index d421cc9f5b2..9450c1eb32d 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/util/GeoHashUtils.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoHashUtils.java @@ -14,11 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.util; +package org.apache.lucene.spatial.util; import java.util.ArrayList; import java.util.Collection; +import org.apache.lucene.util.BitUtil; + /** * Utilities for converting to/from the GeoHash standard * @@ -30,15 +32,20 @@ import java.util.Collection; * @lucene.experimental */ public class GeoHashUtils { - public static final char[] BASE_32 = {'0', '1', '2', '3', '4', '5', '6', + private static final char[] BASE_32 = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; - public static final String BASE_32_STRING = new String(BASE_32); + private static final String BASE_32_STRING = new String(BASE_32); + /** maximum precision for geohash strings */ public static final int PRECISION = 12; private static final short MORTON_OFFSET = (GeoUtils.BITS<<1) - (PRECISION*5); + // No instance: + private GeoHashUtils() { + } + /** * Encode lon/lat to the geohash based long format (lon/lat interleaved, 4 least significant bits = level) */ @@ -75,6 +82,9 @@ public class GeoHashUtils { return ((geohash >>> 4) << (((level - precision) * 5) + 4) | level); } + /** + * Convert from a morton encoded long from a geohash encoded long + */ public static long fromMorton(long morton, int level) { long mFlipped = BitUtil.flipFlop(morton); mFlipped >>>= (((GeoHashUtils.PRECISION - level) * 5) + MORTON_OFFSET); diff --git a/lucene/sandbox/src/java/org/apache/lucene/util/GeoProjectionUtils.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoProjectionUtils.java similarity index 82% rename from lucene/sandbox/src/java/org/apache/lucene/util/GeoProjectionUtils.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoProjectionUtils.java index 7e285dafed1..5a81adc1b61 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/util/GeoProjectionUtils.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoProjectionUtils.java @@ -14,32 +14,60 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.util; +package org.apache.lucene.spatial.util; +import static java.lang.StrictMath.sqrt; + +import static org.apache.lucene.util.SloppyMath.asin; +import static org.apache.lucene.util.SloppyMath.cos; +import static org.apache.lucene.util.SloppyMath.sin; +import static org.apache.lucene.util.SloppyMath.tan; import static org.apache.lucene.util.SloppyMath.PIO2; import static org.apache.lucene.util.SloppyMath.TO_DEGREES; import static org.apache.lucene.util.SloppyMath.TO_RADIANS; +import static org.apache.lucene.spatial.util.GeoUtils.MAX_LAT_INCL; +import static org.apache.lucene.spatial.util.GeoUtils.MAX_LON_INCL; +import static org.apache.lucene.spatial.util.GeoUtils.MIN_LAT_INCL; +import static org.apache.lucene.spatial.util.GeoUtils.MIN_LON_INCL; +import static org.apache.lucene.spatial.util.GeoUtils.normalizeLat; +import static org.apache.lucene.spatial.util.GeoUtils.normalizeLon; + /** * Reusable geo-spatial projection utility methods. * * @lucene.experimental */ public class GeoProjectionUtils { - // WGS84 earth-ellipsoid major (a) minor (b) radius, (f) flattening and eccentricity (e) + // WGS84 earth-ellipsoid parameters + /** major (a) axis in meters */ public static final double SEMIMAJOR_AXIS = 6_378_137; // [m] + /** earth flattening factor (f) */ public static final double FLATTENING = 1.0/298.257223563; + /** minor (b) axis in meters */ public static final double SEMIMINOR_AXIS = SEMIMAJOR_AXIS * (1.0 - FLATTENING); //6_356_752.31420; // [m] - public static final double ECCENTRICITY = StrictMath.sqrt((2.0 - FLATTENING) * FLATTENING); - static final double SEMIMAJOR_AXIS2 = SEMIMAJOR_AXIS * SEMIMAJOR_AXIS; - static final double SEMIMINOR_AXIS2 = SEMIMINOR_AXIS * SEMIMINOR_AXIS; - public static final double MIN_LON_RADIANS = TO_RADIANS * GeoUtils.MIN_LON_INCL; - public static final double MIN_LAT_RADIANS = TO_RADIANS * GeoUtils.MIN_LAT_INCL; - public static final double MAX_LON_RADIANS = TO_RADIANS * GeoUtils.MAX_LON_INCL; - public static final double MAX_LAT_RADIANS = TO_RADIANS * GeoUtils.MAX_LAT_INCL; + /** first eccentricity (e) */ + public static final double ECCENTRICITY = sqrt((2.0 - FLATTENING) * FLATTENING); + /** major axis squared (a2) */ + public static final double SEMIMAJOR_AXIS2 = SEMIMAJOR_AXIS * SEMIMAJOR_AXIS; + /** minor axis squared (b2) */ + public static final double SEMIMINOR_AXIS2 = SEMIMINOR_AXIS * SEMIMINOR_AXIS; private static final double E2 = (SEMIMAJOR_AXIS2 - SEMIMINOR_AXIS2)/(SEMIMAJOR_AXIS2); private static final double EP2 = (SEMIMAJOR_AXIS2 - SEMIMINOR_AXIS2)/(SEMIMINOR_AXIS2); + /** min longitude value in radians */ + public static final double MIN_LON_RADIANS = TO_RADIANS * MIN_LON_INCL; + /** min latitude value in radians */ + public static final double MIN_LAT_RADIANS = TO_RADIANS * MIN_LAT_INCL; + /** max longitude value in radians */ + public static final double MAX_LON_RADIANS = TO_RADIANS * MAX_LON_INCL; + /** max latitude value in radians */ + public static final double MAX_LAT_RADIANS = TO_RADIANS * MAX_LAT_INCL; + + // No instance: + private GeoProjectionUtils() { + } + /** * Converts from geocentric earth-centered earth-fixed to geodesic lat/lon/alt * @param x Cartesian x coordinate @@ -121,9 +149,9 @@ public class GeoProjectionUtils { lon = TO_RADIANS * lon; lat = TO_RADIANS * lat; - final double sl = SloppyMath.sin(lat); + final double sl = sin(lat); final double s2 = sl*sl; - final double cl = SloppyMath.cos(lat); + final double cl = cos(lat); if (ecf == null) { ecf = new double[3]; @@ -141,8 +169,8 @@ public class GeoProjectionUtils { } final double rn = SEMIMAJOR_AXIS / StrictMath.sqrt(1.0D - E2 * s2); - ecf[0] = (rn+alt) * cl * SloppyMath.cos(lon); - ecf[1] = (rn+alt) * cl * SloppyMath.sin(lon); + ecf[0] = (rn+alt) * cl * cos(lon); + ecf[1] = (rn+alt) * cl * sin(lon); ecf[2] = ((rn*(1.0-E2))+alt)*sl; return ecf; @@ -276,10 +304,10 @@ public class GeoProjectionUtils { originLon = TO_RADIANS * originLon; originLat = TO_RADIANS * originLat; - final double sLon = SloppyMath.sin(originLon); - final double cLon = SloppyMath.cos(originLon); - final double sLat = SloppyMath.sin(originLat); - final double cLat = SloppyMath.cos(originLat); + final double sLon = sin(originLon); + final double cLon = cos(originLon); + final double sLat = sin(originLat); + final double cLat = cos(originLat); phiMatrix[0][0] = -sLon; phiMatrix[0][1] = cLon; @@ -310,10 +338,10 @@ public class GeoProjectionUtils { originLon = TO_RADIANS * originLon; originLat = TO_RADIANS * originLat; - final double sLat = SloppyMath.sin(originLat); - final double cLat = SloppyMath.cos(originLat); - final double sLon = SloppyMath.sin(originLon); - final double cLon = SloppyMath.cos(originLon); + final double sLat = sin(originLat); + final double cLat = cos(originLat); + final double sLon = sin(originLon); + final double cLon = cos(originLon); phiMatrix[0][0] = -sLon; phiMatrix[1][0] = cLon; @@ -345,9 +373,9 @@ public class GeoProjectionUtils { } final double alpha1 = TO_RADIANS * bearing; - final double cosA1 = SloppyMath.cos(alpha1); - final double sinA1 = SloppyMath.sin(alpha1); - final double tanU1 = (1-FLATTENING) * SloppyMath.tan(TO_RADIANS * lat); + final double cosA1 = cos(alpha1); + final double sinA1 = sin(alpha1); + final double tanU1 = (1-FLATTENING) * tan(TO_RADIANS * lat); final double cosU1 = 1 / StrictMath.sqrt((1+tanU1*tanU1)); final double sinU1 = tanU1*cosU1; final double sig1 = StrictMath.atan2(tanU1, cosA1); @@ -362,9 +390,9 @@ public class GeoProjectionUtils { double sinSigma, cosSigma, cos2SigmaM, deltaSigma; do { - cos2SigmaM = SloppyMath.cos(2*sig1 + sigma); - sinSigma = SloppyMath.sin(sigma); - cosSigma = SloppyMath.cos(sigma); + cos2SigmaM = cos(2*sig1 + sigma); + sinSigma = sin(sigma); + cosSigma = cos(sigma); deltaSigma = B * sinSigma * (cos2SigmaM + (B/4D) * (cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)- (B/6) * cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))); @@ -380,8 +408,8 @@ public class GeoProjectionUtils { final double lam = lambda - (1-c) * FLATTENING * sinAlpha * (sigma + c * sinSigma * (cos2SigmaM + c * cosSigma * (-1 + 2* cos2SigmaM*cos2SigmaM))); - pt[0] = GeoUtils.normalizeLon(lon + TO_DEGREES * lam); - pt[1] = GeoUtils.normalizeLat(TO_DEGREES * lat2); + pt[0] = normalizeLon(lon + TO_DEGREES * lam); + pt[1] = normalizeLat(TO_DEGREES * lat2); return pt; } @@ -406,13 +434,13 @@ public class GeoProjectionUtils { lat *= TO_RADIANS; bearing *= TO_RADIANS; - final double cLat = SloppyMath.cos(lat); - final double sLat = SloppyMath.sin(lat); - final double sinDoR = SloppyMath.sin(dist / GeoProjectionUtils.SEMIMAJOR_AXIS); - final double cosDoR = SloppyMath.cos(dist / GeoProjectionUtils.SEMIMAJOR_AXIS); + final double cLat = cos(lat); + final double sLat = sin(lat); + final double sinDoR = sin(dist / GeoProjectionUtils.SEMIMAJOR_AXIS); + final double cosDoR = cos(dist / GeoProjectionUtils.SEMIMAJOR_AXIS); - pt[1] = SloppyMath.asin(sLat*cosDoR + cLat * sinDoR * SloppyMath.cos(bearing)); - pt[0] = TO_DEGREES * (lon + Math.atan2(SloppyMath.sin(bearing) * sinDoR * cLat, cosDoR - sLat * SloppyMath.sin(pt[1]))); + pt[1] = asin(sLat*cosDoR + cLat * sinDoR * cos(bearing)); + pt[0] = TO_DEGREES * (lon + Math.atan2(sin(bearing) * sinDoR * cLat, cosDoR - sLat * sin(pt[1]))); pt[1] *= TO_DEGREES; return pt; @@ -430,8 +458,8 @@ public class GeoProjectionUtils { double dLon = (lon2 - lon1) * TO_RADIANS; lat2 *= TO_RADIANS; lat1 *= TO_RADIANS; - double y = SloppyMath.sin(dLon) * SloppyMath.cos(lat2); - double x = SloppyMath.cos(lat1) * SloppyMath.sin(lat2) - SloppyMath.sin(lat1) * SloppyMath.cos(lat2) * SloppyMath.cos(dLon); + double y = sin(dLon) * cos(lat2); + double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon); return Math.atan2(y, x) * TO_DEGREES; } } diff --git a/lucene/sandbox/src/java/org/apache/lucene/util/GeoRect.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRect.java similarity index 98% rename from lucene/sandbox/src/java/org/apache/lucene/util/GeoRect.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRect.java index f8cf1da8a26..fa93e614412 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/util/GeoRect.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRect.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.util; +package org.apache.lucene.spatial.util; /** Represents a lat/lon rectangle. */ public class GeoRect { diff --git a/lucene/sandbox/src/java/org/apache/lucene/util/GeoRelationUtils.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRelationUtils.java similarity index 97% rename from lucene/sandbox/src/java/org/apache/lucene/util/GeoRelationUtils.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRelationUtils.java index 092b9498134..19117201a9a 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/util/GeoRelationUtils.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRelationUtils.java @@ -14,13 +14,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.util; +package org.apache.lucene.spatial.util; + +import org.apache.lucene.util.SloppyMath; /** * Reusable geo-relation utility methods */ public class GeoRelationUtils { + // No instance: + private GeoRelationUtils() { + } + /** * Determine if a bbox (defined by minLon, minLat, maxLon, maxLat) contains the provided point (defined by lon, lat) * NOTE: this is a basic method that does not handle dateline or pole crossing. Unwrapping must be done before @@ -62,6 +68,9 @@ public class GeoRelationUtils { // Rectangle relations ///////////////////////// + /** + * Computes whether two rectangles are disjoint + */ public static boolean rectDisjoint(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY, final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) { return (aMaxX < bMinX || aMinX > bMaxX || aMaxY < bMinY || aMinY > bMaxY); @@ -75,6 +84,9 @@ public class GeoRelationUtils { return !(aMinX < bMinX || aMinY < bMinY || aMaxX > bMaxX || aMaxY > bMaxY); } + /** + * Computes whether two rectangles cross + */ public static boolean rectCrosses(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY, final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) { return !(rectDisjoint(aMinX, aMinY, aMaxX, aMaxY, bMinX, bMinY, bMaxX, bMaxY) || @@ -380,11 +392,18 @@ public class GeoRelationUtils { || SloppyMath.haversin(centerLat, centerLon, rMinY, rMaxX)*1000.0 > radiusMeters; } + /** + * Convenience method for computing whether a rectangle is within a circle using additional precision checks + */ public static boolean rectWithinCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY, final double centerLon, final double centerLat, final double radiusMeters) { return rectWithinCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, false); } + /** + * Computes whether a rectangle is within a circle. Note: approx == true will be faster but less precise and may + * fail on large rectangles + */ public static boolean rectWithinCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY, final double centerLon, final double centerLat, final double radiusMeters, final boolean approx) { @@ -401,6 +420,10 @@ public class GeoRelationUtils { return rectCrossesCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, false); } + /** + * Computes whether a rectangle crosses a circle. Note: approx == true will be faster but less precise and may + * fail on large rectangles + */ public static boolean rectCrossesCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY, final double centerLon, final double centerLat, final double radiusMeters, final boolean approx) { diff --git a/lucene/sandbox/src/java/org/apache/lucene/util/GeoUtils.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoUtils.java similarity index 69% rename from lucene/sandbox/src/java/org/apache/lucene/util/GeoUtils.java rename to lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoUtils.java index a2d0fd14f56..8899170b8ea 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/util/GeoUtils.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoUtils.java @@ -14,12 +14,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.util; +package org.apache.lucene.spatial.util; import java.util.ArrayList; +import org.apache.lucene.util.BitUtil; + +import static java.lang.Math.max; +import static java.lang.Math.min; +import static java.lang.Math.PI; +import static java.lang.Math.abs; + +import static org.apache.lucene.util.SloppyMath.asin; +import static org.apache.lucene.util.SloppyMath.cos; +import static org.apache.lucene.util.SloppyMath.sin; import static org.apache.lucene.util.SloppyMath.TO_DEGREES; import static org.apache.lucene.util.SloppyMath.TO_RADIANS; +import static org.apache.lucene.spatial.util.GeoProjectionUtils.MAX_LAT_RADIANS; +import static org.apache.lucene.spatial.util.GeoProjectionUtils.MAX_LON_RADIANS; +import static org.apache.lucene.spatial.util.GeoProjectionUtils.MIN_LAT_RADIANS; +import static org.apache.lucene.spatial.util.GeoProjectionUtils.MIN_LON_RADIANS; +import static org.apache.lucene.spatial.util.GeoProjectionUtils.pointFromLonLatBearingGreatCircle; +import static org.apache.lucene.spatial.util.GeoProjectionUtils.SEMIMAJOR_AXIS; /** * Basic reusable geo-spatial utility methods @@ -27,9 +43,11 @@ import static org.apache.lucene.util.SloppyMath.TO_RADIANS; * @lucene.experimental */ public final class GeoUtils { + /** number of bits used for quantizing latitude and longitude values */ public static final short BITS = 31; private static final double LON_SCALE = (0x1L<>> 1)); } @@ -76,17 +100,13 @@ public final class GeoUtils { return (val / LAT_SCALE) + MIN_LAT_INCL; } - /** - * Compare two position values within a {@link org.apache.lucene.util.GeoUtils#TOLERANCE} factor - */ + /** Compare two position values within a {@link GeoUtils#TOLERANCE} factor */ public static double compare(final double v1, final double v2) { final double delta = v1-v2; - return Math.abs(delta) <= TOLERANCE ? 0 : delta; + return abs(delta) <= TOLERANCE ? 0 : delta; } - /** - * Puts longitude in range of -180 to +180. - */ + /** Puts longitude in range of -180 to +180. */ public static double normalizeLon(double lon_deg) { if (lon_deg >= -180 && lon_deg <= 180) { return lon_deg; //common case, and avoids slight double precision shifting @@ -101,17 +121,16 @@ public final class GeoUtils { } } - /** - * Puts latitude in range of -90 to 90. - */ + /** Puts latitude in range of -90 to 90. */ public static double normalizeLat(double lat_deg) { if (lat_deg >= -90 && lat_deg <= 90) { return lat_deg; //common case, and avoids slight double precision shifting } - double off = Math.abs((lat_deg + 90) % 360); + double off = abs((lat_deg + 90) % 360); return (off <= 180 ? off : 360-off) - 90; } + /** Converts long value to bit string (useful for debugging) */ public static String geoTermToString(long term) { StringBuilder s = new StringBuilder(64); final int numberOfLeadingZeros = Long.numberOfLeadingZeros(term); @@ -145,7 +164,7 @@ public final class GeoUtils { final int sidesLen = sides-1; for (int i=0; i GeoProjectionUtils.MIN_LAT_RADIANS && maxLat < GeoProjectionUtils.MAX_LAT_RADIANS) { - double deltaLon = SloppyMath.asin(SloppyMath.sin(radDistance) / SloppyMath.cos(radLat)); + if (minLat > MIN_LAT_RADIANS && maxLat < MAX_LAT_RADIANS) { + double deltaLon = asin(sin(radDistance) / cos(radLat)); minLon = radLon - deltaLon; - if (minLon < GeoProjectionUtils.MIN_LON_RADIANS) { - minLon += 2d * StrictMath.PI; + if (minLon < MIN_LON_RADIANS) { + minLon += 2d * PI; } maxLon = radLon + deltaLon; - if (maxLon > GeoProjectionUtils.MAX_LON_RADIANS) { - maxLon -= 2d * StrictMath.PI; + if (maxLon > MAX_LON_RADIANS) { + maxLon -= 2d * PI; } } else { // a pole is within the distance - minLat = StrictMath.max(minLat, GeoProjectionUtils.MIN_LAT_RADIANS); - maxLat = StrictMath.min(maxLat, GeoProjectionUtils.MAX_LAT_RADIANS); - minLon = GeoProjectionUtils.MIN_LON_RADIANS; - maxLon = GeoProjectionUtils.MAX_LON_RADIANS; + minLat = max(minLat, MIN_LAT_RADIANS); + maxLat = min(maxLat, MAX_LAT_RADIANS); + minLon = MIN_LON_RADIANS; + maxLon = MAX_LON_RADIANS; } return new GeoRect(TO_DEGREES * minLon, TO_DEGREES * maxLon, TO_DEGREES * minLat, TO_DEGREES * maxLat); } - /** - * Compute Bounding Box for a polygon using WGS-84 parameters - */ + /** Compute Bounding Box for a polygon using WGS-84 parameters */ public static GeoRect polyToBBox(double[] polyLons, double[] polyLats) { if (polyLons.length != polyLats.length) { throw new IllegalArgumentException("polyLons and polyLats must be equal length"); @@ -211,26 +226,22 @@ public final class GeoUtils { if (GeoUtils.isValidLat(polyLats[i]) == false) { throw new IllegalArgumentException("invalid polyLats[" + i + "]=" + polyLats[i]); } - minLon = Math.min(polyLons[i], minLon); - maxLon = Math.max(polyLons[i], maxLon); - minLat = Math.min(polyLats[i], minLat); - maxLat = Math.max(polyLats[i], maxLat); + minLon = min(polyLons[i], minLon); + maxLon = max(polyLons[i], maxLon); + minLat = min(polyLats[i], minLat); + maxLat = max(polyLats[i], maxLat); } // expand bounding box by TOLERANCE factor to handle round-off error - return new GeoRect(Math.max(minLon - TOLERANCE, MIN_LON_INCL), Math.min(maxLon + TOLERANCE, MAX_LON_INCL), - Math.max(minLat - TOLERANCE, MIN_LAT_INCL), Math.min(maxLat + TOLERANCE, MAX_LAT_INCL)); + return new GeoRect(max(minLon - TOLERANCE, MIN_LON_INCL), min(maxLon + TOLERANCE, MAX_LON_INCL), + max(minLat - TOLERANCE, MIN_LAT_INCL), min(maxLat + TOLERANCE, MAX_LAT_INCL)); } - /** - * validates latitude value is within standard +/-90 coordinate bounds - */ + /** validates latitude value is within standard +/-90 coordinate bounds */ public static boolean isValidLat(double lat) { return Double.isNaN(lat) == false && lat >= MIN_LAT_INCL && lat <= MAX_LAT_INCL; } - /** - * validates longitude value is within standard +/-180 coordinate bounds - */ + /** validates longitude value is within standard +/-180 coordinate bounds */ public static boolean isValidLon(double lon) { return Double.isNaN(lon) == false && lon >= MIN_LON_INCL && lon <= MAX_LON_INCL; } diff --git a/lucene/sandbox/src/test/org/apache/lucene/search/TestGeoPointQuery.java b/lucene/spatial/src/test/org/apache/lucene/spatial/search/TestGeoPointQuery.java similarity index 96% rename from lucene/sandbox/src/test/org/apache/lucene/search/TestGeoPointQuery.java rename to lucene/spatial/src/test/org/apache/lucene/spatial/search/TestGeoPointQuery.java index a91cbd68a9b..4002531e797 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/search/TestGeoPointQuery.java +++ b/lucene/spatial/src/test/org/apache/lucene/spatial/search/TestGeoPointQuery.java @@ -14,27 +14,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.search; +package org.apache.lucene.spatial.search; import org.apache.lucene.analysis.MockAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.FieldType; -import org.apache.lucene.document.GeoPointField; import org.apache.lucene.document.StringField; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; -import org.apache.lucene.util.BaseGeoPointTestCase; -import org.apache.lucene.util.GeoRect; -import org.apache.lucene.util.GeoRelationUtils; -import org.apache.lucene.util.GeoUtils; +import org.apache.lucene.spatial.document.GeoPointField; +import org.apache.lucene.spatial.util.BaseGeoPointTestCase; +import org.apache.lucene.spatial.util.GeoRect; +import org.apache.lucene.spatial.util.GeoRelationUtils; +import org.apache.lucene.spatial.util.GeoUtils; import org.apache.lucene.util.SloppyMath; import org.apache.lucene.util.TestUtil; import org.junit.AfterClass; import org.junit.BeforeClass; -import static org.apache.lucene.util.GeoDistanceUtils.DISTANCE_PCT_ERR; +import static org.apache.lucene.spatial.util.GeoDistanceUtils.DISTANCE_PCT_ERR; /** * Unit testing for basic GeoPoint query logic diff --git a/lucene/sandbox/src/test/org/apache/lucene/util/BaseGeoPointTestCase.java b/lucene/spatial/src/test/org/apache/lucene/spatial/util/BaseGeoPointTestCase.java similarity index 99% rename from lucene/sandbox/src/test/org/apache/lucene/util/BaseGeoPointTestCase.java rename to lucene/spatial/src/test/org/apache/lucene/spatial/util/BaseGeoPointTestCase.java index 5a469db5ce2..9f6edda9aa0 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/util/BaseGeoPointTestCase.java +++ b/lucene/spatial/src/test/org/apache/lucene/spatial/util/BaseGeoPointTestCase.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.util; +package org.apache.lucene.spatial.util; import java.io.IOException; import java.text.DecimalFormat; @@ -45,6 +45,11 @@ import org.apache.lucene.search.Query; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.store.Directory; import org.apache.lucene.store.MockDirectoryWrapper; +import org.apache.lucene.util.FixedBitSet; +import org.apache.lucene.util.IOUtils; +import org.apache.lucene.util.LuceneTestCase; +import org.apache.lucene.util.SloppyMath; +import org.apache.lucene.util.TestUtil; import org.junit.BeforeClass; // TODO: cutover TestGeoUtils too? diff --git a/lucene/sandbox/src/test/org/apache/lucene/util/TestGeoUtils.java b/lucene/spatial/src/test/org/apache/lucene/spatial/util/TestGeoUtils.java similarity index 99% rename from lucene/sandbox/src/test/org/apache/lucene/util/TestGeoUtils.java rename to lucene/spatial/src/test/org/apache/lucene/spatial/util/TestGeoUtils.java index 56506148f9d..7dc9318263d 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/util/TestGeoUtils.java +++ b/lucene/spatial/src/test/org/apache/lucene/spatial/util/TestGeoUtils.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.lucene.util; +package org.apache.lucene.spatial.util; import java.io.PrintWriter; import java.io.StringWriter; @@ -24,11 +24,12 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import org.apache.lucene.util.LuceneTestCase; import org.junit.BeforeClass; import com.carrotsearch.randomizedtesting.generators.RandomInts; -import static org.apache.lucene.util.GeoDistanceUtils.DISTANCE_PCT_ERR; +import static org.apache.lucene.spatial.util.GeoDistanceUtils.DISTANCE_PCT_ERR; /** * Tests class for methods in GeoUtils