Geo: replace intermediate geo objects with libs/geo (#37721)

Replaces intermediate geo objects built by ShapeBuilders with
objects from the libs/geo hierarchy. This should allow us to build
all geo functionality around a single hierarchy.

Follow up for #35320
This commit is contained in:
Igor Motov 2019-01-25 11:37:27 -05:00 committed by GitHub
parent e88ae99340
commit 68149b6058
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 465 additions and 365 deletions

View File

@ -212,6 +212,7 @@ allprojects {
"org.elasticsearch:elasticsearch-core:${version}": ':libs:core',
"org.elasticsearch:elasticsearch-nio:${version}": ':libs:nio',
"org.elasticsearch:elasticsearch-x-content:${version}": ':libs:x-content',
"org.elasticsearch:elasticsearch-geo:${version}": ':libs:elasticsearch-geo',
"org.elasticsearch:elasticsearch-secure-sm:${version}": ':libs:secure-sm',
"org.elasticsearch.client:elasticsearch-rest-client:${version}": ':client:rest',
"org.elasticsearch.client:elasticsearch-rest-client-sniffer:${version}": ':client:sniffer',

View File

@ -67,6 +67,14 @@ public class Line implements Geometry {
return lons[i];
}
public double[] getLats() {
return lats.clone();
}
public double[] getLons() {
return lons.clone();
}
@Override
public ShapeType type() {
return ShapeType.LINESTRING;

View File

@ -48,11 +48,11 @@ public class Point implements Geometry {
return ShapeType.POINT;
}
public double lat() {
public double getLat() {
return lat;
}
public double lon() {
public double getLon() {
return lon;
}

View File

@ -123,12 +123,12 @@ public class WellKnownText {
public Void visit(MultiPoint multiPoint) {
// walk through coordinates:
sb.append(LPAREN);
visitPoint(multiPoint.get(0).lon(), multiPoint.get(0).lat());
visitPoint(multiPoint.get(0).getLon(), multiPoint.get(0).getLat());
for (int i = 1; i < multiPoint.size(); ++i) {
sb.append(COMMA);
sb.append(SPACE);
Point point = multiPoint.get(i);
visitPoint(point.lon(), point.lat());
visitPoint(point.getLon(), point.getLat());
}
sb.append(RPAREN);
return null;
@ -146,7 +146,7 @@ public class WellKnownText {
sb.append(EMPTY);
} else {
sb.append(LPAREN);
visitPoint(point.lon(), point.lat());
visitPoint(point.getLon(), point.getLat());
sb.append(RPAREN);
}
return null;

View File

@ -77,7 +77,8 @@ dependencies {
compile "org.elasticsearch:elasticsearch-core:${version}"
compile "org.elasticsearch:elasticsearch-secure-sm:${version}"
compile "org.elasticsearch:elasticsearch-x-content:${version}"
compile "org.elasticsearch:elasticsearch-geo:${version}"
compileOnly project(':libs:plugin-classloader')
testRuntime project(':libs:plugin-classloader')

View File

@ -258,7 +258,7 @@ public enum GeoShapeType {
},
GEOMETRYCOLLECTION("geometrycollection") {
@Override
public ShapeBuilder<?, ?> getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
public ShapeBuilder<?, ?, ?> getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
Orientation orientation, boolean coerce) {
// noop, handled in parser
return null;
@ -298,7 +298,7 @@ public enum GeoShapeType {
throw new IllegalArgumentException("unknown geo_shape ["+geoshapename+"]");
}
public abstract ShapeBuilder<?, ?> getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
public abstract ShapeBuilder<?, ?, ?> getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
ShapeBuilder.Orientation orientation, boolean coerce);
abstract CoordinateNode validate(CoordinateNode coordinates, boolean coerce);

View File

@ -34,7 +34,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.Objects;
public class CircleBuilder extends ShapeBuilder<Circle, CircleBuilder> {
public class CircleBuilder extends ShapeBuilder<Circle, org.elasticsearch.geo.geometry.Circle, CircleBuilder> {
public static final ParseField FIELD_RADIUS = new ParseField("radius");
public static final GeoShapeType TYPE = GeoShapeType.CIRCLE;
@ -164,7 +164,7 @@ public class CircleBuilder extends ShapeBuilder<Circle, CircleBuilder> {
}
@Override
public Object buildLucene() {
public org.elasticsearch.geo.geometry.Circle buildGeometry() {
throw new UnsupportedOperationException("CIRCLE geometry is not supported");
}

View File

@ -32,7 +32,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.Objects;
public class EnvelopeBuilder extends ShapeBuilder<Rectangle, EnvelopeBuilder> {
public class EnvelopeBuilder extends ShapeBuilder<Rectangle, org.elasticsearch.geo.geometry.Rectangle, EnvelopeBuilder> {
public static final GeoShapeType TYPE = GeoShapeType.ENVELOPE;
@ -113,8 +113,8 @@ public class EnvelopeBuilder extends ShapeBuilder<Rectangle, EnvelopeBuilder> {
}
@Override
public org.apache.lucene.geo.Rectangle buildLucene() {
return new org.apache.lucene.geo.Rectangle(bottomRight.y, topLeft.y, topLeft.x, bottomRight.x);
public org.elasticsearch.geo.geometry.Rectangle buildGeometry() {
return new org.elasticsearch.geo.geometry.Rectangle(bottomRight.y, topLeft.y, topLeft.x, bottomRight.x);
}
@Override

View File

@ -31,11 +31,11 @@ import org.locationtech.spatial4j.shape.Shape;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
public class GeometryCollectionBuilder extends ShapeBuilder<Shape, GeometryCollectionBuilder> {
public class GeometryCollectionBuilder extends ShapeBuilder<Shape,
org.elasticsearch.geo.geometry.GeometryCollection<org.elasticsearch.geo.geometry.Geometry>, GeometryCollectionBuilder> {
public static final GeoShapeType TYPE = GeoShapeType.GEOMETRYCOLLECTION;
@ -185,19 +185,14 @@ public class GeometryCollectionBuilder extends ShapeBuilder<Shape, GeometryColle
}
@Override
public Object buildLucene() {
List<Object> shapes = new ArrayList<>(this.shapes.size());
public org.elasticsearch.geo.geometry.GeometryCollection<org.elasticsearch.geo.geometry.Geometry> buildGeometry() {
List<org.elasticsearch.geo.geometry.Geometry> shapes = new ArrayList<>(this.shapes.size());
for (ShapeBuilder shape : this.shapes) {
Object o = shape.buildLucene();
if (o.getClass().isArray()) {
shapes.addAll(Arrays.asList((Object[])o));
} else {
shapes.add(o);
}
shapes.add(shape.buildGeometry());
}
return shapes.toArray(new Object[shapes.size()]);
return new org.elasticsearch.geo.geometry.GeometryCollection<>(shapes);
}
@Override

View File

@ -19,16 +19,16 @@
package org.elasticsearch.common.geo.builders;
import org.apache.lucene.geo.Line;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.elasticsearch.common.geo.GeoShapeType;
import org.elasticsearch.common.geo.parsers.ShapeParser;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.geo.geometry.Line;
import org.elasticsearch.geo.geometry.MultiLine;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.locationtech.spatial4j.shape.jts.JtsGeometry;
import java.io.IOException;
@ -39,7 +39,7 @@ import java.util.List;
import static org.elasticsearch.common.geo.GeoUtils.normalizeLat;
import static org.elasticsearch.common.geo.GeoUtils.normalizeLon;
public class LineStringBuilder extends ShapeBuilder<JtsGeometry, LineStringBuilder> {
public class LineStringBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.geo.geometry.Geometry, LineStringBuilder> {
public static final GeoShapeType TYPE = GeoShapeType.LINESTRING;
/**
@ -125,15 +125,15 @@ public class LineStringBuilder extends ShapeBuilder<JtsGeometry, LineStringBuild
}
@Override
public Object buildLucene() {
public org.elasticsearch.geo.geometry.Geometry buildGeometry() {
// decompose linestrings crossing dateline into array of Lines
Coordinate[] coordinates = this.coordinates.toArray(new Coordinate[this.coordinates.size()]);
if (wrapdateline) {
ArrayList<Line> linestrings = decomposeLucene(coordinates, new ArrayList<>());
List<Line> linestrings = decomposeGeometry(coordinates, new ArrayList<>());
if (linestrings.size() == 1) {
return linestrings.get(0);
} else {
return linestrings.toArray(new Line[linestrings.size()]);
return new MultiLine(linestrings);
}
}
return new Line(Arrays.stream(coordinates).mapToDouble(i->normalizeLat(i.y)).toArray(),
@ -149,7 +149,7 @@ public class LineStringBuilder extends ShapeBuilder<JtsGeometry, LineStringBuild
return strings;
}
static ArrayList<Line> decomposeLucene(Coordinate[] coordinates, ArrayList<Line> lines) {
static List<Line> decomposeGeometry(Coordinate[] coordinates, List<Line> lines) {
for (Coordinate[] part : decompose(+DATELINE, coordinates)) {
for (Coordinate[] line : decompose(-DATELINE, part)) {
lines.add(new Line(Arrays.stream(line).mapToDouble(i->normalizeLat(i.y)).toArray(),

View File

@ -19,25 +19,25 @@
package org.elasticsearch.common.geo.builders;
import org.apache.lucene.geo.Line;
import org.elasticsearch.common.geo.GeoShapeType;
import org.elasticsearch.common.geo.parsers.GeoWKTParser;
import org.elasticsearch.common.geo.parsers.ShapeParser;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.geo.geometry.MultiLine;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;
import org.locationtech.spatial4j.shape.jts.JtsGeometry;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
public class MultiLineStringBuilder extends ShapeBuilder<JtsGeometry, MultiLineStringBuilder> {
public class MultiLineStringBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.geo.geometry.Geometry, MultiLineStringBuilder> {
public static final GeoShapeType TYPE = GeoShapeType.MULTILINESTRING;
@ -150,24 +150,24 @@ public class MultiLineStringBuilder extends ShapeBuilder<JtsGeometry, MultiLineS
}
@Override
public Object buildLucene() {
public org.elasticsearch.geo.geometry.Geometry buildGeometry() {
if (wrapdateline) {
ArrayList<Line> parts = new ArrayList<>();
List<org.elasticsearch.geo.geometry.Line> parts = new ArrayList<>();
for (LineStringBuilder line : lines) {
LineStringBuilder.decomposeLucene(line.coordinates(false), parts);
LineStringBuilder.decomposeGeometry(line.coordinates(false), parts);
}
if (parts.size() == 1) {
return parts.get(0);
}
return parts.toArray(new Line[parts.size()]);
return new MultiLine(parts);
}
Line[] linestrings = new Line[lines.size()];
List<org.elasticsearch.geo.geometry.Line> linestrings = new ArrayList<>(lines.size());
for (int i = 0; i < lines.size(); ++i) {
LineStringBuilder lsb = lines.get(i);
linestrings[i] = new Line(lsb.coordinates.stream().mapToDouble(c->c.y).toArray(),
lsb.coordinates.stream().mapToDouble(c->c.x).toArray());
linestrings.add(new org.elasticsearch.geo.geometry.Line(lsb.coordinates.stream().mapToDouble(c->c.y).toArray(),
lsb.coordinates.stream().mapToDouble(c->c.x).toArray()));
}
return linestrings;
return new MultiLine(linestrings);
}
@Override

View File

@ -24,14 +24,16 @@ import org.elasticsearch.common.geo.XShapeCollection;
import org.elasticsearch.common.geo.parsers.ShapeParser;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.geo.geometry.MultiPoint;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.spatial4j.shape.Point;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class MultiPointBuilder extends ShapeBuilder<XShapeCollection<Point>, MultiPointBuilder> {
public class MultiPointBuilder extends ShapeBuilder<XShapeCollection<Point>, MultiPoint, MultiPointBuilder> {
public static final GeoShapeType TYPE = GeoShapeType.MULTIPOINT;
@ -74,14 +76,9 @@ public class MultiPointBuilder extends ShapeBuilder<XShapeCollection<Point>, Mul
}
@Override
public double[][] buildLucene() {
double[][] points = new double[coordinates.size()][];
Coordinate coord;
for (int i = 0; i < coordinates.size(); ++i) {
coord = coordinates.get(i);
points[i] = new double[] {coord.x, coord.y};
}
return points;
public MultiPoint buildGeometry() {
return new MultiPoint(coordinates.stream().map(coord -> new org.elasticsearch.geo.geometry.Point(coord.y, coord.x))
.collect(Collectors.toList()));
}
@Override

View File

@ -26,17 +26,17 @@ import org.elasticsearch.common.geo.parsers.ShapeParser;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.geo.geometry.MultiPolygon;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.spatial4j.shape.Shape;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
public class MultiPolygonBuilder extends ShapeBuilder<Shape, MultiPolygonBuilder> {
public class MultiPolygonBuilder extends ShapeBuilder<Shape, MultiPolygon, MultiPolygonBuilder> {
public static final GeoShapeType TYPE = GeoShapeType.MULTIPOLYGON;
@ -185,31 +185,20 @@ public class MultiPolygonBuilder extends ShapeBuilder<Shape, MultiPolygonBuilder
//note: ShapeCollection is probably faster than a Multi* geom.
}
@SuppressWarnings({"unchecked"})
@Override
public Object buildLucene() {
List<org.apache.lucene.geo.Polygon> shapes = new ArrayList<>(this.polygons.size());
public MultiPolygon buildGeometry() {
List<org.elasticsearch.geo.geometry.Polygon> shapes = new ArrayList<>(this.polygons.size());
Object poly;
if (wrapdateline) {
for (PolygonBuilder polygon : this.polygons) {
poly = polygon.buildLucene();
if (poly instanceof org.apache.lucene.geo.Polygon[]) {
shapes.addAll(Arrays.asList((org.apache.lucene.geo.Polygon[])poly));
} else {
shapes.add((org.apache.lucene.geo.Polygon)poly);
}
}
} else {
for (int i = 0; i < this.polygons.size(); ++i) {
PolygonBuilder pb = this.polygons.get(i);
poly = pb.buildLucene();
if (poly instanceof org.apache.lucene.geo.Polygon[]) {
shapes.addAll(Arrays.asList((org.apache.lucene.geo.Polygon[])poly));
} else {
shapes.add((org.apache.lucene.geo.Polygon)poly);
}
for (PolygonBuilder polygon : this.polygons) {
poly = polygon.buildGeometry();
if (poly instanceof List) {
shapes.addAll((List<org.elasticsearch.geo.geometry.Polygon>) poly);
} else {
shapes.add((org.elasticsearch.geo.geometry.Polygon)poly);
}
}
return shapes.stream().toArray(org.apache.lucene.geo.Polygon[]::new);
return new MultiPolygon(shapes);
}
@Override

View File

@ -19,18 +19,16 @@
package org.elasticsearch.common.geo.builders;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.GeoShapeType;
import org.elasticsearch.common.geo.parsers.ShapeParser;
import org.locationtech.spatial4j.shape.Point;
import org.locationtech.jts.geom.Coordinate;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.spatial4j.shape.Point;
import java.io.IOException;
public class PointBuilder extends ShapeBuilder<Point, PointBuilder> {
public class PointBuilder extends ShapeBuilder<Point, org.elasticsearch.geo.geometry.Point, PointBuilder> {
public static final GeoShapeType TYPE = GeoShapeType.POINT;
/**
@ -90,8 +88,8 @@ public class PointBuilder extends ShapeBuilder<Point, PointBuilder> {
}
@Override
public GeoPoint buildLucene() {
return new GeoPoint(coordinates.get(0).y, coordinates.get(0).x);
public org.elasticsearch.geo.geometry.Point buildGeometry() {
return new org.elasticsearch.geo.geometry.Point(coordinates.get(0).y, coordinates.get(0).x);
}
@Override

View File

@ -38,6 +38,7 @@ import org.locationtech.spatial4j.shape.jts.JtsGeometry;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -55,7 +56,7 @@ import static org.apache.lucene.geo.GeoUtils.orient;
* Methods to wrap polygons at the dateline and building shapes from the data held by the
* builder.
*/
public class PolygonBuilder extends ShapeBuilder<JtsGeometry, PolygonBuilder> {
public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.geo.geometry.Geometry, PolygonBuilder> {
public static final GeoShapeType TYPE = GeoShapeType.POLYGON;
@ -233,14 +234,14 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, PolygonBuilder> {
}
@Override
public Object buildLucene() {
public org.elasticsearch.geo.geometry.Geometry buildGeometry() {
if (wrapdateline) {
Coordinate[][][] polygons = coordinates();
return polygons.length == 1
? polygonLucene(polygons[0])
: multipolygonLucene(polygons);
? polygonGeometry(polygons[0])
: multipolygon(polygons);
}
return toPolygonLucene();
return toPolygonGeometry();
}
protected XContentBuilder coordinatesArray(XContentBuilder builder, Params params) throws IOException {
@ -288,17 +289,19 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, PolygonBuilder> {
return factory.createPolygon(shell, holes);
}
public Object toPolygonLucene() {
final org.apache.lucene.geo.Polygon[] holes = new org.apache.lucene.geo.Polygon[this.holes.size()];
for (int i = 0; i < holes.length; ++i) {
holes[i] = linearRing(this.holes.get(i).coordinates);
public org.elasticsearch.geo.geometry.Polygon toPolygonGeometry() {
final List<org.elasticsearch.geo.geometry.LinearRing> holes = new ArrayList<>(this.holes.size());
for (int i = 0; i < this.holes.size(); ++i) {
holes.add(linearRing(this.holes.get(i).coordinates));
}
return new org.apache.lucene.geo.Polygon(this.shell.coordinates.stream().mapToDouble(i -> normalizeLat(i.y)).toArray(),
this.shell.coordinates.stream().mapToDouble(i -> normalizeLon(i.x)).toArray(), holes);
return new org.elasticsearch.geo.geometry.Polygon(
new org.elasticsearch.geo.geometry.LinearRing(
this.shell.coordinates.stream().mapToDouble(i -> normalizeLat(i.y)).toArray(),
this.shell.coordinates.stream().mapToDouble(i -> normalizeLon(i.x)).toArray()), holes);
}
protected static org.apache.lucene.geo.Polygon linearRing(List<Coordinate> coordinates) {
return new org.apache.lucene.geo.Polygon(coordinates.stream().mapToDouble(i -> normalizeLat(i.y)).toArray(),
protected static org.elasticsearch.geo.geometry.LinearRing linearRing(List<Coordinate> coordinates) {
return new org.elasticsearch.geo.geometry.LinearRing(coordinates.stream().mapToDouble(i -> normalizeLat(i.y)).toArray(),
coordinates.stream().mapToDouble(i -> normalizeLon(i.x)).toArray());
}
@ -335,13 +338,13 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, PolygonBuilder> {
return factory.createPolygon(shell, holes);
}
protected static org.apache.lucene.geo.Polygon polygonLucene(Coordinate[][] polygon) {
org.apache.lucene.geo.Polygon[] holes;
protected static org.elasticsearch.geo.geometry.Polygon polygonGeometry(Coordinate[][] polygon) {
List<org.elasticsearch.geo.geometry.LinearRing> holes;
Coordinate[] shell = polygon[0];
if (polygon.length > 1) {
holes = new org.apache.lucene.geo.Polygon[polygon.length - 1];
for (int i = 0; i < holes.length; ++i) {
Coordinate[] coords = polygon[i+1];
holes = new ArrayList<>(polygon.length - 1);
for (int i = 1; i < polygon.length; ++i) {
Coordinate[] coords = polygon[i];
//We do not have holes on the dateline as they get eliminated
//when breaking the polygon around it.
double[] x = new double[coords.length];
@ -350,10 +353,10 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, PolygonBuilder> {
x[c] = normalizeLon(coords[c].x);
y[c] = normalizeLat(coords[c].y);
}
holes[i] = new org.apache.lucene.geo.Polygon(y, x);
holes.add(new org.elasticsearch.geo.geometry.LinearRing(y, x));
}
} else {
holes = new org.apache.lucene.geo.Polygon[0];
holes = Collections.emptyList();
}
double[] x = new double[shell.length];
@ -365,7 +368,7 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, PolygonBuilder> {
y[i] = normalizeLat(shell[i].y);
}
return new org.apache.lucene.geo.Polygon(y, x, holes);
return new org.elasticsearch.geo.geometry.Polygon(new org.elasticsearch.geo.geometry.LinearRing(y, x), holes);
}
/**
@ -386,12 +389,12 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, PolygonBuilder> {
return factory.createMultiPolygon(polygonSet);
}
protected static org.apache.lucene.geo.Polygon[] multipolygonLucene(Coordinate[][][] polygons) {
org.apache.lucene.geo.Polygon[] polygonSet = new org.apache.lucene.geo.Polygon[polygons.length];
for (int i = 0; i < polygonSet.length; ++i) {
polygonSet[i] = polygonLucene(polygons[i]);
protected static org.elasticsearch.geo.geometry.MultiPolygon multipolygon(Coordinate[][][] polygons) {
List<org.elasticsearch.geo.geometry.Polygon> polygonSet = new ArrayList<>(polygons.length);
for (int i = 0; i < polygons.length; ++i) {
polygonSet.add(polygonGeometry(polygons[i]));
}
return polygonSet;
return new org.elasticsearch.geo.geometry.MultiPolygon(polygonSet);
}
/**

View File

@ -52,7 +52,8 @@ import java.util.Objects;
/**
* Basic class for building GeoJSON shapes like Polygons, Linestrings, etc
*/
public abstract class ShapeBuilder<T extends Shape, E extends ShapeBuilder<T,E>> implements NamedWriteable, ToXContentObject {
public abstract class ShapeBuilder<T extends Shape, G extends org.elasticsearch.geo.geometry.Geometry,
E extends ShapeBuilder<T, G, E>> implements NamedWriteable, ToXContentObject {
protected static final Logger LOGGER = LogManager.getLogger(ShapeBuilder.class);
@ -218,7 +219,7 @@ public abstract class ShapeBuilder<T extends Shape, E extends ShapeBuilder<T,E>>
*
* @return GeoPoint, double[][], Line, Line[], Polygon, Polygon[], Rectangle, Object[]
*/
public abstract Object buildLucene();
public abstract G buildGeometry();
protected static Coordinate shift(Coordinate coordinate, double dateline) {
if (dateline == 0) {
@ -484,7 +485,7 @@ public abstract class ShapeBuilder<T extends Shape, E extends ShapeBuilder<T,E>>
if (this == o) return true;
if (!(o instanceof ShapeBuilder)) return false;
ShapeBuilder<?,?> that = (ShapeBuilder<?,?>) o;
ShapeBuilder<?,?,?> that = (ShapeBuilder<?,?,?>) o;
return Objects.equals(coordinates, that.coordinates);
}

View File

@ -22,13 +22,20 @@ import org.apache.lucene.document.Field;
import org.apache.lucene.document.LatLonShape;
import org.apache.lucene.geo.Line;
import org.apache.lucene.geo.Polygon;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.index.IndexableField;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.geo.parsers.ShapeParser;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.geo.geometry.Circle;
import org.elasticsearch.geo.geometry.Geometry;
import org.elasticsearch.geo.geometry.GeometryCollection;
import org.elasticsearch.geo.geometry.GeometryVisitor;
import org.elasticsearch.geo.geometry.LinearRing;
import org.elasticsearch.geo.geometry.MultiLine;
import org.elasticsearch.geo.geometry.MultiPoint;
import org.elasticsearch.geo.geometry.MultiPolygon;
import org.elasticsearch.geo.geometry.Point;
import java.io.IOException;
import java.util.ArrayList;
@ -107,7 +114,7 @@ public class GeoShapeFieldMapper extends BaseGeoShapeFieldMapper {
if (shapeBuilder == null) {
return;
}
shape = shapeBuilder.buildLucene();
shape = shapeBuilder.buildGeometry();
}
indexShape(context, shape);
} catch (Exception e) {
@ -120,47 +127,97 @@ public class GeoShapeFieldMapper extends BaseGeoShapeFieldMapper {
}
private void indexShape(ParseContext context, Object luceneShape) {
if (luceneShape instanceof GeoPoint) {
GeoPoint pt = (GeoPoint) luceneShape;
indexFields(context, LatLonShape.createIndexableFields(name(), pt.lat(), pt.lon()));
} else if (luceneShape instanceof double[]) {
double[] pt = (double[]) luceneShape;
indexFields(context, LatLonShape.createIndexableFields(name(), pt[1], pt[0]));
} else if (luceneShape instanceof Line) {
indexFields(context, LatLonShape.createIndexableFields(name(), (Line)luceneShape));
} else if (luceneShape instanceof Polygon) {
indexFields(context, LatLonShape.createIndexableFields(name(), (Polygon) luceneShape));
} else if (luceneShape instanceof double[][]) {
double[][] pts = (double[][])luceneShape;
for (int i = 0; i < pts.length; ++i) {
indexFields(context, LatLonShape.createIndexableFields(name(), pts[i][1], pts[i][0]));
}
} else if (luceneShape instanceof Line[]) {
Line[] lines = (Line[]) luceneShape;
for (int i = 0; i < lines.length; ++i) {
indexFields(context, LatLonShape.createIndexableFields(name(), lines[i]));
}
} else if (luceneShape instanceof Polygon[]) {
Polygon[] polys = (Polygon[]) luceneShape;
for (int i = 0; i < polys.length; ++i) {
indexFields(context, LatLonShape.createIndexableFields(name(), polys[i]));
}
} else if (luceneShape instanceof Rectangle) {
// index rectangle as a polygon
Rectangle r = (Rectangle) luceneShape;
Polygon p = new Polygon(new double[]{r.minLat, r.minLat, r.maxLat, r.maxLat, r.minLat},
new double[]{r.minLon, r.maxLon, r.maxLon, r.minLon, r.minLon});
indexFields(context, LatLonShape.createIndexableFields(name(), p));
} else if (luceneShape instanceof Object[]) {
// recurse to index geometry collection
for (Object o : (Object[])luceneShape) {
indexShape(context, o);
}
if (luceneShape instanceof Geometry) {
((Geometry) luceneShape).visit(new LuceneGeometryIndexer(context));
} else {
throw new IllegalArgumentException("invalid shape type found [" + luceneShape.getClass() + "] while indexing shape");
}
}
private class LuceneGeometryIndexer implements GeometryVisitor<Void> {
private ParseContext context;
private LuceneGeometryIndexer(ParseContext context) {
this.context = context;
}
@Override
public Void visit(Circle circle) {
throw new IllegalArgumentException("invalid shape type found [Circle] while indexing shape");
}
@Override
public Void visit(GeometryCollection<?> collection) {
for (Geometry geometry : collection) {
geometry.visit(this);
}
return null;
}
@Override
public Void visit(org.elasticsearch.geo.geometry.Line line) {
indexFields(context, LatLonShape.createIndexableFields(name(), new Line(line.getLats(), line.getLons())));
return null;
}
@Override
public Void visit(LinearRing ring) {
throw new IllegalArgumentException("invalid shape type found [LinearRing] while indexing shape");
}
@Override
public Void visit(MultiLine multiLine) {
for (org.elasticsearch.geo.geometry.Line line : multiLine) {
visit(line);
}
return null;
}
@Override
public Void visit(MultiPoint multiPoint) {
for(Point point : multiPoint) {
visit(point);
}
return null;
}
@Override
public Void visit(MultiPolygon multiPolygon) {
for(org.elasticsearch.geo.geometry.Polygon polygon : multiPolygon) {
visit(polygon);
}
return null;
}
@Override
public Void visit(Point point) {
indexFields(context, LatLonShape.createIndexableFields(name(), point.getLat(), point.getLon()));
return null;
}
@Override
public Void visit(org.elasticsearch.geo.geometry.Polygon polygon) {
indexFields(context, LatLonShape.createIndexableFields(name(), toLucenePolygon(polygon)));
return null;
}
@Override
public Void visit(org.elasticsearch.geo.geometry.Rectangle r) {
Polygon p = new Polygon(new double[]{r.getMinLat(), r.getMinLat(), r.getMaxLat(), r.getMaxLat(), r.getMinLat()},
new double[]{r.getMinLon(), r.getMaxLon(), r.getMaxLon(), r.getMinLon(), r.getMinLon()});
indexFields(context, LatLonShape.createIndexableFields(name(), p));
return null;
}
}
public static Polygon toLucenePolygon(org.elasticsearch.geo.geometry.Polygon polygon) {
Polygon[] holes = new Polygon[polygon.getNumberOfHoles()];
for(int i = 0; i<holes.length; i++) {
holes[i] = new Polygon(polygon.getHole(i).getLats(), polygon.getHole(i).getLons());
}
return new Polygon(polygon.getPolygon().getLats(), polygon.getPolygon().getLons(), holes);
}
private void indexFields(ParseContext context, Field[] fields) {
ArrayList<IndexableField> flist = new ArrayList<>(Arrays.asList(fields));
createFieldNamesField(context, flist);

View File

@ -23,7 +23,6 @@ import org.apache.logging.log4j.LogManager;
import org.apache.lucene.document.LatLonShape;
import org.apache.lucene.geo.Line;
import org.apache.lucene.geo.Polygon;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.ConstantScoreQuery;
@ -42,7 +41,6 @@ import org.elasticsearch.client.Client;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.GeoShapeType;
import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.geo.SpatialStrategy;
@ -56,6 +54,15 @@ import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.geo.geometry.Circle;
import org.elasticsearch.geo.geometry.Geometry;
import org.elasticsearch.geo.geometry.GeometryCollection;
import org.elasticsearch.geo.geometry.GeometryVisitor;
import org.elasticsearch.geo.geometry.LinearRing;
import org.elasticsearch.geo.geometry.MultiLine;
import org.elasticsearch.geo.geometry.MultiPoint;
import org.elasticsearch.geo.geometry.MultiPolygon;
import org.elasticsearch.geo.geometry.Point;
import org.elasticsearch.index.mapper.BaseGeoShapeFieldMapper;
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
@ -64,6 +71,8 @@ import java.io.IOException;
import java.util.Objects;
import java.util.function.Supplier;
import static org.elasticsearch.index.mapper.GeoShapeFieldMapper.toLucenePolygon;
/**
* {@link QueryBuilder} that builds a GeoShape Query
*/
@ -446,55 +455,85 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil
}
// wrap geoQuery as a ConstantScoreQuery
return getVectorQueryFromShape(context, queryShapeBuilder.buildLucene());
return getVectorQueryFromShape(context, queryShapeBuilder.buildGeometry());
}
private Query getVectorQueryFromShape(QueryShardContext context, Object queryShape) {
Query geoQuery;
if (queryShape instanceof Line[]) {
geoQuery = LatLonShape.newLineQuery(fieldName(), relation.getLuceneRelation(), (Line[]) queryShape);
} else if (queryShape instanceof Polygon[]) {
geoQuery = LatLonShape.newPolygonQuery(fieldName(), relation.getLuceneRelation(), (Polygon[]) queryShape);
} else if (queryShape instanceof Line) {
geoQuery = LatLonShape.newLineQuery(fieldName(), relation.getLuceneRelation(), (Line) queryShape);
} else if (queryShape instanceof Polygon) {
geoQuery = LatLonShape.newPolygonQuery(fieldName(), relation.getLuceneRelation(), (Polygon) queryShape);
} else if (queryShape instanceof Rectangle) {
Rectangle r = (Rectangle) queryShape;
geoQuery = LatLonShape.newBoxQuery(fieldName(), relation.getLuceneRelation(),
r.minLat, r.maxLat, r.minLon, r.maxLon);
} else if (queryShape instanceof double[][]) {
// note: we decompose point queries into a bounding box query with min values == max values
// to do this for multipoint we would have to create a BooleanQuery for each point
// this is *way* too costly. So we do not allow multipoint queries
throw new QueryShardException(context, "Field [" + fieldName + "] does not support " + GeoShapeType.MULTIPOINT + " queries");
} else if (queryShape instanceof double[] || queryShape instanceof GeoPoint) {
// for now just create a single bounding box query with min values == max values
double[] pt;
if (queryShape instanceof GeoPoint) {
pt = new double[] {((GeoPoint)queryShape).lon(), ((GeoPoint)queryShape).lat()};
} else {
pt = (double[])queryShape;
if (pt.length != 2) {
throw new QueryShardException(context, "Expected double array of length 2. "
+ "But found length " + pt.length + " for field [" + fieldName + "]");
private Query getVectorQueryFromShape(QueryShardContext context, Geometry queryShape) {
return queryShape.visit(new GeometryVisitor<Query>() {
@Override
public Query visit(Circle circle) {
throw new QueryShardException(context, "Field [" + fieldName + "] found and unknown shape Circle");
}
@Override
public Query visit(GeometryCollection<?> collection) {
BooleanQuery.Builder bqb = new BooleanQuery.Builder();
visit(bqb, collection);
return bqb.build();
}
private void visit(BooleanQuery.Builder bqb, GeometryCollection<?> collection) {
for (Geometry shape : collection) {
if (shape instanceof MultiPoint) {
// Flatten multipoints
visit(bqb, (GeometryCollection<?>) shape);
} else {
bqb.add(shape.visit(this), BooleanClause.Occur.SHOULD);
}
}
}
return LatLonShape.newBoxQuery(fieldName, relation.getLuceneRelation(), pt[1], pt[1], pt[0], pt[0]);
} else if (queryShape instanceof Object[]) {
geoQuery = createGeometryCollectionQuery(context, (Object[]) queryShape);
} else {
throw new QueryShardException(context, "Field [" + fieldName + "] found and unknown shape");
}
return geoQuery;
}
private Query createGeometryCollectionQuery(QueryShardContext context, Object... shapes) {
BooleanQuery.Builder bqb = new BooleanQuery.Builder();
for (Object shape : shapes) {
bqb.add(getVectorQueryFromShape(context, shape), BooleanClause.Occur.SHOULD);
}
return bqb.build();
@Override
public Query visit(org.elasticsearch.geo.geometry.Line line) {
return LatLonShape.newLineQuery(fieldName(), relation.getLuceneRelation(), new Line(line.getLats(), line.getLons()));
}
@Override
public Query visit(LinearRing ring) {
throw new QueryShardException(context, "Field [" + fieldName + "] found and unsupported shape LinearRing");
}
@Override
public Query visit(MultiLine multiLine) {
Line[] lines = new Line[multiLine.size()];
for (int i=0; i<multiLine.size(); i++) {
lines[i] = new Line(multiLine.get(i).getLats(), multiLine.get(i).getLons());
}
return LatLonShape.newLineQuery(fieldName(), relation.getLuceneRelation(), lines);
}
@Override
public Query visit(MultiPoint multiPoint) {
throw new QueryShardException(context, "Field [" + fieldName + "] does not support " + GeoShapeType.MULTIPOINT +
" queries");
}
@Override
public Query visit(MultiPolygon multiPolygon) {
Polygon[] polygons = new Polygon[multiPolygon.size()];
for (int i=0; i<multiPolygon.size(); i++) {
polygons[i] = toLucenePolygon(multiPolygon.get(i));
}
return LatLonShape.newPolygonQuery(fieldName(), relation.getLuceneRelation(), polygons);
}
@Override
public Query visit(Point point) {
return LatLonShape.newBoxQuery(fieldName, relation.getLuceneRelation(),
point.getLat(), point.getLat(), point.getLon(), point.getLon());
}
@Override
public Query visit(org.elasticsearch.geo.geometry.Polygon polygon) {
return LatLonShape.newPolygonQuery(fieldName(), relation.getLuceneRelation(), toLucenePolygon(polygon));
}
@Override
public Query visit(org.elasticsearch.geo.geometry.Rectangle r) {
return LatLonShape.newBoxQuery(fieldName(), relation.getLuceneRelation(),
r.getMinLat(), r.getMaxLat(), r.getMinLon(), r.getMaxLon());
}
});
}
/**

View File

@ -62,7 +62,7 @@ abstract class BaseGeoParsingTestCase extends ESTestCase {
if (useJTS) {
ElasticsearchGeoAssertions.assertEquals(expected, ShapeParser.parse(parser).buildS4J());
} else {
ElasticsearchGeoAssertions.assertEquals(expected, ShapeParser.parse(parser).buildLucene());
ElasticsearchGeoAssertions.assertEquals(expected, ShapeParser.parse(parser).buildGeometry());
}
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.common.geo;
import org.apache.lucene.geo.Line;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetaData;
@ -31,6 +30,10 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.geo.geometry.Geometry;
import org.elasticsearch.geo.geometry.GeometryCollection;
import org.elasticsearch.geo.geometry.MultiLine;
import org.elasticsearch.geo.geometry.MultiPoint;
import org.elasticsearch.index.mapper.ContentPath;
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
import org.elasticsearch.index.mapper.Mapper;
@ -53,6 +56,7 @@ import org.locationtech.spatial4j.shape.jts.JtsPoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.common.geo.builders.ShapeBuilder.SPATIAL_CONTEXT;
@ -72,7 +76,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
.endObject();
Point expected = GEOMETRY_FACTORY.createPoint(new Coordinate(100.0, 0.0));
assertGeometryEquals(new JtsPoint(expected, SPATIAL_CONTEXT), pointGeoJson, true);
assertGeometryEquals(new GeoPoint(0d, 100d), pointGeoJson, false);
assertGeometryEquals(new org.elasticsearch.geo.geometry.Point(0d, 100d), pointGeoJson, false);
}
@Override
@ -98,7 +102,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(lineGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertLineString(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertLineString(ShapeParser.parse(parser).buildGeometry(), false);
}
}
@ -130,9 +134,9 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
}),
});
assertGeometryEquals(jtsGeom(expected), multilinesGeoJson, true);
assertGeometryEquals(new Line[] {
new Line(new double[] {0d, 1d}, new double[] {100d, 101d}),
new Line(new double[] {2d, 3d}, new double[] {102d, 103d})},
assertGeometryEquals(new MultiLine(Arrays.asList(
new org.elasticsearch.geo.geometry.Line(new double[] {0d, 1d}, new double[] {100d, 101d}),
new org.elasticsearch.geo.geometry.Line(new double[] {2d, 3d}, new double[] {102d, 103d}))),
multilinesGeoJson, false);
}
@ -188,7 +192,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
.endObject();
Rectangle expected = SPATIAL_CONTEXT.makeRectangle(-50, 50, -30, 30);
assertGeometryEquals(expected, multilinesGeoJson, true);
assertGeometryEquals(new org.apache.lucene.geo.Rectangle(-30, 30, -50, 50),
assertGeometryEquals(new org.elasticsearch.geo.geometry.Rectangle(-30, 30, -50, 50),
multilinesGeoJson, false);
// test #2: envelope that spans dateline
@ -201,7 +205,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
expected = SPATIAL_CONTEXT.makeRectangle(50, -50, -30, 30);
assertGeometryEquals(expected, multilinesGeoJson, true);
assertGeometryEquals(new org.apache.lucene.geo.Rectangle(-30, 30, 50, -50),
assertGeometryEquals(new org.elasticsearch.geo.geometry.Rectangle(-30, 30, 50, -50),
multilinesGeoJson, false);
// test #3: "envelope" (actually a triangle) with invalid number of coordinates (TopRight, BottomLeft, BottomRight)
@ -257,9 +261,10 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
Polygon expected = GEOMETRY_FACTORY.createPolygon(shell, null);
assertGeometryEquals(jtsGeom(expected), polygonGeoJson, true);
org.apache.lucene.geo.Polygon p = new org.apache.lucene.geo.Polygon(
new double[] {0d, 0d, 1d, 1d, 0d},
new double[] {100d, 101d, 101d, 100d, 100d});
org.elasticsearch.geo.geometry.Polygon p = new org.elasticsearch.geo.geometry.Polygon(
new org.elasticsearch.geo.geometry.LinearRing(
new double[] {0d, 0d, 1d, 1d, 0d},
new double[] {100d, 101d, 101d, 100d, 100d}));
assertGeometryEquals(p, polygonGeoJson, false);
}
@ -303,9 +308,10 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
ElasticsearchGeoAssertions.assertEquals(jtsGeom(expected), ShapeParser.parse(parser, mapperBuilder).buildS4J());
}
org.apache.lucene.geo.Polygon p = new org.apache.lucene.geo.Polygon(
org.elasticsearch.geo.geometry.Polygon p = new org.elasticsearch.geo.geometry.Polygon(new org.elasticsearch.geo.geometry.LinearRing(
Arrays.stream(coordinates).mapToDouble(i->i.y).toArray(),
Arrays.stream(coordinates).mapToDouble(i->i.x).toArray());
Arrays.stream(coordinates).mapToDouble(i->i.x).toArray()
));
assertGeometryEquals(p, polygonGeoJson, false);
}
@ -502,7 +508,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
// test 2: ccw poly crossing dateline
@ -527,7 +533,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
// test 3: cw poly not crossing dateline
@ -552,7 +558,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
// test 4: cw poly crossing dateline
@ -577,7 +583,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
}
@ -610,7 +616,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
// test 2: ccw poly crossing dateline
@ -641,7 +647,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
// test 3: cw poly not crossing dateline
@ -672,7 +678,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
// test 4: cw poly crossing dateline
@ -703,7 +709,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(JsonXContent.jsonXContent, polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
}
@ -855,12 +861,12 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
Polygon expected = GEOMETRY_FACTORY.createPolygon(shell, holes);
assertGeometryEquals(jtsGeom(expected), polygonGeoJson, true);
org.apache.lucene.geo.Polygon hole =
new org.apache.lucene.geo.Polygon(
org.elasticsearch.geo.geometry.LinearRing hole =
new org.elasticsearch.geo.geometry.LinearRing(
new double[] {0.8d, 0.2d, 0.2d, 0.8d, 0.8d}, new double[] {100.8d, 100.8d, 100.2d, 100.2d, 100.8d});
org.apache.lucene.geo.Polygon p =
new org.apache.lucene.geo.Polygon(
new double[] {0d, 0d, 1d, 1d, 0d}, new double[] {100d, 101d, 101d, 100d, 100d}, hole);
org.elasticsearch.geo.geometry.Polygon p =
new org.elasticsearch.geo.geometry.Polygon(new org.elasticsearch.geo.geometry.LinearRing(
new double[] {0d, 0d, 1d, 1d, 0d}, new double[] {100d, 101d, 101d, 100d, 100d}), Collections.singletonList(hole));
assertGeometryEquals(p, polygonGeoJson, false);
}
@ -902,9 +908,9 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
SPATIAL_CONTEXT.makePoint(101, 1.0));
assertGeometryEquals(expected, multiPointGeoJson, true);
assertGeometryEquals(new double[][]{
new double[] {100d, 0d},
new double[] {101d, 1d}}, multiPointGeoJson, false);
assertGeometryEquals(new MultiPoint(Arrays.asList(
new org.elasticsearch.geo.geometry.Point(0, 100),
new org.elasticsearch.geo.geometry.Point(1, 101))), multiPointGeoJson, false);
}
@Override
@ -975,16 +981,15 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
assertGeometryEquals(expected, multiPolygonGeoJson, true);
org.apache.lucene.geo.Polygon hole =
new org.apache.lucene.geo.Polygon(
org.elasticsearch.geo.geometry.LinearRing hole = new org.elasticsearch.geo.geometry.LinearRing(
new double[] {0.8d, 0.2d, 0.2d, 0.8d, 0.8d}, new double[] {100.8d, 100.8d, 100.2d, 100.2d, 100.8d});
org.apache.lucene.geo.Polygon[] polygons = new org.apache.lucene.geo.Polygon[] {
new org.apache.lucene.geo.Polygon(
new double[] {2d, 3d, 3d, 2d, 2d}, new double[] {103d, 103d, 102d, 102d, 103d}),
new org.apache.lucene.geo.Polygon(
new double[] {0d, 1d, 1d, 0d, 0d}, new double[] {101d, 101d, 100d, 100d, 101d}, hole)
};
org.elasticsearch.geo.geometry.MultiPolygon polygons = new org.elasticsearch.geo.geometry.MultiPolygon(Arrays.asList(
new org.elasticsearch.geo.geometry.Polygon(new org.elasticsearch.geo.geometry.LinearRing(
new double[] {2d, 3d, 3d, 2d, 2d}, new double[] {103d, 103d, 102d, 102d, 103d})),
new org.elasticsearch.geo.geometry.Polygon(new org.elasticsearch.geo.geometry.LinearRing(
new double[] {0d, 1d, 1d, 0d, 0d}, new double[] {101d, 101d, 100d, 100d, 101d}), Collections.singletonList(hole))));
assertGeometryEquals(polygons, multiPolygonGeoJson, false);
// test #2: multipolygon; one polygon with one hole
@ -1034,14 +1039,13 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
assertGeometryEquals(jtsGeom(withHoles), multiPolygonGeoJson, true);
org.apache.lucene.geo.Polygon luceneHole =
new org.apache.lucene.geo.Polygon(
org.elasticsearch.geo.geometry.LinearRing luceneHole =
new org.elasticsearch.geo.geometry.LinearRing(
new double[] {0.8d, 0.2d, 0.2d, 0.8d, 0.8d}, new double[] {100.8d, 100.8d, 100.2d, 100.2d, 100.8d});
org.apache.lucene.geo.Polygon[] lucenePolygons = new org.apache.lucene.geo.Polygon[] {
new org.apache.lucene.geo.Polygon(
new double[] {0d, 0d, 1d, 1d, 0d}, new double[] {100d, 101d, 101d, 100d, 100d}, luceneHole)
};
org.elasticsearch.geo.geometry.MultiPolygon lucenePolygons = new org.elasticsearch.geo.geometry.MultiPolygon(
Collections.singletonList(new org.elasticsearch.geo.geometry.Polygon(new org.elasticsearch.geo.geometry.LinearRing(
new double[] {0d, 0d, 1d, 1d, 0d}, new double[] {100d, 101d, 101d, 100d, 100d}), Collections.singletonList(luceneHole))));
assertGeometryEquals(lucenePolygons, multiPolygonGeoJson, false);
}
@ -1117,19 +1121,21 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
//equals returns true only if geometries are in the same order
assertGeometryEquals(shapeCollection(expected), geometryCollectionGeoJson, true);
Object[] luceneExpected = new Object[] {
new Line(new double[] {0d, 1d}, new double[] {100d, 101d}),
new GeoPoint(2d, 102d),
new org.apache.lucene.geo.Polygon(
new double[] {-12.142857142857142d, 12.142857142857142d, 15d, 0d, -15d, -12.142857142857142d},
new double[] {180d, 180d, 176d, 172d, 176d, 180d}
),
new org.apache.lucene.geo.Polygon(
new double[] {12.142857142857142d, -12.142857142857142d, -10d, 10d, 12.142857142857142d},
new double[] {-180d, -180d, -177d, -177d, -180d}
)
};
assertGeometryEquals(luceneExpected, geometryCollectionGeoJson, false);
GeometryCollection<Geometry> geometryExpected = new GeometryCollection<> (Arrays.asList(
new org.elasticsearch.geo.geometry.Line(new double[] {0d, 1d}, new double[] {100d, 101d}),
new org.elasticsearch.geo.geometry.Point(2d, 102d),
new org.elasticsearch.geo.geometry.MultiPolygon(Arrays.asList(
new org.elasticsearch.geo.geometry.Polygon(new org.elasticsearch.geo.geometry.LinearRing(
new double[] {-12.142857142857142d, 12.142857142857142d, 15d, 0d, -15d, -12.142857142857142d},
new double[] {180d, 180d, 176d, 172d, 176d, 180d}
)),
new org.elasticsearch.geo.geometry.Polygon(new org.elasticsearch.geo.geometry.LinearRing(
new double[] {12.142857142857142d, -12.142857142857142d, -10d, 10d, 12.142857142857142d},
new double[] {-180d, -180d, -177d, -177d, -180d}
))
))
));
assertGeometryEquals(geometryExpected, geometryCollectionGeoJson, false);
}
public void testThatParserExtractsCorrectTypeAndCoordinatesFromArbitraryJson() throws IOException {
@ -1151,7 +1157,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
Point expected = GEOMETRY_FACTORY.createPoint(new Coordinate(100.0, 0.0));
assertGeometryEquals(new JtsPoint(expected, SPATIAL_CONTEXT), pointGeoJson, true);
GeoPoint expectedPt = new GeoPoint(0, 100);
org.elasticsearch.geo.geometry.Point expectedPt = new org.elasticsearch.geo.geometry.Point(0, 100);
assertGeometryEquals(expectedPt, pointGeoJson, false);
}
@ -1187,7 +1193,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
// test 2: valid ccw (right handed system) poly not crossing dateline (with 'ccw' field)
@ -1221,7 +1227,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
// test 3: valid ccw (right handed system) poly not crossing dateline (with 'counterclockwise' field)
@ -1255,7 +1261,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
// test 4: valid cw (left handed system) poly crossing dateline (with 'left' field)
@ -1289,7 +1295,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
// test 5: valid cw multipoly (left handed system) poly crossing dateline (with 'cw' field)
@ -1323,7 +1329,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
// test 6: valid cw multipoly (left handed system) poly crossing dateline (with 'clockwise' field)
@ -1357,7 +1363,7 @@ public class GeoJsonShapeParserTests extends BaseGeoParsingTestCase {
try (XContentParser parser = createParser(polygonGeoJson)) {
parser.nextToken();
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildLucene(), false);
ElasticsearchGeoAssertions.assertMultiPolygon(ShapeParser.parse(parser).buildGeometry(), false);
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.common.geo;
import org.apache.lucene.geo.GeoTestUtil;
import org.apache.lucene.geo.Line;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.Version;
@ -41,6 +40,9 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.geo.geometry.Line;
import org.elasticsearch.geo.geometry.MultiLine;
import org.elasticsearch.geo.geometry.MultiPoint;
import org.elasticsearch.index.mapper.ContentPath;
import org.elasticsearch.index.mapper.GeoShapeFieldMapper;
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
@ -61,6 +63,7 @@ import org.locationtech.spatial4j.shape.jts.JtsPoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.common.geo.builders.ShapeBuilder.SPATIAL_CONTEXT;
@ -72,7 +75,7 @@ import static org.hamcrest.Matchers.hasToString;
*/
public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
private static XContentBuilder toWKTContent(ShapeBuilder<?, ?> builder, boolean generateMalformed)
private static XContentBuilder toWKTContent(ShapeBuilder<?, ?, ?> builder, boolean generateMalformed)
throws IOException {
String wkt = builder.toWKT();
if (generateMalformed) {
@ -87,12 +90,12 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
return XContentFactory.jsonBuilder().value(wkt);
}
private void assertExpected(Object expected, ShapeBuilder<?, ?> builder, boolean useJTS) throws IOException {
private void assertExpected(Object expected, ShapeBuilder<?, ?, ?> builder, boolean useJTS) throws IOException {
XContentBuilder xContentBuilder = toWKTContent(builder, false);
assertGeometryEquals(expected, xContentBuilder, useJTS);
}
private void assertMalformed(ShapeBuilder<?, ?> builder) throws IOException {
private void assertMalformed(ShapeBuilder<?, ?, ?> builder) throws IOException {
XContentBuilder xContentBuilder = toWKTContent(builder, true);
assertValidException(xContentBuilder, ElasticsearchParseException.class);
}
@ -103,7 +106,7 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
Coordinate c = new Coordinate(p.lon(), p.lat());
Point expected = GEOMETRY_FACTORY.createPoint(c);
assertExpected(new JtsPoint(expected, SPATIAL_CONTEXT), new PointBuilder().coordinate(c), true);
assertExpected(new GeoPoint(p.lat(), p.lon()), new PointBuilder().coordinate(c), false);
assertExpected(new org.elasticsearch.geo.geometry.Point(p.lat(), p.lon()), new PointBuilder().coordinate(c), false);
assertMalformed(new PointBuilder().coordinate(c));
}
@ -123,13 +126,12 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
ShapeCollection<?> expected = shapeCollection(shapes);
assertExpected(expected, new MultiPointBuilder(coordinates), true);
double[][] luceneShapes = new double[numPoints][2];
List<org.elasticsearch.geo.geometry.Point> points = new ArrayList<>(numPoints);
for (int i = 0; i < numPoints; ++i) {
Coordinate c = coordinates.get(i);
luceneShapes[i][0] = c.x;
luceneShapes[i][1] = c.y;
points.add(new org.elasticsearch.geo.geometry.Point(c.y, c.x));
}
assertExpected(luceneShapes, new MultiPointBuilder(coordinates), false);
assertExpected(new MultiPoint(points), new MultiPointBuilder(coordinates), false);
assertMalformed(new MultiPointBuilder(coordinates));
}
@ -175,13 +177,13 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
lineStrings.toArray(new LineString[lineStrings.size()]));
assertExpected(jtsGeom(expected), builder, true);
Line[] lines = new Line[lineStrings.size()];
List<Line> lines = new ArrayList<>(lineStrings.size());
for (int j = 0; j < lineStrings.size(); ++j) {
Coordinate[] c = lineStrings.get(j).getCoordinates();
lines[j] = new Line(Arrays.stream(c).mapToDouble(i->i.y).toArray(),
Arrays.stream(c).mapToDouble(i->i.x).toArray());
lines.add(new Line(Arrays.stream(c).mapToDouble(i->i.y).toArray(),
Arrays.stream(c).mapToDouble(i->i.x).toArray()));
}
assertExpected(lines, builder, false);
assertExpected(new MultiLine(lines), builder, false);
assertMalformed(builder);
}
@ -245,12 +247,12 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
Polygon expected = GEOMETRY_FACTORY.createPolygon(shell, holes);
assertExpected(jtsGeom(expected), polygonWithHole, true);
org.apache.lucene.geo.Polygon hole =
new org.apache.lucene.geo.Polygon(
org.elasticsearch.geo.geometry.LinearRing hole =
new org.elasticsearch.geo.geometry.LinearRing(
new double[] {0.8d, 0.8d, 0.2d, 0.2d, 0.8d}, new double[] {100.2d, 100.8d, 100.8d, 100.2d, 100.2d});
org.apache.lucene.geo.Polygon p =
new org.apache.lucene.geo.Polygon(
new double[] {0d, 1d, 1d, 0d, 0d}, new double[] {101d, 101d, 100d, 100d, 101d}, hole);
org.elasticsearch.geo.geometry.Polygon p =
new org.elasticsearch.geo.geometry.Polygon(new org.elasticsearch.geo.geometry.LinearRing(
new double[] {0d, 1d, 1d, 0d, 0d}, new double[] {101d, 101d, 100d, 100d, 101d}), Collections.singletonList(hole));
assertExpected(p, polygonWithHole, false);
assertMalformed(polygonWithHole);
}
@ -357,7 +359,7 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
final LegacyGeoShapeFieldMapper mapperBuilder =
(LegacyGeoShapeFieldMapper)(new LegacyGeoShapeFieldMapper.Builder("test").ignoreZValue(true).build(mockBuilderContext));
ShapeBuilder<?, ?> shapeBuilder = ShapeParser.parse(parser, mapperBuilder);
ShapeBuilder<?, ?, ?> shapeBuilder = ShapeParser.parse(parser, mapperBuilder);
assertEquals(shapeBuilder.numDimensions(), 3);
}
@ -383,7 +385,7 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
final LegacyGeoShapeFieldMapper coercingMapperBuilder =
(LegacyGeoShapeFieldMapper)(new LegacyGeoShapeFieldMapper.Builder("test").coerce(true).build(mockBuilderContext));
ShapeBuilder<?, ?> shapeBuilder = ShapeParser.parse(parser, coercingMapperBuilder);
ShapeBuilder<?, ?, ?> shapeBuilder = ShapeParser.parse(parser, coercingMapperBuilder);
assertNotNull(shapeBuilder);
assertEquals("polygon ((100.0 5.0, 100.0 10.0, 90.0 10.0, 90.0 5.0, 100.0 5.0))", shapeBuilder.toWKT());
}
@ -418,7 +420,7 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
Rectangle expected = SPATIAL_CONTEXT.makeRectangle(r.minLon, r.maxLon, r.minLat, r.maxLat);
assertExpected(expected, builder, true);
assertExpected(r, builder, false);
assertExpected(new org.elasticsearch.geo.geometry.Rectangle(r.minLat, r.maxLat, r.minLon, r.maxLon), builder, false);
assertMalformed(builder);
}
@ -436,12 +438,12 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
if (randomBoolean()) {
assertEquals(shapeCollection(expected).isEmpty(), builder.buildS4J().isEmpty());
} else {
assertEquals(shapeCollection(expected).isEmpty(), ((Object[])builder.buildLucene()).length == 0);
assertEquals(shapeCollection(expected).isEmpty(), builder.buildGeometry().size() == 0);
}
} else {
GeometryCollectionBuilder gcb = RandomShapeGenerator.createGeometryCollection(random());
assertExpected(gcb.buildS4J(), gcb, true);
assertExpected(gcb.buildLucene(), gcb, false);
assertExpected(gcb.buildGeometry(), gcb, false);
}
}

View File

@ -52,7 +52,7 @@ public class ShapeBuilderTests extends ESTestCase {
Point point = pb.buildS4J();
assertEquals(-100D, point.getX(), 0.0d);
assertEquals(45D, point.getY(), 0.0d);
GeoPoint geoPoint = pb.buildLucene();
org.elasticsearch.geo.geometry.Point geoPoint = pb.buildGeometry();
assertEquals(-100D, geoPoint.getLon(), 0.0d);
assertEquals(45D, geoPoint.getLat(), 0.0d);
}
@ -65,11 +65,11 @@ public class ShapeBuilderTests extends ESTestCase {
assertEquals(45D, rectangle.getMaxX(), 0.0d);
assertEquals(30D, rectangle.getMaxY(), 0.0d);
org.apache.lucene.geo.Rectangle luceneRectangle = eb.buildLucene();
assertEquals(-45D, luceneRectangle.minLon, 0.0d);
assertEquals(-30D, luceneRectangle.minLat, 0.0d);
assertEquals(45D, luceneRectangle.maxLon, 0.0d);
assertEquals(30D, luceneRectangle.maxLat, 0.0d);
org.elasticsearch.geo.geometry.Rectangle luceneRectangle = eb.buildGeometry();
assertEquals(-45D, luceneRectangle.getMinLon(), 0.0d);
assertEquals(-30D, luceneRectangle.getMinLat(), 0.0d);
assertEquals(45D, luceneRectangle.getMaxLon(), 0.0d);
assertEquals(30D, luceneRectangle.getMaxLat(), 0.0d);
}
public void testNewPolygon() {
@ -87,15 +87,15 @@ public class ShapeBuilderTests extends ESTestCase {
assertEquals(exterior.getCoordinateN(2), new Coordinate(45, -30));
assertEquals(exterior.getCoordinateN(3), new Coordinate(-45, -30));
org.apache.lucene.geo.Polygon lucenePoly = (org.apache.lucene.geo.Polygon)(pb.toPolygonLucene());
assertEquals(lucenePoly.getPolyLat(0), 30, 0d);
assertEquals(lucenePoly.getPolyLon(0), -45, 0d);
assertEquals(lucenePoly.getPolyLat(1), 30, 0d);
assertEquals(lucenePoly.getPolyLon(1), 45, 0d);
assertEquals(lucenePoly.getPolyLat(2), -30, 0d);
assertEquals(lucenePoly.getPolyLon(2), 45, 0d);
assertEquals(lucenePoly.getPolyLat(3), -30, 0d);
assertEquals(lucenePoly.getPolyLon(3), -45, 0d);
org.elasticsearch.geo.geometry.LinearRing polygon = pb.toPolygonGeometry().getPolygon();
assertEquals(polygon.getLat(0), 30, 0d);
assertEquals(polygon.getLon(0), -45, 0d);
assertEquals(polygon.getLat(1), 30, 0d);
assertEquals(polygon.getLon(1), 45, 0d);
assertEquals(polygon.getLat(2), -30, 0d);
assertEquals(polygon.getLon(2), 45, 0d);
assertEquals(polygon.getLat(3), -30, 0d);
assertEquals(polygon.getLon(3), -45, 0d);
}
public void testNewPolygon_coordinate() {
@ -113,15 +113,15 @@ public class ShapeBuilderTests extends ESTestCase {
assertEquals(exterior.getCoordinateN(2), new Coordinate(45, -30));
assertEquals(exterior.getCoordinateN(3), new Coordinate(-45, -30));
org.apache.lucene.geo.Polygon lucenePoly = (org.apache.lucene.geo.Polygon)(pb.toPolygonLucene());
assertEquals(lucenePoly.getPolyLat(0), 30, 0d);
assertEquals(lucenePoly.getPolyLon(0), -45, 0d);
assertEquals(lucenePoly.getPolyLat(1), 30, 0d);
assertEquals(lucenePoly.getPolyLon(1), 45, 0d);
assertEquals(lucenePoly.getPolyLat(2), -30, 0d);
assertEquals(lucenePoly.getPolyLon(2), 45, 0d);
assertEquals(lucenePoly.getPolyLat(3), -30, 0d);
assertEquals(lucenePoly.getPolyLon(3), -45, 0d);
org.elasticsearch.geo.geometry.LinearRing polygon = pb.toPolygonGeometry().getPolygon();
assertEquals(polygon.getLat(0), 30, 0d);
assertEquals(polygon.getLon(0), -45, 0d);
assertEquals(polygon.getLat(1), 30, 0d);
assertEquals(polygon.getLon(1), 45, 0d);
assertEquals(polygon.getLat(2), -30, 0d);
assertEquals(polygon.getLon(2), 45, 0d);
assertEquals(polygon.getLat(3), -30, 0d);
assertEquals(polygon.getLon(3), -45, 0d);
}
public void testNewPolygon_coordinates() {
@ -137,15 +137,15 @@ public class ShapeBuilderTests extends ESTestCase {
assertEquals(exterior.getCoordinateN(2), new Coordinate(45, -30));
assertEquals(exterior.getCoordinateN(3), new Coordinate(-45, -30));
org.apache.lucene.geo.Polygon lucenePoly = (org.apache.lucene.geo.Polygon)(pb.toPolygonLucene());
assertEquals(lucenePoly.getPolyLat(0), 30, 0d);
assertEquals(lucenePoly.getPolyLon(0), -45, 0d);
assertEquals(lucenePoly.getPolyLat(1), 30, 0d);
assertEquals(lucenePoly.getPolyLon(1), 45, 0d);
assertEquals(lucenePoly.getPolyLat(2), -30, 0d);
assertEquals(lucenePoly.getPolyLon(2), 45, 0d);
assertEquals(lucenePoly.getPolyLat(3), -30, 0d);
assertEquals(lucenePoly.getPolyLon(3), -45, 0d);
org.elasticsearch.geo.geometry.LinearRing polygon = pb.toPolygonGeometry().getPolygon();
assertEquals(polygon.getLat(0), 30, 0d);
assertEquals(polygon.getLon(0), -45, 0d);
assertEquals(polygon.getLat(1), 30, 0d);
assertEquals(polygon.getLon(1), 45, 0d);
assertEquals(polygon.getLat(2), -30, 0d);
assertEquals(polygon.getLon(2), 45, 0d);
assertEquals(polygon.getLat(3), -30, 0d);
assertEquals(polygon.getLon(3), -45, 0d);
}
public void testLineStringBuilder() {
@ -161,7 +161,7 @@ public class ShapeBuilderTests extends ESTestCase {
.coordinate(-110.0, 55.0));
lsb.buildS4J();
lsb.buildLucene();
lsb.buildGeometry();
// Building a linestring that needs to be wrapped
lsb = new LineStringBuilder(new CoordinatesBuilder()
@ -175,7 +175,7 @@ public class ShapeBuilderTests extends ESTestCase {
.coordinate(130.0, 60.0));
lsb.buildS4J();
lsb.buildLucene();
lsb.buildGeometry();
// Building a lineString on the dateline
lsb = new LineStringBuilder(new CoordinatesBuilder()
@ -185,7 +185,7 @@ public class ShapeBuilderTests extends ESTestCase {
.coordinate(-180.0, -80.0));
lsb.buildS4J();
lsb.buildLucene();
lsb.buildGeometry();
// Building a lineString on the dateline
lsb = new LineStringBuilder(new CoordinatesBuilder()
@ -195,7 +195,7 @@ public class ShapeBuilderTests extends ESTestCase {
.coordinate(180.0, -80.0));
lsb.buildS4J();
lsb.buildLucene();
lsb.buildGeometry();
}
public void testMultiLineString() {
@ -215,7 +215,7 @@ public class ShapeBuilderTests extends ESTestCase {
)
);
mlsb.buildS4J();
mlsb.buildLucene();
mlsb.buildGeometry();
// LineString that needs to be wrapped
new MultiLineStringBuilder()
@ -235,7 +235,7 @@ public class ShapeBuilderTests extends ESTestCase {
);
mlsb.buildS4J();
mlsb.buildLucene();
mlsb.buildGeometry();
}
public void testPolygonSelfIntersection() {
@ -283,7 +283,7 @@ public class ShapeBuilderTests extends ESTestCase {
.close());
assertMultiPolygon(pb.buildS4J(), true);
assertMultiPolygon(pb.buildLucene(), false);
assertMultiPolygon(pb.buildGeometry(), false);
}
public void testLineStringWrapping() {
@ -295,7 +295,7 @@ public class ShapeBuilderTests extends ESTestCase {
.close());
assertMultiLineString(lsb.buildS4J(), true);
assertMultiLineString(lsb.buildLucene(), false);
assertMultiLineString(lsb.buildGeometry(), false);
}
public void testDatelineOGC() {
@ -339,7 +339,7 @@ public class ShapeBuilderTests extends ESTestCase {
));
assertMultiPolygon(builder.close().buildS4J(), true);
assertMultiPolygon(builder.close().buildLucene(), false);
assertMultiPolygon(builder.close().buildGeometry(), false);
}
public void testDateline() {
@ -383,7 +383,7 @@ public class ShapeBuilderTests extends ESTestCase {
));
assertMultiPolygon(builder.close().buildS4J(), true);
assertMultiPolygon(builder.close().buildLucene(), false);
assertMultiPolygon(builder.close().buildGeometry(), false);
}
public void testComplexShapeWithHole() {
@ -458,7 +458,7 @@ public class ShapeBuilderTests extends ESTestCase {
)
);
assertPolygon(builder.close().buildS4J(), true);
assertPolygon(builder.close().buildLucene(), false);
assertPolygon(builder.close().buildGeometry(), false);
}
public void testShapeWithHoleAtEdgeEndPoints() {
@ -480,7 +480,7 @@ public class ShapeBuilderTests extends ESTestCase {
.coordinate(4, 1)
));
assertPolygon(builder.close().buildS4J(), true);
assertPolygon(builder.close().buildLucene(), false);
assertPolygon(builder.close().buildGeometry(), false);
}
public void testShapeWithPointOnDateline() {
@ -491,7 +491,7 @@ public class ShapeBuilderTests extends ESTestCase {
.coordinate(180, 0)
);
assertPolygon(builder.close().buildS4J(), true);
assertPolygon(builder.close().buildLucene(), false);
assertPolygon(builder.close().buildGeometry(), false);
}
public void testShapeWithEdgeAlongDateline() {
@ -504,7 +504,7 @@ public class ShapeBuilderTests extends ESTestCase {
);
assertPolygon(builder.close().buildS4J(), true);
assertPolygon(builder.close().buildLucene(), false);
assertPolygon(builder.close().buildGeometry(), false);
// test case 2: test the negative side of the dateline
builder = new PolygonBuilder(new CoordinatesBuilder()
@ -515,7 +515,7 @@ public class ShapeBuilderTests extends ESTestCase {
);
assertPolygon(builder.close().buildS4J(), true);
assertPolygon(builder.close().buildLucene(), false);
assertPolygon(builder.close().buildGeometry(), false);
}
public void testShapeWithBoundaryHoles() {
@ -537,7 +537,7 @@ public class ShapeBuilderTests extends ESTestCase {
));
assertMultiPolygon(builder.close().buildS4J(), true);
assertMultiPolygon(builder.close().buildLucene(), false);
assertMultiPolygon(builder.close().buildGeometry(), false);
// test case 2: test the negative side of the dateline
builder = new PolygonBuilder(
@ -560,7 +560,7 @@ public class ShapeBuilderTests extends ESTestCase {
));
assertMultiPolygon(builder.close().buildS4J(), true);
assertMultiPolygon(builder.close().buildLucene(), false);
assertMultiPolygon(builder.close().buildGeometry(), false);
}
public void testShapeWithTangentialHole() {
@ -582,7 +582,7 @@ public class ShapeBuilderTests extends ESTestCase {
));
assertMultiPolygon(builder.close().buildS4J(), true);
assertMultiPolygon(builder.close().buildLucene(), false);
assertMultiPolygon(builder.close().buildGeometry(), false);
}
public void testShapeWithInvalidTangentialHole() {
@ -606,7 +606,7 @@ public class ShapeBuilderTests extends ESTestCase {
e = expectThrows(InvalidShapeException.class, () -> builder.close().buildS4J());
assertThat(e.getMessage(), containsString("interior cannot share more than one point with the exterior"));
e = expectThrows(InvalidShapeException.class, () -> builder.close().buildLucene());
e = expectThrows(InvalidShapeException.class, () -> builder.close().buildGeometry());
assertThat(e.getMessage(), containsString("interior cannot share more than one point with the exterior"));
}
@ -634,7 +634,7 @@ public class ShapeBuilderTests extends ESTestCase {
.coordinate(172, 0)
));
assertMultiPolygon(builder.close().buildS4J(), true);
assertMultiPolygon(builder.close().buildLucene(), false);
assertMultiPolygon(builder.close().buildGeometry(), false);
}
public void testBoundaryShapeWithInvalidTangentialHole() {
@ -657,7 +657,7 @@ public class ShapeBuilderTests extends ESTestCase {
Exception e;
e = expectThrows(InvalidShapeException.class, () -> builder.close().buildS4J());
assertThat(e.getMessage(), containsString("interior cannot share more than one point with the exterior"));
e = expectThrows(InvalidShapeException.class, () -> builder.close().buildLucene());
e = expectThrows(InvalidShapeException.class, () -> builder.close().buildGeometry());
assertThat(e.getMessage(), containsString("interior cannot share more than one point with the exterior"));
}
@ -673,7 +673,7 @@ public class ShapeBuilderTests extends ESTestCase {
);
assertPolygon(builder.close().buildS4J(), true);
assertPolygon(builder.close().buildLucene(), false);
assertPolygon(builder.close().buildGeometry(), false);
}
public void testShapeWithAlternateOrientation() {
@ -686,7 +686,7 @@ public class ShapeBuilderTests extends ESTestCase {
);
assertPolygon(builder.close().buildS4J(), true);
assertPolygon(builder.close().buildLucene(), false);
assertPolygon(builder.close().buildGeometry(), false);
// cw: geo core will convert to ccw across the dateline
builder = new PolygonBuilder(new CoordinatesBuilder()
@ -697,7 +697,7 @@ public class ShapeBuilderTests extends ESTestCase {
);
assertMultiPolygon(builder.close().buildS4J(), true);
assertMultiPolygon(builder.close().buildLucene(), false);
assertMultiPolygon(builder.close().buildGeometry(), false);
}
public void testInvalidShapeWithConsecutiveDuplicatePoints() {
@ -711,7 +711,7 @@ public class ShapeBuilderTests extends ESTestCase {
Exception e = expectThrows(InvalidShapeException.class, () -> builder.close().buildS4J());
assertThat(e.getMessage(), containsString("duplicate consecutive coordinates at: ("));
e = expectThrows(InvalidShapeException.class, () -> builder.close().buildLucene());
e = expectThrows(InvalidShapeException.class, () -> builder.close().buildGeometry());
assertThat(e.getMessage(), containsString("duplicate consecutive coordinates at: ("));
}

View File

@ -37,7 +37,7 @@ import java.io.IOException;
import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode;
public abstract class AbstractShapeBuilderTestCase<SB extends ShapeBuilder<?,?>> extends ESTestCase {
public abstract class AbstractShapeBuilderTestCase<SB extends ShapeBuilder<?,?,?>> extends ESTestCase {
private static final int NUMBER_OF_TESTBUILDERS = 20;
private static NamedWriteableRegistry namedWriteableRegistry;
@ -81,7 +81,7 @@ public abstract class AbstractShapeBuilderTestCase<SB extends ShapeBuilder<?,?>>
XContentBuilder shuffled = shuffleXContent(builder);
try (XContentParser shapeContentParser = createParser(shuffled)) {
shapeContentParser.nextToken();
ShapeBuilder<?, ?> parsedShape = ShapeParser.parse(shapeContentParser);
ShapeBuilder<?, ?, ?> parsedShape = ShapeParser.parse(shapeContentParser);
assertNotSame(testShape, parsedShape);
assertEquals(testShape, parsedShape);
assertEquals(testShape.hashCode(), parsedShape.hashCode());

View File

@ -69,7 +69,7 @@ public class GeometryCollectionBuilderTests extends AbstractShapeBuilderTestCase
GeometryCollectionBuilder mutation = copyShape(original);
if (mutation.shapes.size() > 0) {
int shapePosition = randomIntBetween(0, mutation.shapes.size() - 1);
ShapeBuilder<?, ?> shapeToChange = mutation.shapes.get(shapePosition);
ShapeBuilder<?, ?, ?> shapeToChange = mutation.shapes.get(shapePosition);
switch (shapeToChange.type()) {
case POINT:
shapeToChange = PointBuilderTests.mutate((PointBuilder) shapeToChange);

View File

@ -187,7 +187,7 @@ public class ExternalMapper extends FieldMapper {
// Let's add a Dummy Shape
PointBuilder pb = new PointBuilder(-100, 45);
if (shapeMapper instanceof GeoShapeFieldMapper) {
shapeMapper.parse(context.createExternalValueContext(pb.buildLucene()));
shapeMapper.parse(context.createExternalValueContext(pb.buildGeometry()));
} else {
shapeMapper.parse(context.createExternalValueContext(pb.buildS4J()));
}

View File

@ -63,7 +63,7 @@ public class GeoPolygonQueryBuilderTests extends AbstractQueryTestCase<GeoPolygo
}
private static List<GeoPoint> randomPolygon() {
ShapeBuilder<?, ?> shapeBuilder = null;
ShapeBuilder<?, ?, ?> shapeBuilder = null;
// This is a temporary fix because sometimes the RandomShapeGenerator
// returns null. This is if there is an error generating the polygon. So
// in this case keep trying until we successfully generate one

View File

@ -63,7 +63,7 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
protected static String indexedShapePath;
protected static String indexedShapeIndex;
protected static String indexedShapeRouting;
protected static ShapeBuilder<?, ?> indexedShapeToReturn;
protected static ShapeBuilder<?, ?, ?> indexedShapeToReturn;
protected String fieldName() {
return GEO_SHAPE_FIELD_NAME;
@ -88,7 +88,7 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
// LatLonShape does not support MultiPoint queries
RandomShapeGenerator.ShapeType shapeType =
randomFrom(ShapeType.POINT, ShapeType.LINESTRING, ShapeType.MULTILINESTRING, ShapeType.POLYGON);
ShapeBuilder<?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
ShapeBuilder<?, ?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
GeoShapeQueryBuilder builder;
clearShapeFields();
if (indexedShape == false) {
@ -174,7 +174,7 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
}
public void testNoFieldName() throws Exception {
ShapeBuilder<?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null);
ShapeBuilder<?, ?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new GeoShapeQueryBuilder(null, shape));
assertEquals("fieldName is required", e.getMessage());
}
@ -190,7 +190,7 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
}
public void testNoRelation() throws IOException {
ShapeBuilder<?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null);
ShapeBuilder<?, ?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null);
GeoShapeQueryBuilder builder = new GeoShapeQueryBuilder(fieldName(), shape);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder.relation(null));
assertEquals("No Shape Relation defined", e.getMessage());
@ -255,7 +255,7 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
public void testIgnoreUnmapped() throws IOException {
ShapeType shapeType = ShapeType.randomType(random());
ShapeBuilder<?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
ShapeBuilder<?, ?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
final GeoShapeQueryBuilder queryBuilder = new GeoShapeQueryBuilder("unmapped", shape);
queryBuilder.ignoreUnmapped(true);
Query query = queryBuilder.toQuery(createShardContext());
@ -270,7 +270,7 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
public void testWrongFieldType() throws IOException {
ShapeType shapeType = ShapeType.randomType(random());
ShapeBuilder<?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
ShapeBuilder<?, ?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
final GeoShapeQueryBuilder queryBuilder = new GeoShapeQueryBuilder(STRING_FIELD_NAME, shape);
QueryShardException e = expectThrows(QueryShardException.class, () -> queryBuilder.toQuery(createShardContext()));
assertThat(e.getMessage(), containsString("Field [mapped_string] is not of type [geo_shape] but of type [text]"));

View File

@ -51,7 +51,7 @@ public class LegacyGeoShapeFieldQueryTests extends GeoShapeQueryBuilderTests {
@Override
protected GeoShapeQueryBuilder doCreateTestQueryBuilder(boolean indexedShape) {
ShapeType shapeType = ShapeType.randomType(random());
ShapeBuilder<?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
ShapeBuilder<?, ?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null, shapeType);
GeoShapeQueryBuilder builder;
clearShapeFields();
if (indexedShape == false) {
@ -93,7 +93,7 @@ public class LegacyGeoShapeFieldQueryTests extends GeoShapeQueryBuilderTests {
}
public void testInvalidRelation() throws IOException {
ShapeBuilder<?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null);
ShapeBuilder<?, ?, ?> shape = RandomShapeGenerator.createShapeWithin(random(), null);
GeoShapeQueryBuilder builder = new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, shape);
builder.strategy(SpatialStrategy.TERM);
expectThrows(IllegalArgumentException.class, () -> builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.WITHIN)));

View File

@ -24,6 +24,7 @@ import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.parsers.ShapeParser;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.geo.geometry.MultiLine;
import org.hamcrest.Matcher;
import org.junit.Assert;
import org.locationtech.jts.geom.Coordinate;
@ -221,7 +222,9 @@ public class ElasticsearchGeoAssertions {
|| (s1 instanceof GeoPoint && s2 instanceof GeoPoint)) {
Assert.assertEquals(s1, s2);
} else if (s1 instanceof Object[] && s2 instanceof Object[]) {
Assert.assertArrayEquals((Object[])s1, (Object[])s2);
Assert.assertArrayEquals((Object[]) s1, (Object[]) s2);
} else if (s1 instanceof org.elasticsearch.geo.geometry.Geometry && s2 instanceof org.elasticsearch.geo.geometry.Geometry) {
Assert.assertEquals(s1, s2);
} else {
//We want to know the type of the shape because we test shape equality in a special way...
//... in particular we test that one ring is equivalent to another ring even if the points are rotated or reversed.
@ -242,7 +245,7 @@ public class ElasticsearchGeoAssertions {
unwrapJTS(shape) instanceof MultiPolygon);
} else {
assertTrue("expected Polygon[] but found " + shape.getClass().getName(),
shape instanceof org.apache.lucene.geo.Polygon[]);
shape instanceof org.elasticsearch.geo.geometry.MultiPolygon);
}
}
@ -252,7 +255,7 @@ public class ElasticsearchGeoAssertions {
+ unwrapJTS(shape).getClass().getName(), unwrapJTS(shape) instanceof Polygon);
} else {
assertTrue("expected Polygon but found " + shape.getClass().getName(),
shape instanceof org.apache.lucene.geo.Polygon);
shape instanceof org.elasticsearch.geo.geometry.Polygon);
}
}
@ -262,7 +265,7 @@ public class ElasticsearchGeoAssertions {
+ unwrapJTS(shape).getClass().getName(), unwrapJTS(shape) instanceof LineString);
} else {
assertTrue("expected Line but found " + shape.getClass().getName(),
shape instanceof org.apache.lucene.geo.Line);
shape instanceof org.elasticsearch.geo.geometry.Line);
}
}
@ -272,7 +275,7 @@ public class ElasticsearchGeoAssertions {
+ unwrapJTS(shape).getClass().getName(), unwrapJTS(shape) instanceof MultiLineString);
} else {
assertTrue("expected Line[] but found " + shape.getClass().getName(),
shape instanceof org.apache.lucene.geo.Line[]);
shape instanceof MultiLine);
}
}