mirror of https://github.com/apache/lucene.git
LUCENE-7173: Bring polygon API into compliance with 2D version.
This commit is contained in:
parent
9bef6c000b
commit
7289bc36f6
|
@ -22,6 +22,8 @@ import java.util.ArrayList;
|
|||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.FieldType;
|
||||
import org.apache.lucene.index.PointValues;
|
||||
import org.apache.lucene.geo.Polygon;
|
||||
import org.apache.lucene.geo.GeoUtils;
|
||||
import org.apache.lucene.spatial3d.geom.Vector;
|
||||
import org.apache.lucene.spatial3d.geom.GeoPoint;
|
||||
import org.apache.lucene.spatial3d.geom.GeoShape;
|
||||
|
@ -30,6 +32,8 @@ import org.apache.lucene.spatial3d.geom.GeoCircleFactory;
|
|||
import org.apache.lucene.spatial3d.geom.GeoBBoxFactory;
|
||||
import org.apache.lucene.spatial3d.geom.GeoPolygonFactory;
|
||||
import org.apache.lucene.spatial3d.geom.GeoPath;
|
||||
import org.apache.lucene.spatial3d.geom.GeoCompositePolygon;
|
||||
import org.apache.lucene.spatial3d.geom.GeoPolygon;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.NumericUtils;
|
||||
|
@ -64,8 +68,8 @@ public final class Geo3DPoint extends Field {
|
|||
*/
|
||||
public Geo3DPoint(String name, double latitude, double longitude) {
|
||||
super(name, TYPE);
|
||||
checkLatitude(latitude);
|
||||
checkLongitude(longitude);
|
||||
GeoUtils.checkLatitude(latitude);
|
||||
GeoUtils.checkLongitude(longitude);
|
||||
// Translate latitude/longitude to x,y,z:
|
||||
final GeoPoint point = new GeoPoint(PlanetModel.WGS84, fromDegrees(latitude), fromDegrees(longitude));
|
||||
fillFieldsData(point.x, point.y, point.z);
|
||||
|
@ -94,8 +98,8 @@ public final class Geo3DPoint extends Field {
|
|||
* @throws IllegalArgumentException if {@code field} is null, location has invalid coordinates, or radius is invalid.
|
||||
*/
|
||||
public static Query newDistanceQuery(final String field, final double latitude, final double longitude, final double radiusMeters) {
|
||||
checkLatitude(latitude);
|
||||
checkLongitude(longitude);
|
||||
GeoUtils.checkLatitude(latitude);
|
||||
GeoUtils.checkLongitude(longitude);
|
||||
final GeoShape shape = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, fromDegrees(latitude), fromDegrees(longitude), fromMeters(radiusMeters));
|
||||
return newShapeQuery(field, shape);
|
||||
}
|
||||
|
@ -113,10 +117,10 @@ public final class Geo3DPoint extends Field {
|
|||
* @throws IllegalArgumentException if {@code field} is null, or the box has invalid coordinates.
|
||||
*/
|
||||
public static Query newBoxQuery(final String field, final double minLatitude, final double maxLatitude, final double minLongitude, final double maxLongitude) {
|
||||
checkLatitude(minLatitude);
|
||||
checkLongitude(minLongitude);
|
||||
checkLatitude(maxLatitude);
|
||||
checkLongitude(maxLongitude);
|
||||
GeoUtils.checkLatitude(minLatitude);
|
||||
GeoUtils.checkLongitude(minLongitude);
|
||||
GeoUtils.checkLatitude(maxLatitude);
|
||||
GeoUtils.checkLongitude(maxLongitude);
|
||||
final GeoShape shape = GeoBBoxFactory.makeGeoBBox(PlanetModel.WGS84,
|
||||
fromDegrees(maxLatitude), fromDegrees(minLatitude), fromDegrees(minLongitude), fromDegrees(maxLongitude));
|
||||
return newShapeQuery(field, shape);
|
||||
|
@ -125,36 +129,28 @@ public final class Geo3DPoint extends Field {
|
|||
/**
|
||||
* Create a query for matching a polygon.
|
||||
* <p>
|
||||
* The supplied {@code polyLatitudes}/{@code polyLongitudes} must be clockwise or counter-clockwise.
|
||||
* The supplied {@code polygons} must be clockwise on the outside level, counterclockwise on the next level in, etc.
|
||||
* @param field field name. must not be null.
|
||||
* @param polyLatitudes latitude values for points of the polygon: must be within standard +/-90 coordinate bounds.
|
||||
* @param polyLongitudes longitude values for points of the polygon: must be within standard +/-180 coordinate bounds.
|
||||
* @param polygons is the list of polygons to use to construct the query; must be at least one.
|
||||
* @return query matching points within this polygon
|
||||
*/
|
||||
public static Query newPolygonQuery(final String field, final double[] polyLatitudes, final double[] polyLongitudes) {
|
||||
if (polyLatitudes.length != polyLongitudes.length) {
|
||||
throw new IllegalArgumentException("same number of latitudes and longitudes required");
|
||||
public static Query newPolygonQuery(final String field, final Polygon... polygons) {
|
||||
if (polygons.length < 1) {
|
||||
throw new IllegalArgumentException("need at least one polygon");
|
||||
}
|
||||
if (polyLatitudes.length < 4) {
|
||||
throw new IllegalArgumentException("need three or more points");
|
||||
final GeoShape shape;
|
||||
if (polygons.length == 1) {
|
||||
shape = fromPolygon(polygons[0], false);
|
||||
} else {
|
||||
final GeoCompositePolygon poly = new GeoCompositePolygon();
|
||||
for (final Polygon p : polygons) {
|
||||
poly.addShape(fromPolygon(p, false));
|
||||
}
|
||||
shape = poly;
|
||||
}
|
||||
if (polyLatitudes[0] != polyLatitudes[polyLatitudes.length-1] || polyLongitudes[0] != polyLongitudes[polyLongitudes.length-1]) {
|
||||
throw new IllegalArgumentException("last point must equal first point");
|
||||
}
|
||||
|
||||
final List<GeoPoint> polyPoints = new ArrayList<>(polyLatitudes.length-1);
|
||||
for (int i = 0; i < polyLatitudes.length-1; i++) {
|
||||
final double latitude = polyLatitudes[i];
|
||||
final double longitude = polyLongitudes[i];
|
||||
checkLatitude(latitude);
|
||||
checkLongitude(longitude);
|
||||
polyPoints.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(latitude), fromDegrees(longitude)));
|
||||
}
|
||||
// We use the polygon constructor that looks at point order.
|
||||
final GeoShape shape = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, polyPoints, null);
|
||||
return newShapeQuery(field, shape);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a query for matching a path.
|
||||
* <p>
|
||||
|
@ -172,14 +168,47 @@ public final class Geo3DPoint extends Field {
|
|||
for (int i = 0; i < pathLatitudes.length; i++) {
|
||||
final double latitude = pathLatitudes[i];
|
||||
final double longitude = pathLongitudes[i];
|
||||
checkLatitude(latitude);
|
||||
checkLongitude(longitude);
|
||||
GeoUtils.checkLatitude(latitude);
|
||||
GeoUtils.checkLongitude(longitude);
|
||||
points[i] = new GeoPoint(PlanetModel.WGS84, fromDegrees(latitude), fromDegrees(longitude));
|
||||
}
|
||||
final GeoShape shape = new GeoPath(PlanetModel.WGS84, fromMeters(pathWidthMeters), points);
|
||||
return newShapeQuery(field, shape);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Polygon object into a GeoPolygon.
|
||||
* This method uses
|
||||
* @param polygon is the Polygon object.
|
||||
* @param reverseMe is true if the order of the points should be reversed.
|
||||
* @return the GeoPolygon.
|
||||
*/
|
||||
protected static GeoPolygon fromPolygon(final Polygon polygon, final boolean reverseMe) {
|
||||
// First, assemble the "holes". The geo3d convention is to use the same polygon sense on the inner ring as the
|
||||
// outer ring, so we process these recursively with reverseMe flipped.
|
||||
final Polygon[] theHoles = polygon.getHoles();
|
||||
final List<GeoPolygon> holeList = new ArrayList<>(theHoles.length);
|
||||
for (final Polygon hole : theHoles) {
|
||||
holeList.add(fromPolygon(hole, !reverseMe));
|
||||
}
|
||||
// Now do the polygon itself
|
||||
final double[] polyLats = polygon.getPolyLats();
|
||||
final double[] polyLons = polygon.getPolyLons();
|
||||
|
||||
// I presume the arguments have already been checked
|
||||
final List<GeoPoint> points = new ArrayList<>(polyLats.length-1);
|
||||
// We skip the last point anyway because the API requires it to be repeated, and geo3d doesn't repeat it.
|
||||
for (int i = 0; i < polyLats.length - 1; i++) {
|
||||
if (reverseMe) {
|
||||
points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[i]), fromDegrees(polyLons[i])));
|
||||
} else {
|
||||
final int index = polyLats.length - 2 - i;
|
||||
points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[index]), fromDegrees(polyLons[index])));
|
||||
}
|
||||
}
|
||||
return GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, points, holeList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Geo3DPoint field with the specified x,y,z.
|
||||
*
|
||||
|
@ -235,31 +264,4 @@ public final class Geo3DPoint extends Field {
|
|||
return result.toString();
|
||||
}
|
||||
|
||||
// TODO LUCENE-7152: share this with GeoUtils.java from spatial module
|
||||
|
||||
/** Minimum longitude value. */
|
||||
private static final double MIN_LON_INCL = -180.0D;
|
||||
|
||||
/** Maximum longitude value. */
|
||||
private static final double MAX_LON_INCL = 180.0D;
|
||||
|
||||
/** Minimum latitude value. */
|
||||
private static final double MIN_LAT_INCL = -90.0D;
|
||||
|
||||
/** Maximum latitude value. */
|
||||
private static final double MAX_LAT_INCL = 90.0D;
|
||||
|
||||
/** validates latitude value is within standard +/-90 coordinate bounds */
|
||||
private static void checkLatitude(double latitude) {
|
||||
if (Double.isNaN(latitude) || latitude < MIN_LAT_INCL || latitude > MAX_LAT_INCL) {
|
||||
throw new IllegalArgumentException("invalid latitude " + latitude + "; must be between " + MIN_LAT_INCL + " and " + MAX_LAT_INCL);
|
||||
}
|
||||
}
|
||||
|
||||
/** validates longitude value is within standard +/-180 coordinate bounds */
|
||||
private static void checkLongitude(double longitude) {
|
||||
if (Double.isNaN(longitude) || longitude < MIN_LON_INCL || longitude > MAX_LON_INCL) {
|
||||
throw new IllegalArgumentException("invalid longitude " + longitude + "; must be between " + MIN_LON_INCL + " and " + MAX_LON_INCL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue