diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java index 3fdefb55240..dd171ec1ae0 100644 --- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java @@ -22,10 +22,12 @@ import org.apache.lucene.search.FieldDoc; import org.apache.lucene.search.SortField; import org.apache.lucene.document.Field; import org.apache.lucene.document.FieldType; +import org.apache.lucene.geo.Polygon; import org.apache.lucene.spatial3d.geom.PlanetModel; import org.apache.lucene.spatial3d.geom.GeoPoint; import org.apache.lucene.spatial3d.geom.GeoDistanceShape; +import org.apache.lucene.spatial3d.geom.GeoOutsideDistance; /** * An per-document 3D location field. @@ -256,7 +258,7 @@ public class Geo3DDocValuesField extends Field { } /** - * Creates a SortField for sorting by distance from a point. + * Creates a SortField for sorting by distance within a circle. *
* This sort orders documents by ascending distance from the location. The value returned in {@link FieldDoc} for * the hits contains a Double instance with the distance in meters. @@ -264,14 +266,14 @@ public class Geo3DDocValuesField extends Field { * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY} distance * (missing values sort last). *
- * If a document contains multiple values for the field, the closest distance to the location is used. + * If a document contains multiple values for the field, the closest distance from the circle center is used. * * @param field field name. must not be null. * @param latitude latitude at the center: must be within standard +/-90 coordinate bounds. * @param longitude longitude at the center: must be within standard +/-180 coordinate bounds. * @param maxRadiusMeters is the maximum radius in meters. * @return SortField ordering documents by distance - * @throws IllegalArgumentException if {@code field} is null or location has invalid coordinates. + * @throws IllegalArgumentException if {@code field} is null or circle has invalid coordinates. */ public static SortField newDistanceSort(final String field, final double latitude, final double longitude, final double maxRadiusMeters) { final GeoDistanceShape shape = Geo3DUtil.fromDistance(latitude, longitude, maxRadiusMeters); @@ -287,18 +289,138 @@ public class Geo3DDocValuesField extends Field { * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY} distance * (missing values sort last). *
- * If a document contains multiple values for the field, the closest distance to the location is used. + * If a document contains multiple values for the field, the closest distance along the path is used. * * @param field field name. must not be null. * @param pathLatitudes latitude values for points of the path: must be within standard +/-90 coordinate bounds. * @param pathLongitudes longitude values for points of the path: must be within standard +/-180 coordinate bounds. * @param pathWidthMeters width of the path in meters. * @return SortField ordering documents by distance - * @throws IllegalArgumentException if {@code field} is null or location has invalid coordinates. + * @throws IllegalArgumentException if {@code field} is null or path has invalid coordinates. */ public static SortField newPathSort(final String field, final double[] pathLatitudes, final double[] pathLongitudes, final double pathWidthMeters) { final GeoDistanceShape shape = Geo3DUtil.fromPath(pathLatitudes, pathLongitudes, pathWidthMeters); return new Geo3DPointSortField(field, shape); } + // Outside distances + + /** + * Creates a SortField for sorting by outside distance from a circle. + *
+ * This sort orders documents by ascending outside distance from the circle. Points within the circle have distance 0.0. + * The value returned in {@link FieldDoc} for + * the hits contains a Double instance with the distance in meters. + *
+ * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY} distance + * (missing values sort last). + *
+ * If a document contains multiple values for the field, the closest distance to the circle is used. + * + * @param field field name. must not be null. + * @param latitude latitude at the center: must be within standard +/-90 coordinate bounds. + * @param longitude longitude at the center: must be within standard +/-180 coordinate bounds. + * @param maxRadiusMeters is the maximum radius in meters. + * @return SortField ordering documents by distance + * @throws IllegalArgumentException if {@code field} is null or location has invalid coordinates. + */ + public static SortField newOutsideDistanceSort(final String field, final double latitude, final double longitude, final double maxRadiusMeters) { + final GeoOutsideDistance shape = Geo3DUtil.fromDistance(latitude, longitude, maxRadiusMeters); + return new Geo3DPointOutsideSortField(field, shape); + } + + /** + * Creates a SortField for sorting by outside distance from a box. + *
+ * This sort orders documents by ascending outside distance from the box. Points within the box have distance 0.0. + * The value returned in {@link FieldDoc} for + * the hits contains a Double instance with the distance in meters. + *
+ * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY} distance + * (missing values sort last). + *
+ * If a document contains multiple values for the field, the closest distance to the box is used. + * + * @param field field name. must not be null. + * @param minLatitude latitude lower bound: must be within standard +/-90 coordinate bounds. + * @param maxLatitude latitude upper bound: must be within standard +/-90 coordinate bounds. + * @param minLongitude longitude lower bound: must be within standard +/-180 coordinate bounds. + * @param maxLongitude longitude upper bound: must be within standard +/-180 coordinate bounds. + * @return SortField ordering documents by distance + * @throws IllegalArgumentException if {@code field} is null or box has invalid coordinates. + */ + public static SortField newOutsideBoxSort(final String field, final double minLatitude, final double maxLatitude, final double minLongitude, final double maxLongitude) { + final GeoOutsideDistance shape = Geo3DUtil.fromBox(minLatitude, maxLatitude, minLongitude, maxLongitude); + return new Geo3DPointOutsideSortField(field, shape); + } + + /** + * Creates a SortField for sorting by outside distance from a polygon. + *
+ * This sort orders documents by ascending outside distance from the polygon. Points within the polygon have distance 0.0. + * The value returned in {@link FieldDoc} for + * the hits contains a Double instance with the distance in meters. + *
+ * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY} distance + * (missing values sort last). + *
+ * If a document contains multiple values for the field, the closest distance to the polygon is used. + * + * @param field field name. must not be null. + * @param polygons is the list of polygons to use to construct the query; must be at least one. + * @return SortField ordering documents by distance + * @throws IllegalArgumentException if {@code field} is null or polygon has invalid coordinates. + */ + public static SortField newOutsidePolygonSort(final String field, final Polygon... polygons) { + final GeoOutsideDistance shape = Geo3DUtil.fromPolygon(polygons); + return new Geo3DPointOutsideSortField(field, shape); + } + + /** + * Creates a SortField for sorting by outside distance from a large polygon. This differs from the related newOutsideLargePolygonSort in that it + * does little or no legality checking and is optimized for very large numbers of polygon edges. + *
+ * This sort orders documents by ascending outside distance from the polygon. Points within the polygon have distance 0.0. + * The value returned in {@link FieldDoc} for + * the hits contains a Double instance with the distance in meters. + *
+ * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY} distance + * (missing values sort last). + *
+ * If a document contains multiple values for the field, the closest distance to the polygon is used. + * + * @param field field name. must not be null. + * @param polygons is the list of polygons to use to construct the query; must be at least one. + * @return SortField ordering documents by distance + * @throws IllegalArgumentException if {@code field} is null or polygon has invalid coordinates. + */ + public static SortField newOutsideLargePolygonSort(final String field, final Polygon... polygons) { + final GeoOutsideDistance shape = Geo3DUtil.fromLargePolygon(polygons); + return new Geo3DPointOutsideSortField(field, shape); + } + + /** + * Creates a SortField for sorting by outside distance from a path. + *
+ * This sort orders documents by ascending outside distance from the described path. Points within the path + * are given the distance of 0.0. The value returned in {@link FieldDoc} for + * the hits contains a Double instance with the distance in meters. + *
+ * If a document is missing the field, then by default it is treated as having {@link Double#POSITIVE_INFINITY} distance + * (missing values sort last). + *
+ * If a document contains multiple values for the field, the closest distance from the path is used.
+ *
+ * @param field field name. must not be null.
+ * @param pathLatitudes latitude values for points of the path: must be within standard +/-90 coordinate bounds.
+ * @param pathLongitudes longitude values for points of the path: must be within standard +/-180 coordinate bounds.
+ * @param pathWidthMeters width of the path in meters.
+ * @return SortField ordering documents by distance
+ * @throws IllegalArgumentException if {@code field} is null or path has invalid coordinates.
+ */
+ public static SortField newOutsidePathSort(final String field, final double[] pathLatitudes, final double[] pathLongitudes, final double pathWidthMeters) {
+ final GeoOutsideDistance shape = Geo3DUtil.fromPath(pathLatitudes, pathLongitudes, pathWidthMeters);
+ return new Geo3DPointOutsideSortField(field, shape);
+ }
+
}
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
index 2ff1286d434..15426e68952 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
@@ -129,9 +129,6 @@ public final class Geo3DPoint extends Field {
* @return query matching points within this polygon
*/
public static Query newLargePolygonQuery(final String field, final Polygon... polygons) {
- if (polygons.length < 1) {
- throw new IllegalArgumentException("need at least one polygon");
- }
final GeoShape shape = Geo3DUtil.fromLargePolygon(polygons);
return newShapeQuery(field, shape);
}
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideDistanceComparator.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideDistanceComparator.java
new file mode 100644
index 00000000000..10e001066f6
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideDistanceComparator.java
@@ -0,0 +1,137 @@
+/*
+ * 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.spatial3d;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.FieldInfo;
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SortedNumericDocValues;
+import org.apache.lucene.search.FieldComparator;
+import org.apache.lucene.search.LeafFieldComparator;
+import org.apache.lucene.search.Scorer;
+
+import org.apache.lucene.spatial3d.geom.GeoOutsideDistance;
+import org.apache.lucene.spatial3d.geom.DistanceStyle;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
+
+/**
+ * Compares documents by outside distance, using a GeoOutsideDistance to compute the distance
+ */
+class Geo3DPointOutsideDistanceComparator extends FieldComparator