Geo: Add validation of shapes to shape builders
So far the validation of geo shapes was only taking place in the parse methods in ShapeBuilder. With the recent refactoring we no longer can rely on shapes being parsed from json, so the same kind of validation should take place when just using the java api. A lot of validation concerns the number of points a shape needs to have in order to be valid. Since this is not possible with current builders where points can be added one by one, the builder constructors are changed to require the mandatory parameters and validate those already at construction time. To help with constructing longer lists of points, a new utility PointsListBuilder is instroduces which can produce list of coordinates accepted by most of the other shape builder constructors. Also adding tests for invalid shape exceptions to the already existing shape builder tests.
This commit is contained in:
parent
d8af49eb91
commit
57c579e7b7
|
@ -37,10 +37,18 @@ public class CircleBuilder extends ShapeBuilder {
|
|||
|
||||
public static final CircleBuilder PROTOTYPE = new CircleBuilder();
|
||||
|
||||
private DistanceUnit unit;
|
||||
private DistanceUnit unit = DistanceUnit.DEFAULT;
|
||||
private double radius;
|
||||
private Coordinate center;
|
||||
|
||||
/**
|
||||
* Creates a circle centered at [0.0, 0.0].
|
||||
* Center can be changed by calling {@link #center(Coordinate)} later.
|
||||
*/
|
||||
public CircleBuilder() {
|
||||
this.center = ZERO_ZERO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the center of the circle
|
||||
*
|
||||
|
|
|
@ -32,33 +32,22 @@ public class EnvelopeBuilder extends ShapeBuilder {
|
|||
|
||||
public static final GeoShapeType TYPE = GeoShapeType.ENVELOPE;
|
||||
|
||||
public static final EnvelopeBuilder PROTOTYPE = new EnvelopeBuilder();
|
||||
public static final EnvelopeBuilder PROTOTYPE = new EnvelopeBuilder(new Coordinate(-1.0, 1.0), new Coordinate(1.0, -1.0));
|
||||
|
||||
private Coordinate topLeft;
|
||||
private Coordinate bottomRight;
|
||||
|
||||
public EnvelopeBuilder topLeft(Coordinate topLeft) {
|
||||
public EnvelopeBuilder(Coordinate topLeft, Coordinate bottomRight) {
|
||||
Objects.requireNonNull(topLeft, "topLeft of envelope cannot be null");
|
||||
Objects.requireNonNull(bottomRight, "bottomRight of envelope cannot be null");
|
||||
this.topLeft = topLeft;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EnvelopeBuilder topLeft(double longitude, double latitude) {
|
||||
return topLeft(coordinate(longitude, latitude));
|
||||
this.bottomRight = bottomRight;
|
||||
}
|
||||
|
||||
public Coordinate topLeft() {
|
||||
return this.topLeft;
|
||||
}
|
||||
|
||||
public EnvelopeBuilder bottomRight(Coordinate bottomRight) {
|
||||
this.bottomRight = bottomRight;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EnvelopeBuilder bottomRight(double longitude, double latitude) {
|
||||
return bottomRight(coordinate(longitude, latitude));
|
||||
}
|
||||
|
||||
public Coordinate bottomRight() {
|
||||
return this.bottomRight;
|
||||
}
|
||||
|
@ -110,8 +99,6 @@ public class EnvelopeBuilder extends ShapeBuilder {
|
|||
|
||||
@Override
|
||||
public EnvelopeBuilder readFrom(StreamInput in) throws IOException {
|
||||
return new EnvelopeBuilder()
|
||||
.topLeft(readCoordinateFrom(in))
|
||||
.bottomRight(readCoordinateFrom(in));
|
||||
return new EnvelopeBuilder(readCoordinateFrom(in), readCoordinateFrom(in));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,11 +33,35 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class LineStringBuilder extends PointCollection<LineStringBuilder> {
|
||||
|
||||
/**
|
||||
* Construct a new LineString.
|
||||
* Per GeoJSON spec (http://geojson.org/geojson-spec.html#linestring)
|
||||
* a LineString must contain two or more positions
|
||||
* @param points the initial list of points
|
||||
* @throw {@link IllegalArgumentException} if there are less then two points defined
|
||||
*/
|
||||
public LineStringBuilder(List<Coordinate> points) {
|
||||
super(points);
|
||||
if (points.size() < 2) {
|
||||
throw new IllegalArgumentException("invalid number of points in LineString (found [" + points.size()+ "] - must be >= 2)");
|
||||
}
|
||||
}
|
||||
|
||||
public static final GeoShapeType TYPE = GeoShapeType.LINESTRING;
|
||||
|
||||
public static final LineStringBuilder PROTOTYPE = new LineStringBuilder();
|
||||
public static final LineStringBuilder PROTOTYPE = new LineStringBuilder(new PointListBuilder().point(0.0, 0.0).point(1.0, 1.0).list());
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
|
@ -172,11 +196,12 @@ public class LineStringBuilder extends PointCollection<LineStringBuilder> {
|
|||
|
||||
@Override
|
||||
public LineStringBuilder readFrom(StreamInput in) throws IOException {
|
||||
LineStringBuilder lineStringBuilder = new LineStringBuilder();
|
||||
PointListBuilder pl = new PointListBuilder();
|
||||
int size = in.readVInt();
|
||||
for (int i=0; i < size; i++) {
|
||||
lineStringBuilder.point(readCoordinateFrom(in));
|
||||
pl.point(readCoordinateFrom(in));
|
||||
}
|
||||
LineStringBuilder lineStringBuilder = new LineStringBuilder(pl.list());
|
||||
return lineStringBuilder;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@ import org.elasticsearch.common.io.stream.StreamInput;
|
|||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
@ -46,7 +50,7 @@ public class MultiLineStringBuilder extends ShapeBuilder {
|
|||
}
|
||||
|
||||
public MultiLineStringBuilder linestring(Coordinate[] coordinates) {
|
||||
return this.linestring(new LineStringBuilder().points(coordinates));
|
||||
return this.linestring(new LineStringBuilder(new PointListBuilder().points(coordinates).list()));
|
||||
}
|
||||
|
||||
public Coordinate[][] coordinates() {
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
|
@ -36,7 +37,15 @@ public class MultiPointBuilder extends PointCollection<MultiPointBuilder> {
|
|||
|
||||
public static final GeoShapeType TYPE = GeoShapeType.MULTIPOINT;
|
||||
|
||||
public final static MultiPointBuilder PROTOTYPE = new MultiPointBuilder();
|
||||
public final static MultiPointBuilder PROTOTYPE = new MultiPointBuilder(Arrays.asList(new Coordinate[]{new Coordinate(0.0, 0.0)}));
|
||||
|
||||
/**
|
||||
* Create a new {@link MultiPointBuilder}.
|
||||
* @param points needs at least two points to be valid, otherwise will throw an exception
|
||||
*/
|
||||
public MultiPointBuilder(List<Coordinate> points) {
|
||||
super(points);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
|
@ -93,11 +102,13 @@ public class MultiPointBuilder extends PointCollection<MultiPointBuilder> {
|
|||
|
||||
@Override
|
||||
public MultiPointBuilder readFrom(StreamInput in) throws IOException {
|
||||
MultiPointBuilder multiPointBuilder = new MultiPointBuilder();
|
||||
int size = in.readVInt();
|
||||
List<Coordinate> points = new ArrayList<Coordinate>(size);
|
||||
for (int i=0; i < size; i++) {
|
||||
multiPointBuilder.point(readCoordinateFrom(in));
|
||||
points.add(readCoordinateFrom(in));
|
||||
}
|
||||
MultiPointBuilder multiPointBuilder = new MultiPointBuilder(points);
|
||||
|
||||
return multiPointBuilder;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.common.geo.builders;
|
|||
|
||||
import com.spatial4j.core.shape.Shape;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
import org.elasticsearch.common.geo.XShapeCollection;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
|
@ -28,6 +29,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
@ -58,8 +60,7 @@ public class MultiPolygonBuilder extends ShapeBuilder {
|
|||
* {@link MultiPolygonBuilder} to the polygon if polygon has different orientation.
|
||||
*/
|
||||
public MultiPolygonBuilder polygon(PolygonBuilder polygon) {
|
||||
PolygonBuilder pb = new PolygonBuilder(this.orientation);
|
||||
pb.points(polygon.shell().coordinates(false));
|
||||
PolygonBuilder pb = new PolygonBuilder(Arrays.asList(polygon.shell().coordinates(false)), this.orientation);
|
||||
for (LineStringBuilder hole : polygon.holes()) {
|
||||
pb.hole(hole);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.common.geo.builders;
|
|||
|
||||
import com.spatial4j.core.shape.Point;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
@ -35,6 +36,13 @@ public class PointBuilder extends ShapeBuilder {
|
|||
|
||||
private Coordinate coordinate;
|
||||
|
||||
/**
|
||||
* Create a point at [0.0,0.0]
|
||||
*/
|
||||
public PointBuilder() {
|
||||
this.coordinate = ZERO_ZERO;
|
||||
}
|
||||
|
||||
public PointBuilder coordinate(Coordinate coordinate) {
|
||||
this.coordinate = coordinate;
|
||||
return this;
|
||||
|
|
|
@ -20,25 +20,30 @@
|
|||
package org.elasticsearch.common.geo.builders;
|
||||
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link PointCollection} is an abstract base implementation for all GeoShapes. It simply handles a set of points.
|
||||
*/
|
||||
public abstract class PointCollection<E extends PointCollection<E>> extends ShapeBuilder {
|
||||
|
||||
protected final ArrayList<Coordinate> points;
|
||||
protected final List<Coordinate> points;
|
||||
|
||||
protected PointCollection() {
|
||||
this(new ArrayList<Coordinate>());
|
||||
}
|
||||
|
||||
protected PointCollection(ArrayList<Coordinate> points) {
|
||||
/**
|
||||
* Construct a new collection of points.
|
||||
* @param points an initial list of points
|
||||
* @throws IllegalArgumentException if points is <tt>null</tt> or empty
|
||||
*/
|
||||
protected PointCollection(List<Coordinate> points) {
|
||||
if (points == null || points.size() == 0) {
|
||||
throw new IllegalArgumentException("cannot create point collection with empty set of points");
|
||||
}
|
||||
this.points = points;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.elasticsearch.common.geo.builders;
|
||||
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A builder for a list of points (of {@link Coordinate} type).
|
||||
* Enables chaining of individual points either as long/lat pairs
|
||||
* or as {@link Coordinate} elements, arrays or collections.
|
||||
*/
|
||||
public class PointListBuilder {
|
||||
|
||||
private final List<Coordinate> points = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Add a new point to the collection
|
||||
* @param longitude longitude of the coordinate
|
||||
* @param latitude latitude of the coordinate
|
||||
* @return this
|
||||
*/
|
||||
public PointListBuilder point(double longitude, double latitude) {
|
||||
return this.point(new Coordinate(longitude, latitude));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new point to the collection
|
||||
* @param coordinate coordinate of the point
|
||||
* @return this
|
||||
*/
|
||||
public PointListBuilder point(Coordinate coordinate) {
|
||||
this.points.add(coordinate);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a array of points to the collection
|
||||
*
|
||||
* @param coordinates array of {@link Coordinate}s to add
|
||||
* @return this
|
||||
*/
|
||||
public PointListBuilder points(Coordinate...coordinates) {
|
||||
return this.points(Arrays.asList(coordinates));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a collection of points to the collection
|
||||
*
|
||||
* @param coordinates array of {@link Coordinate}s to add
|
||||
* @return this
|
||||
*/
|
||||
public PointListBuilder points(Collection<? extends Coordinate> coordinates) {
|
||||
this.points.addAll(coordinates);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the current list of points by adding the starting point as the end point
|
||||
* if they are not already the same
|
||||
*/
|
||||
public PointListBuilder close() {
|
||||
Coordinate start = points.get(0);
|
||||
Coordinate end = points.get(points.size()-1);
|
||||
if(start.x != end.x || start.y != end.y) {
|
||||
points.add(start);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current list of points
|
||||
*/
|
||||
public List<Coordinate> list() {
|
||||
return new ArrayList<>(this.points);
|
||||
}
|
||||
}
|
|
@ -52,7 +52,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
public class PolygonBuilder extends ShapeBuilder {
|
||||
|
||||
public static final GeoShapeType TYPE = GeoShapeType.POLYGON;
|
||||
public static final PolygonBuilder PROTOTYPE = new PolygonBuilder();
|
||||
public static final PolygonBuilder PROTOTYPE = new PolygonBuilder(new PointListBuilder().point(0.0, 0.0).point(0.0, 1.0)
|
||||
.point(1.0, 0.0).point(0.0, 0.0).list());
|
||||
|
||||
private static final Coordinate[][] EMPTY = new Coordinate[0][];
|
||||
|
||||
|
@ -64,55 +65,40 @@ public class PolygonBuilder extends ShapeBuilder {
|
|||
// List of line strings defining the holes of the polygon
|
||||
private final ArrayList<LineStringBuilder> holes = new ArrayList<>();
|
||||
|
||||
public PolygonBuilder() {
|
||||
this(Orientation.RIGHT);
|
||||
public PolygonBuilder(List<Coordinate> points, Orientation orientation) {
|
||||
this(points, orientation, false);
|
||||
}
|
||||
|
||||
public PolygonBuilder(Orientation orientation) {
|
||||
this(new ArrayList<Coordinate>(), orientation);
|
||||
}
|
||||
|
||||
public PolygonBuilder(ArrayList<Coordinate> points, Orientation orientation) {
|
||||
public PolygonBuilder(List<Coordinate> points, Orientation orientation, boolean coerce) {
|
||||
this.orientation = orientation;
|
||||
this.shell = new LineStringBuilder().points(points);
|
||||
this.shell = validateLinearRing(new LineStringBuilder(points), coerce);
|
||||
}
|
||||
|
||||
public PolygonBuilder(List<Coordinate> points) {
|
||||
this(points, Orientation.RIGHT);
|
||||
}
|
||||
|
||||
public Orientation orientation() {
|
||||
return this.orientation;
|
||||
}
|
||||
|
||||
public PolygonBuilder point(double longitude, double latitude) {
|
||||
shell.point(longitude, latitude);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a point to the shell of the polygon
|
||||
* @param coordinate coordinate of the new point
|
||||
* @return this
|
||||
*/
|
||||
public PolygonBuilder point(Coordinate coordinate) {
|
||||
shell.point(coordinate);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an array of points to the shell of the polygon
|
||||
* @param coordinates coordinates of the new points to add
|
||||
* @return this
|
||||
*/
|
||||
public PolygonBuilder points(Coordinate...coordinates) {
|
||||
shell.points(coordinates);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new hole to the polygon
|
||||
* @param hole linear ring defining the hole
|
||||
* @return this
|
||||
*/
|
||||
public PolygonBuilder hole(LineStringBuilder hole) {
|
||||
holes.add(hole);
|
||||
return this.hole(hole, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new hole to the polygon
|
||||
* @param hole linear ring defining the hole
|
||||
* @param coerce if set to true, will close the hole by adding starting point as end point
|
||||
* @return this
|
||||
*/
|
||||
public PolygonBuilder hole(LineStringBuilder hole, boolean coerce) {
|
||||
holes.add(validateLinearRing(hole, coerce));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -138,6 +124,30 @@ public class PolygonBuilder extends ShapeBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
private static LineStringBuilder validateLinearRing(LineStringBuilder linestring, boolean coerce) {
|
||||
/**
|
||||
* Per GeoJSON spec (http://geojson.org/geojson-spec.html#linestring)
|
||||
* A LinearRing is closed LineString with 4 or more positions. The first and last positions
|
||||
* are equivalent (they represent equivalent points). Though a LinearRing is not explicitly
|
||||
* represented as a GeoJSON geometry type, it is referred to in the Polygon geometry type definition.
|
||||
*/
|
||||
int numValidPts;
|
||||
List<Coordinate> points = linestring.points;
|
||||
if (points.size() < (numValidPts = (coerce) ? 3 : 4)) {
|
||||
throw new IllegalArgumentException(
|
||||
"invalid number of points in LinearRing (found [" + points.size() + "] - must be >= " + numValidPts + ")");
|
||||
}
|
||||
|
||||
if (!points.get(0).equals(points.get(points.size() - 1))) {
|
||||
if (coerce) {
|
||||
points.add(points.get(0));
|
||||
} else {
|
||||
throw new IllegalArgumentException("invalid LinearRing found (coordinates are not closed)");
|
||||
}
|
||||
}
|
||||
return linestring;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates only 1 vertex is tangential (shared) between the interior and exterior of a polygon
|
||||
*/
|
||||
|
@ -235,7 +245,7 @@ public class PolygonBuilder extends ShapeBuilder {
|
|||
return factory.createPolygon(shell, holes);
|
||||
}
|
||||
|
||||
protected static LinearRing linearRing(GeometryFactory factory, ArrayList<Coordinate> coordinates) {
|
||||
protected static LinearRing linearRing(GeometryFactory factory, List<Coordinate> coordinates) {
|
||||
return factory.createLinearRing(coordinates.toArray(new Coordinate[coordinates.size()]));
|
||||
}
|
||||
|
||||
|
@ -711,8 +721,8 @@ public class PolygonBuilder extends ShapeBuilder {
|
|||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
orientation.writeTo(out);
|
||||
shell.writeTo(out);
|
||||
orientation.writeTo(out);
|
||||
out.writeVInt(holes.size());
|
||||
for (LineStringBuilder hole : holes) {
|
||||
hole.writeTo(out);
|
||||
|
@ -721,8 +731,9 @@ public class PolygonBuilder extends ShapeBuilder {
|
|||
|
||||
@Override
|
||||
public PolygonBuilder readFrom(StreamInput in) throws IOException {
|
||||
PolygonBuilder polyBuilder = new PolygonBuilder(Orientation.readFrom(in));
|
||||
polyBuilder.shell = LineStringBuilder.PROTOTYPE.readFrom(in);
|
||||
LineStringBuilder shell = LineStringBuilder.PROTOTYPE.readFrom(in);
|
||||
Orientation orientation = Orientation.readFrom(in);
|
||||
PolygonBuilder polyBuilder = new PolygonBuilder(shell.points, orientation);
|
||||
int holes = in.readVInt();
|
||||
for (int i = 0; i < holes; i++) {
|
||||
polyBuilder.hole(LineStringBuilder.PROTOTYPE.readFrom(in));
|
||||
|
|
|
@ -64,6 +64,11 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
|
|||
}
|
||||
|
||||
public static final double DATELINE = 180;
|
||||
|
||||
/**
|
||||
* coordinate at [0.0, 0.0]
|
||||
*/
|
||||
public static final Coordinate ZERO_ZERO = new Coordinate(0.0, 0.0);
|
||||
// TODO how might we use JtsSpatialContextFactory to configure the context (esp. for non-geo)?
|
||||
public static final JtsSpatialContext SPATIAL_CONTEXT = JtsSpatialContext.GEO;
|
||||
public static final GeometryFactory FACTORY = SPATIAL_CONTEXT.getGeometryFactory();
|
||||
|
@ -569,7 +574,7 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
|
|||
uL = new Coordinate(Math.min(uL.x, lR.x), Math.max(uL.y, lR.y));
|
||||
lR = new Coordinate(Math.max(uLtmp.x, lR.x), Math.min(uLtmp.y, lR.y));
|
||||
}
|
||||
return ShapeBuilders.newEnvelope().topLeft(uL).bottomRight(lR);
|
||||
return ShapeBuilders.newEnvelope(uL, lR);
|
||||
}
|
||||
|
||||
protected static void validateMultiPointNode(CoordinateNode coordinates) {
|
||||
|
@ -589,12 +594,11 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
|
|||
|
||||
protected static MultiPointBuilder parseMultiPoint(CoordinateNode coordinates) {
|
||||
validateMultiPointNode(coordinates);
|
||||
|
||||
MultiPointBuilder points = new MultiPointBuilder();
|
||||
PointListBuilder points = new PointListBuilder();
|
||||
for (CoordinateNode node : coordinates.children) {
|
||||
points.point(node.coordinate);
|
||||
}
|
||||
return points;
|
||||
return new MultiPointBuilder(points.list());
|
||||
}
|
||||
|
||||
protected static LineStringBuilder parseLineString(CoordinateNode coordinates) {
|
||||
|
@ -607,11 +611,11 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
|
|||
throw new ElasticsearchParseException("invalid number of points in LineString (found [{}] - must be >= 2)", coordinates.children.size());
|
||||
}
|
||||
|
||||
LineStringBuilder line = ShapeBuilders.newLineString();
|
||||
PointListBuilder line = new PointListBuilder();
|
||||
for (CoordinateNode node : coordinates.children) {
|
||||
line.point(node.coordinate);
|
||||
}
|
||||
return line;
|
||||
return ShapeBuilders.newLineString(line.list());
|
||||
}
|
||||
|
||||
protected static MultiLineStringBuilder parseMultiLine(CoordinateNode coordinates) {
|
||||
|
|
|
@ -21,6 +21,8 @@ package org.elasticsearch.common.geo.builders;
|
|||
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A collection of static methods for creating ShapeBuilders.
|
||||
*/
|
||||
|
@ -50,16 +52,16 @@ public class ShapeBuilders {
|
|||
* Create a new set of points
|
||||
* @return new {@link MultiPointBuilder}
|
||||
*/
|
||||
public static MultiPointBuilder newMultiPoint() {
|
||||
return new MultiPointBuilder();
|
||||
public static MultiPointBuilder newMultiPoint(List<Coordinate> points) {
|
||||
return new MultiPointBuilder(points);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new lineString
|
||||
* @return a new {@link LineStringBuilder}
|
||||
*/
|
||||
public static LineStringBuilder newLineString() {
|
||||
return new LineStringBuilder();
|
||||
public static LineStringBuilder newLineString(List<Coordinate> list) {
|
||||
return new LineStringBuilder(list);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,16 +76,8 @@ public class ShapeBuilders {
|
|||
* Create a new Polygon
|
||||
* @return a new {@link PointBuilder}
|
||||
*/
|
||||
public static PolygonBuilder newPolygon() {
|
||||
return new PolygonBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Polygon
|
||||
* @return a new {@link PointBuilder}
|
||||
*/
|
||||
public static PolygonBuilder newPolygon(ShapeBuilder.Orientation orientation) {
|
||||
return new PolygonBuilder(orientation);
|
||||
public static PolygonBuilder newPolygon(List<Coordinate> shell) {
|
||||
return new PolygonBuilder(shell);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,7 +118,7 @@ public class ShapeBuilders {
|
|||
*
|
||||
* @return a new {@link EnvelopeBuilder}
|
||||
*/
|
||||
public static EnvelopeBuilder newEnvelope() {
|
||||
return new EnvelopeBuilder();
|
||||
public static EnvelopeBuilder newEnvelope(Coordinate topLeft, Coordinate bottomRight) {
|
||||
return new EnvelopeBuilder(topLeft, bottomRight);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import com.vividsolutions.jts.geom.LinearRing;
|
|||
import com.vividsolutions.jts.geom.MultiLineString;
|
||||
import com.vividsolutions.jts.geom.Point;
|
||||
import com.vividsolutions.jts.geom.Polygon;
|
||||
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
|
|
|
@ -29,6 +29,7 @@ import com.vividsolutions.jts.geom.Coordinate;
|
|||
import com.vividsolutions.jts.geom.LineString;
|
||||
import com.vividsolutions.jts.geom.Polygon;
|
||||
import org.elasticsearch.common.geo.builders.LineStringBuilder;
|
||||
import org.elasticsearch.common.geo.builders.PointListBuilder;
|
||||
import org.elasticsearch.common.geo.builders.PolygonBuilder;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilders;
|
||||
|
@ -50,7 +51,7 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testNewRectangle() {
|
||||
Rectangle rectangle = ShapeBuilders.newEnvelope().topLeft(-45, 30).bottomRight(45, -30).build();
|
||||
Rectangle rectangle = ShapeBuilders.newEnvelope(new Coordinate(-45, 30), new Coordinate(45, -30)).build();
|
||||
assertEquals(-45D, rectangle.getMinX(), 0.0d);
|
||||
assertEquals(-30D, rectangle.getMinY(), 0.0d);
|
||||
assertEquals(45D, rectangle.getMaxX(), 0.0d);
|
||||
|
@ -58,12 +59,12 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testNewPolygon() {
|
||||
Polygon polygon = ShapeBuilders.newPolygon()
|
||||
Polygon polygon = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-45, 30)
|
||||
.point(45, 30)
|
||||
.point(45, -30)
|
||||
.point(-45, -30)
|
||||
.point(-45, 30).toPolygon();
|
||||
.point(-45, 30).list()).toPolygon();
|
||||
|
||||
LineString exterior = polygon.getExteriorRing();
|
||||
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
|
||||
|
@ -73,12 +74,12 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testNewPolygon_coordinate() {
|
||||
Polygon polygon = ShapeBuilders.newPolygon()
|
||||
Polygon polygon = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(new Coordinate(-45, 30))
|
||||
.point(new Coordinate(45, 30))
|
||||
.point(new Coordinate(45, -30))
|
||||
.point(new Coordinate(-45, -30))
|
||||
.point(new Coordinate(-45, 30)).toPolygon();
|
||||
.point(new Coordinate(-45, 30)).list()).toPolygon();
|
||||
|
||||
LineString exterior = polygon.getExteriorRing();
|
||||
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
|
||||
|
@ -88,8 +89,9 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testNewPolygon_coordinates() {
|
||||
Polygon polygon = ShapeBuilders.newPolygon()
|
||||
.points(new Coordinate(-45, 30), new Coordinate(45, 30), new Coordinate(45, -30), new Coordinate(-45, -30), new Coordinate(-45, 30)).toPolygon();
|
||||
Polygon polygon = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.points(new Coordinate(-45, 30), new Coordinate(45, 30), new Coordinate(45, -30), new Coordinate(-45, -30), new Coordinate(-45, 30))
|
||||
.list()).toPolygon();
|
||||
|
||||
LineString exterior = polygon.getExteriorRing();
|
||||
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
|
||||
|
@ -100,7 +102,7 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
|
||||
public void testLineStringBuilder() {
|
||||
// Building a simple LineString
|
||||
ShapeBuilders.newLineString()
|
||||
ShapeBuilders.newLineString(new PointListBuilder()
|
||||
.point(-130.0, 55.0)
|
||||
.point(-130.0, -40.0)
|
||||
.point(-15.0, -40.0)
|
||||
|
@ -108,10 +110,10 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
.point(-45.0, 50.0)
|
||||
.point(-45.0, -15.0)
|
||||
.point(-110.0, -15.0)
|
||||
.point(-110.0, 55.0).build();
|
||||
.point(-110.0, 55.0).list()).build();
|
||||
|
||||
// Building a linestring that needs to be wrapped
|
||||
ShapeBuilders.newLineString()
|
||||
ShapeBuilders.newLineString(new PointListBuilder()
|
||||
.point(100.0, 50.0)
|
||||
.point(110.0, -40.0)
|
||||
.point(240.0, -40.0)
|
||||
|
@ -120,66 +122,73 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
.point(200.0, -30.0)
|
||||
.point(130.0, -30.0)
|
||||
.point(130.0, 60.0)
|
||||
.list())
|
||||
.build();
|
||||
|
||||
// Building a lineString on the dateline
|
||||
ShapeBuilders.newLineString()
|
||||
ShapeBuilders.newLineString(new PointListBuilder()
|
||||
.point(-180.0, 80.0)
|
||||
.point(-180.0, 40.0)
|
||||
.point(-180.0, -40.0)
|
||||
.point(-180.0, -80.0)
|
||||
.list())
|
||||
.build();
|
||||
|
||||
// Building a lineString on the dateline
|
||||
ShapeBuilders.newLineString()
|
||||
ShapeBuilders.newLineString(new PointListBuilder()
|
||||
.point(180.0, 80.0)
|
||||
.point(180.0, 40.0)
|
||||
.point(180.0, -40.0)
|
||||
.point(180.0, -80.0)
|
||||
.list())
|
||||
.build();
|
||||
}
|
||||
|
||||
public void testMultiLineString() {
|
||||
ShapeBuilders.newMultiLinestring()
|
||||
.linestring(new LineStringBuilder()
|
||||
.linestring(new LineStringBuilder(new PointListBuilder()
|
||||
.point(-100.0, 50.0)
|
||||
.point(50.0, 50.0)
|
||||
.point(50.0, 20.0)
|
||||
.point(-100.0, 20.0)
|
||||
.list())
|
||||
)
|
||||
.linestring(new LineStringBuilder()
|
||||
.linestring(new LineStringBuilder(new PointListBuilder()
|
||||
.point(-100.0, 20.0)
|
||||
.point(50.0, 20.0)
|
||||
.point(50.0, 0.0)
|
||||
.point(-100.0, 0.0)
|
||||
.list())
|
||||
)
|
||||
.build();
|
||||
|
||||
// LineString that needs to be wrappped
|
||||
ShapeBuilders.newMultiLinestring()
|
||||
.linestring(new LineStringBuilder()
|
||||
.linestring(new LineStringBuilder(new PointListBuilder()
|
||||
.point(150.0, 60.0)
|
||||
.point(200.0, 60.0)
|
||||
.point(200.0, 40.0)
|
||||
.point(150.0, 40.0)
|
||||
.list())
|
||||
)
|
||||
.linestring(new LineStringBuilder()
|
||||
.linestring(new LineStringBuilder(new PointListBuilder()
|
||||
.point(150.0, 20.0)
|
||||
.point(200.0, 20.0)
|
||||
.point(200.0, 0.0)
|
||||
.point(150.0, 0.0)
|
||||
.list())
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
||||
public void testPolygonSelfIntersection() {
|
||||
try {
|
||||
ShapeBuilders.newPolygon()
|
||||
ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-40.0, 50.0)
|
||||
.point(40.0, 50.0)
|
||||
.point(-40.0, -50.0)
|
||||
.point(40.0, -50.0)
|
||||
.close().build();
|
||||
.point(40.0, -50.0).close().list())
|
||||
.build();
|
||||
fail("Expected InvalidShapeException");
|
||||
} catch (InvalidShapeException e) {
|
||||
assertThat(e.getMessage(), containsString("Self-intersection at or near point (0.0"));
|
||||
|
@ -212,22 +221,26 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testPolygonWrapping() {
|
||||
Shape shape = ShapeBuilders.newPolygon()
|
||||
Shape shape = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-150.0, 65.0)
|
||||
.point(-250.0, 65.0)
|
||||
.point(-250.0, -65.0)
|
||||
.point(-150.0, -65.0)
|
||||
.close().build();
|
||||
.close()
|
||||
.list())
|
||||
.build();
|
||||
|
||||
assertMultiPolygon(shape);
|
||||
}
|
||||
|
||||
public void testLineStringWrapping() {
|
||||
Shape shape = ShapeBuilders.newLineString()
|
||||
Shape shape = ShapeBuilders.newLineString(new PointListBuilder()
|
||||
.point(-150.0, 65.0)
|
||||
.point(-250.0, 65.0)
|
||||
.point(-250.0, -65.0)
|
||||
.point(-150.0, -65.0)
|
||||
.close()
|
||||
.list())
|
||||
.build();
|
||||
assertMultiLineString(shape);
|
||||
}
|
||||
|
@ -238,7 +251,7 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
// expected results: 3 polygons, 1 with a hole
|
||||
|
||||
// a giant c shape
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(174,0)
|
||||
.point(-176,0)
|
||||
.point(-176,3)
|
||||
|
@ -247,10 +260,11 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
.point(-176,5)
|
||||
.point(-176,8)
|
||||
.point(174,8)
|
||||
.point(174,0);
|
||||
.point(174,0)
|
||||
.list());
|
||||
|
||||
// 3/4 of an embedded 'c', crossing dateline once
|
||||
builder.hole(new LineStringBuilder()
|
||||
builder.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(175, 1)
|
||||
.point(175, 7)
|
||||
.point(-178, 7)
|
||||
|
@ -259,15 +273,17 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
.point(176, 2)
|
||||
.point(179, 2)
|
||||
.point(179,1)
|
||||
.point(175, 1));
|
||||
.point(175, 1)
|
||||
.list()));
|
||||
|
||||
// embedded hole right of the dateline
|
||||
builder.hole(new LineStringBuilder()
|
||||
builder.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(-179, 1)
|
||||
.point(-179, 2)
|
||||
.point(-177, 2)
|
||||
.point(-177,1)
|
||||
.point(-179,1));
|
||||
.point(-179,1)
|
||||
.list()));
|
||||
|
||||
Shape shape = builder.close().build();
|
||||
assertMultiPolygon(shape);
|
||||
|
@ -279,7 +295,7 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
// expected results: 3 polygons, 1 with a hole
|
||||
|
||||
// a giant c shape
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-186,0)
|
||||
.point(-176,0)
|
||||
.point(-176,3)
|
||||
|
@ -288,10 +304,11 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
.point(-176,5)
|
||||
.point(-176,8)
|
||||
.point(-186,8)
|
||||
.point(-186,0);
|
||||
.point(-186,0)
|
||||
.list());
|
||||
|
||||
// 3/4 of an embedded 'c', crossing dateline once
|
||||
builder.hole(new LineStringBuilder()
|
||||
builder.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(-185,1)
|
||||
.point(-181,1)
|
||||
.point(-181,2)
|
||||
|
@ -300,22 +317,24 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
.point(-178,6)
|
||||
.point(-178,7)
|
||||
.point(-185,7)
|
||||
.point(-185,1));
|
||||
.point(-185,1)
|
||||
.list()));
|
||||
|
||||
// embedded hole right of the dateline
|
||||
builder.hole(new LineStringBuilder()
|
||||
builder.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(-179,1)
|
||||
.point(-177,1)
|
||||
.point(-177,2)
|
||||
.point(-179,2)
|
||||
.point(-179,1));
|
||||
.point(-179,1)
|
||||
.list()));
|
||||
|
||||
Shape shape = builder.close().build();
|
||||
assertMultiPolygon(shape);
|
||||
}
|
||||
|
||||
public void testComplexShapeWithHole() {
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-85.0018514,37.1311314)
|
||||
.point(-85.0016645,37.1315293)
|
||||
.point(-85.0016246,37.1317069)
|
||||
|
@ -353,9 +372,10 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
.point(-85.0009461,37.1311684)
|
||||
.point(-85.0011373,37.1311515)
|
||||
.point(-85.0016455,37.1310491)
|
||||
.point(-85.0018514,37.1311314);
|
||||
.point(-85.0018514,37.1311314)
|
||||
.list());
|
||||
|
||||
builder.hole(new LineStringBuilder()
|
||||
builder.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(-85.0000002,37.1317672)
|
||||
.point(-85.0001983,37.1317538)
|
||||
.point(-85.0003378,37.1317582)
|
||||
|
@ -381,39 +401,44 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
.point(-84.9993527,37.1317788)
|
||||
.point(-84.9994931,37.1318061)
|
||||
.point(-84.9996815,37.1317979)
|
||||
.point(-85.0000002,37.1317672));
|
||||
.point(-85.0000002,37.1317672)
|
||||
.list())
|
||||
);
|
||||
|
||||
Shape shape = builder.close().build();
|
||||
assertPolygon(shape);
|
||||
}
|
||||
|
||||
public void testShapeWithHoleAtEdgeEndPoints() {
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-4, 2)
|
||||
.point(4, 2)
|
||||
.point(6, 0)
|
||||
.point(4, -2)
|
||||
.point(-4, -2)
|
||||
.point(-6, 0)
|
||||
.point(-4, 2);
|
||||
.point(-4, 2)
|
||||
.list());
|
||||
|
||||
builder.hole(new LineStringBuilder()
|
||||
builder.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(4, 1)
|
||||
.point(4, -1)
|
||||
.point(-4, -1)
|
||||
.point(-4, 1)
|
||||
.point(4, 1));
|
||||
.point(4, 1)
|
||||
.list()));
|
||||
|
||||
Shape shape = builder.close().build();
|
||||
assertPolygon(shape);
|
||||
}
|
||||
|
||||
public void testShapeWithPointOnDateline() {
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(180, 0)
|
||||
.point(176, 4)
|
||||
.point(176, -4)
|
||||
.point(180, 0);
|
||||
.point(180, 0)
|
||||
.list());
|
||||
|
||||
Shape shape = builder.close().build();
|
||||
assertPolygon(shape);
|
||||
|
@ -421,21 +446,23 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
|
||||
public void testShapeWithEdgeAlongDateline() {
|
||||
// test case 1: test the positive side of the dateline
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(180, 0)
|
||||
.point(176, 4)
|
||||
.point(180, -4)
|
||||
.point(180, 0);
|
||||
.point(180, 0)
|
||||
.list());
|
||||
|
||||
Shape shape = builder.close().build();
|
||||
assertPolygon(shape);
|
||||
|
||||
// test case 2: test the negative side of the dateline
|
||||
builder = ShapeBuilders.newPolygon()
|
||||
builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-176, 4)
|
||||
.point(-180, 0)
|
||||
.point(-180, -4)
|
||||
.point(-176, 4);
|
||||
.point(-176, 4)
|
||||
.list());
|
||||
|
||||
shape = builder.close().build();
|
||||
assertPolygon(shape);
|
||||
|
@ -443,73 +470,85 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
|
||||
public void testShapeWithBoundaryHoles() {
|
||||
// test case 1: test the positive side of the dateline
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-177, 10)
|
||||
.point(176, 15)
|
||||
.point(172, 0)
|
||||
.point(176, -15)
|
||||
.point(-177, -10)
|
||||
.point(-177, 10);
|
||||
builder.hole(new LineStringBuilder()
|
||||
.point(-177, 10)
|
||||
.list());
|
||||
builder.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(176, 10)
|
||||
.point(180, 5)
|
||||
.point(180, -5)
|
||||
.point(176, -10)
|
||||
.point(176, 10));
|
||||
.point(176, 10)
|
||||
.list()));
|
||||
Shape shape = builder.close().build();
|
||||
assertMultiPolygon(shape);
|
||||
|
||||
// test case 2: test the negative side of the dateline
|
||||
builder = ShapeBuilders.newPolygon()
|
||||
builder = ShapeBuilders.newPolygon(
|
||||
new PointListBuilder()
|
||||
.point(-176, 15)
|
||||
.point(179, 10)
|
||||
.point(179, -10)
|
||||
.point(-176, -15)
|
||||
.point(-172, 0);
|
||||
builder.hole(new LineStringBuilder()
|
||||
.point(-172, 0)
|
||||
.close()
|
||||
.list());
|
||||
builder.hole(new LineStringBuilder(
|
||||
new PointListBuilder()
|
||||
.point(-176, 10)
|
||||
.point(-176, -10)
|
||||
.point(-180, -5)
|
||||
.point(-180, 5)
|
||||
.point(-176, 10));
|
||||
.point(-176, 10)
|
||||
.close()
|
||||
.list()));
|
||||
shape = builder.close().build();
|
||||
assertMultiPolygon(shape);
|
||||
}
|
||||
|
||||
public void testShapeWithTangentialHole() {
|
||||
// test a shape with one tangential (shared) vertex (should pass)
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(179, 10)
|
||||
.point(168, 15)
|
||||
.point(164, 0)
|
||||
.point(166, -15)
|
||||
.point(179, -10)
|
||||
.point(179, 10);
|
||||
builder.hole(new LineStringBuilder()
|
||||
.point(179, 10)
|
||||
.list());
|
||||
builder.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(-177, 10)
|
||||
.point(-178, -10)
|
||||
.point(-180, -5)
|
||||
.point(-180, 5)
|
||||
.point(-177, 10));
|
||||
.point(-177, 10)
|
||||
.list()));
|
||||
Shape shape = builder.close().build();
|
||||
assertMultiPolygon(shape);
|
||||
}
|
||||
|
||||
public void testShapeWithInvalidTangentialHole() {
|
||||
// test a shape with one invalid tangential (shared) vertex (should throw exception)
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(179, 10)
|
||||
.point(168, 15)
|
||||
.point(164, 0)
|
||||
.point(166, -15)
|
||||
.point(179, -10)
|
||||
.point(179, 10);
|
||||
builder.hole(new LineStringBuilder()
|
||||
.point(179, 10)
|
||||
.list());
|
||||
builder.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(164, 0)
|
||||
.point(175, 10)
|
||||
.point(175, 5)
|
||||
.point(179, -10)
|
||||
.point(164, 0));
|
||||
.point(164, 0)
|
||||
.list()));
|
||||
try {
|
||||
builder.close().build();
|
||||
fail("Expected InvalidShapeException");
|
||||
|
@ -520,43 +559,48 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
|
||||
public void testBoundaryShapeWithTangentialHole() {
|
||||
// test a shape with one tangential (shared) vertex for each hole (should pass)
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-177, 10)
|
||||
.point(176, 15)
|
||||
.point(172, 0)
|
||||
.point(176, -15)
|
||||
.point(-177, -10)
|
||||
.point(-177, 10);
|
||||
builder.hole(new LineStringBuilder()
|
||||
.point(-177, 10)
|
||||
.list());
|
||||
builder.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(-177, 10)
|
||||
.point(-178, -10)
|
||||
.point(-180, -5)
|
||||
.point(-180, 5)
|
||||
.point(-177, 10));
|
||||
builder.hole(new LineStringBuilder()
|
||||
.point(-177, 10)
|
||||
.list()));
|
||||
builder.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(172, 0)
|
||||
.point(176, 10)
|
||||
.point(176, -5)
|
||||
.point(172, 0));
|
||||
.point(172, 0)
|
||||
.list()));
|
||||
Shape shape = builder.close().build();
|
||||
assertMultiPolygon(shape);
|
||||
}
|
||||
|
||||
public void testBoundaryShapeWithInvalidTangentialHole() {
|
||||
// test shape with two tangential (shared) vertices (should throw exception)
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-177, 10)
|
||||
.point(176, 15)
|
||||
.point(172, 0)
|
||||
.point(176, -15)
|
||||
.point(-177, -10)
|
||||
.point(-177, 10);
|
||||
builder.hole(new LineStringBuilder()
|
||||
.point(-177, 10)
|
||||
.list());
|
||||
builder.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(-177, 10)
|
||||
.point(172, 0)
|
||||
.point(180, -5)
|
||||
.point(176, -10)
|
||||
.point(-177, 10));
|
||||
.point(-177, 10)
|
||||
.list()));
|
||||
try {
|
||||
builder.close().build();
|
||||
fail("Expected InvalidShapeException");
|
||||
|
@ -569,11 +613,12 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
* Test an enveloping polygon around the max mercator bounds
|
||||
*/
|
||||
public void testBoundaryShape() {
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-180, 90)
|
||||
.point(180, 90)
|
||||
.point(180, -90)
|
||||
.point(-180, -90);
|
||||
.point(-180, 90)
|
||||
.list());
|
||||
|
||||
Shape shape = builder.close().build();
|
||||
|
||||
|
@ -582,21 +627,23 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
|
||||
public void testShapeWithAlternateOrientation() {
|
||||
// cw: should produce a multi polygon spanning hemispheres
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(180, 0)
|
||||
.point(176, 4)
|
||||
.point(-176, 4)
|
||||
.point(180, 0);
|
||||
.point(180, 0)
|
||||
.list());
|
||||
|
||||
Shape shape = builder.close().build();
|
||||
assertPolygon(shape);
|
||||
|
||||
// cw: geo core will convert to ccw across the dateline
|
||||
builder = ShapeBuilders.newPolygon()
|
||||
builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(180, 0)
|
||||
.point(-176, 4)
|
||||
.point(176, 4)
|
||||
.point(180, 0);
|
||||
.point(180, 0)
|
||||
.list());
|
||||
|
||||
shape = builder.close().build();
|
||||
|
||||
|
@ -604,12 +651,13 @@ public class ShapeBuilderTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testInvalidShapeWithConsecutiveDuplicatePoints() {
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(180, 0)
|
||||
.point(176, 4)
|
||||
.point(176, 4)
|
||||
.point(-176, 4)
|
||||
.point(180, 0);
|
||||
.point(180, 0)
|
||||
.list());
|
||||
try {
|
||||
builder.close().build();
|
||||
fail("Expected InvalidShapeException");
|
||||
|
|
|
@ -40,7 +40,7 @@ import static org.hamcrest.Matchers.not;
|
|||
|
||||
public abstract class AbstractShapeBuilderTestCase<SB extends ShapeBuilder> extends ESTestCase {
|
||||
|
||||
private static final int NUMBER_OF_TESTBUILDERS = 20;
|
||||
private static final int NUMBER_OF_TESTBUILDERS = 100;
|
||||
private static NamedWriteableRegistry namedWriteableRegistry;
|
||||
|
||||
/**
|
||||
|
|
|
@ -42,9 +42,18 @@ public class CircleBuilderTests extends AbstractShapeBuilderTestCase<CircleBuild
|
|||
DistanceUnit unit = original.unit();
|
||||
|
||||
if (randomBoolean()) {
|
||||
mutation.center(new Coordinate(original.center().x/2, original.center().y/2));
|
||||
if (original.center().x > 0.0 || original.center().y > 0.0) {
|
||||
mutation.center(new Coordinate(original.center().x/2, original.center().y/2));
|
||||
} else {
|
||||
// original center was 0.0, 0.0
|
||||
mutation.center(randomDouble() + 0.1, randomDouble() + 0.1);
|
||||
}
|
||||
} else if (randomBoolean()) {
|
||||
radius = radius/2;
|
||||
if (radius > 0) {
|
||||
radius = radius/2;
|
||||
} else {
|
||||
radius = randomDouble() + 0.1;
|
||||
}
|
||||
} else {
|
||||
DistanceUnit newRandom = unit;
|
||||
while (newRandom == unit) {
|
||||
|
@ -56,10 +65,15 @@ public class CircleBuilderTests extends AbstractShapeBuilderTestCase<CircleBuild
|
|||
}
|
||||
|
||||
static CircleBuilder createRandomShape() {
|
||||
double centerX = randomDoubleBetween(-180, 180, false);
|
||||
double centerY = randomDoubleBetween(-90, 90, false);
|
||||
return new CircleBuilder()
|
||||
.center(new Coordinate(centerX, centerY))
|
||||
.radius(randomDoubleBetween(0.1, 10.0, false), randomFrom(DistanceUnit.values()));
|
||||
CircleBuilder circle = new CircleBuilder();
|
||||
if (frequently()) {
|
||||
double centerX = randomDoubleBetween(-180, 180, false);
|
||||
double centerY = randomDoubleBetween(-90, 90, false);
|
||||
circle.center(centerX, centerY);
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
circle.radius(randomDoubleBetween(0.1, 10.0, false), randomFrom(DistanceUnit.values()));
|
||||
}
|
||||
return circle;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,26 @@ import org.elasticsearch.test.geo.RandomShapeGenerator;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
public class EnvelopeBuilderTests extends AbstractShapeBuilderTestCase<EnvelopeBuilder> {
|
||||
|
||||
public void testInvalidConstructorArgs() {
|
||||
try {
|
||||
new EnvelopeBuilder(null, new Coordinate(1.0, -1.0));
|
||||
fail("Exception expected");
|
||||
} catch (NullPointerException e) {
|
||||
assertThat("topLeft of envelope cannot be null", equalTo(e.getMessage()));
|
||||
}
|
||||
|
||||
try {
|
||||
new EnvelopeBuilder(new Coordinate(1.0, -1.0), null);
|
||||
fail("Exception expected");
|
||||
} catch (NullPointerException e) {
|
||||
assertThat("bottomRight of envelope cannot be null", equalTo(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EnvelopeBuilder createTestShapeBuilder() {
|
||||
return createRandomShape();
|
||||
|
@ -42,26 +60,25 @@ public class EnvelopeBuilderTests extends AbstractShapeBuilderTestCase<EnvelopeB
|
|||
// move one corner to the middle of original
|
||||
switch (randomIntBetween(0, 3)) {
|
||||
case 0:
|
||||
mutation.topLeft(new Coordinate(randomDoubleBetween(-180.0, original.bottomRight().x, true), original.topLeft().y));
|
||||
mutation = new EnvelopeBuilder(new Coordinate(randomDoubleBetween(-180.0, original.bottomRight().x, true), original.topLeft().y), original.bottomRight());
|
||||
break;
|
||||
case 1:
|
||||
mutation.topLeft(new Coordinate(original.topLeft().x, randomDoubleBetween(original.bottomRight().y, 90.0, true)));
|
||||
mutation = new EnvelopeBuilder(new Coordinate(original.topLeft().x, randomDoubleBetween(original.bottomRight().y, 90.0, true)), original.bottomRight());
|
||||
break;
|
||||
case 2:
|
||||
mutation.bottomRight(new Coordinate(randomDoubleBetween(original.topLeft().x, 180.0, true), original.bottomRight().y));
|
||||
mutation = new EnvelopeBuilder(original.topLeft(), new Coordinate(randomDoubleBetween(original.topLeft().x, 180.0, true), original.bottomRight().y));
|
||||
break;
|
||||
case 3:
|
||||
mutation.bottomRight(new Coordinate(original.bottomRight().x, randomDoubleBetween(-90.0, original.topLeft().y, true)));
|
||||
mutation = new EnvelopeBuilder(original.topLeft(), new Coordinate(original.bottomRight().x, randomDoubleBetween(-90.0, original.topLeft().y, true)));
|
||||
break;
|
||||
}
|
||||
return mutation;
|
||||
}
|
||||
|
||||
static EnvelopeBuilder createRandomShape() {
|
||||
EnvelopeBuilder envelope = new EnvelopeBuilder();
|
||||
Rectangle box = RandomShapeGenerator.xRandomRectangle(getRandom(), RandomShapeGenerator.xRandomPoint(getRandom()));
|
||||
envelope.topLeft(box.getMinX(), box.getMaxY())
|
||||
.bottomRight(box.getMaxX(), box.getMinY());
|
||||
EnvelopeBuilder envelope = new EnvelopeBuilder(new Coordinate(box.getMinX(), box.getMaxY()),
|
||||
new Coordinate(box.getMaxX(), box.getMinY()));
|
||||
return envelope;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,33 @@ import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
public class LineStringBuilderTests extends AbstractShapeBuilderTestCase<LineStringBuilder> {
|
||||
|
||||
public void testInvalidConstructorArgs() {
|
||||
try {
|
||||
new LineStringBuilder(null);
|
||||
fail("Exception expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat("cannot create point collection with empty set of points", equalTo(e.getMessage()));
|
||||
}
|
||||
|
||||
try {
|
||||
new LineStringBuilder(new PointListBuilder().list());
|
||||
fail("Exception expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat("cannot create point collection with empty set of points", equalTo(e.getMessage()));
|
||||
}
|
||||
|
||||
try {
|
||||
new LineStringBuilder(new PointListBuilder().point(0.0, 0.0).list());
|
||||
fail("Exception expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat("invalid number of points in LineString (found [1] - must be >= 2)", equalTo(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LineStringBuilder createTestShapeBuilder() {
|
||||
return createRandomShape();
|
||||
|
|
|
@ -40,30 +40,37 @@ public class MultiLineStringBuilderTests extends AbstractShapeBuilderTestCase<Mu
|
|||
static MultiLineStringBuilder mutate(MultiLineStringBuilder original) throws IOException {
|
||||
MultiLineStringBuilder mutation = (MultiLineStringBuilder) copyShape(original);
|
||||
Coordinate[][] coordinates = mutation.coordinates();
|
||||
int lineToChange = randomInt(coordinates.length - 1);
|
||||
for (int i = 0; i < coordinates.length; i++) {
|
||||
Coordinate[] line = coordinates[i];
|
||||
if (i == lineToChange) {
|
||||
Coordinate coordinate = randomFrom(line);
|
||||
if (randomBoolean()) {
|
||||
if (coordinate.x != 0.0) {
|
||||
coordinate.x = coordinate.x / 2;
|
||||
if (coordinates.length > 0) {
|
||||
int lineToChange = randomInt(coordinates.length - 1);
|
||||
for (int i = 0; i < coordinates.length; i++) {
|
||||
Coordinate[] line = coordinates[i];
|
||||
if (i == lineToChange) {
|
||||
Coordinate coordinate = randomFrom(line);
|
||||
if (randomBoolean()) {
|
||||
if (coordinate.x != 0.0) {
|
||||
coordinate.x = coordinate.x / 2;
|
||||
} else {
|
||||
coordinate.x = randomDoubleBetween(-180.0, 180.0, true);
|
||||
}
|
||||
} else {
|
||||
coordinate.x = randomDoubleBetween(-180.0, 180.0, true);
|
||||
}
|
||||
} else {
|
||||
if (coordinate.y != 0.0) {
|
||||
coordinate.y = coordinate.y / 2;
|
||||
} else {
|
||||
coordinate.y = randomDoubleBetween(-90.0, 90.0, true);
|
||||
if (coordinate.y != 0.0) {
|
||||
coordinate.y = coordinate.y / 2;
|
||||
} else {
|
||||
coordinate.y = randomDoubleBetween(-90.0, 90.0, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mutation.linestring((LineStringBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.LINESTRING));
|
||||
}
|
||||
return mutation;
|
||||
}
|
||||
|
||||
static MultiLineStringBuilder createRandomShape() {
|
||||
if (true) {
|
||||
return new MultiLineStringBuilder();
|
||||
}
|
||||
return (MultiLineStringBuilder) RandomShapeGenerator.createShape(getRandom(), ShapeType.MULTILINESTRING);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,29 @@ import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
public class MultiPointBuilderTests extends AbstractShapeBuilderTestCase<MultiPointBuilder> {
|
||||
|
||||
public void testInvalidBuilderException() {
|
||||
try {
|
||||
new MultiPointBuilder(null);
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat("cannot create point collection with empty set of points", equalTo(e.getMessage()));
|
||||
}
|
||||
|
||||
try {
|
||||
new MultiPointBuilder(new PointListBuilder().list());
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat("cannot create point collection with empty set of points", equalTo(e.getMessage()));
|
||||
}
|
||||
|
||||
// one point is minimum
|
||||
new MultiPointBuilder(new PointListBuilder().point(0.0, 0.0).list());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MultiPointBuilder createTestShapeBuilder() {
|
||||
return createRandomShape();
|
||||
|
@ -40,19 +61,23 @@ public class MultiPointBuilderTests extends AbstractShapeBuilderTestCase<MultiPo
|
|||
static MultiPointBuilder mutate(MultiPointBuilder original) throws IOException {
|
||||
MultiPointBuilder mutation = (MultiPointBuilder) copyShape(original);
|
||||
Coordinate[] coordinates = original.coordinates(false);
|
||||
Coordinate coordinate = randomFrom(coordinates);
|
||||
if (randomBoolean()) {
|
||||
if (coordinate.x != 0.0) {
|
||||
coordinate.x = coordinate.x / 2;
|
||||
if (coordinates.length > 0) {
|
||||
Coordinate coordinate = randomFrom(coordinates);
|
||||
if (randomBoolean()) {
|
||||
if (coordinate.x != 0.0) {
|
||||
coordinate.x = coordinate.x / 2;
|
||||
} else {
|
||||
coordinate.x = randomDoubleBetween(-180.0, 180.0, true);
|
||||
}
|
||||
} else {
|
||||
coordinate.x = randomDoubleBetween(-180.0, 180.0, true);
|
||||
if (coordinate.y != 0.0) {
|
||||
coordinate.y = coordinate.y / 2;
|
||||
} else {
|
||||
coordinate.y = randomDoubleBetween(-90.0, 90.0, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (coordinate.y != 0.0) {
|
||||
coordinate.y = coordinate.y / 2;
|
||||
} else {
|
||||
coordinate.y = randomDoubleBetween(-90.0, 90.0, true);
|
||||
}
|
||||
coordinates = new Coordinate[]{new Coordinate(1.0, 1.0)};
|
||||
}
|
||||
return mutation.points(coordinates);
|
||||
}
|
||||
|
|
|
@ -77,8 +77,7 @@ public class PolygonBuilderTests extends AbstractShapeBuilderTestCase<PolygonBui
|
|||
* This is done so we don't have to expose a setter for orientation in the actual class
|
||||
*/
|
||||
private static PolygonBuilder polyWithOposingOrientation(PolygonBuilder pb) {
|
||||
PolygonBuilder mutation = new PolygonBuilder(pb.orientation() == Orientation.LEFT ? Orientation.RIGHT : Orientation.LEFT);
|
||||
mutation.points(pb.shell().coordinates(false));
|
||||
PolygonBuilder mutation = new PolygonBuilder(pb.shell().points, pb.orientation() == Orientation.LEFT ? Orientation.RIGHT : Orientation.LEFT);
|
||||
for (LineStringBuilder hole : pb.holes()) {
|
||||
mutation.hole(hole);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.ConstantScoreQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
|
@ -215,7 +217,7 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
|
|||
|
||||
// see #3878
|
||||
public void testThatXContentSerializationInsideOfArrayWorks() throws Exception {
|
||||
EnvelopeBuilder envelopeBuilder = ShapeBuilders.newEnvelope().topLeft(0, 0).bottomRight(10, 10);
|
||||
EnvelopeBuilder envelopeBuilder = ShapeBuilders.newEnvelope(new Coordinate(0, 0), new Coordinate(10, 10));
|
||||
GeoShapeQueryBuilder geoQuery = QueryBuilders.geoShapeQuery("searchGeometry", envelopeBuilder);
|
||||
JsonXContent.contentBuilder().startArray().value(geoQuery).endArray();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.search.join.ScoreMode;
|
|||
import org.elasticsearch.common.geo.GeoDistance;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.geo.builders.PointListBuilder;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilders;
|
||||
import org.elasticsearch.common.unit.DistanceUnit;
|
||||
import org.elasticsearch.index.query.MoreLikeThisQueryBuilder.Item;
|
||||
|
@ -174,12 +175,14 @@ public class QueryDSLDocumentationTests extends ESTestCase {
|
|||
public void testGeoShape() throws IOException {
|
||||
GeoShapeQueryBuilder qb = geoShapeQuery(
|
||||
"pin.location",
|
||||
ShapeBuilders.newMultiPoint()
|
||||
ShapeBuilders.newMultiPoint(
|
||||
new PointListBuilder()
|
||||
.point(0, 0)
|
||||
.point(0, 10)
|
||||
.point(10, 10)
|
||||
.point(10, 0)
|
||||
.point(0, 0));
|
||||
.point(0, 0)
|
||||
.list()));
|
||||
qb.relation(ShapeRelation.WITHIN);
|
||||
|
||||
qb = geoShapeQuery(
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.elasticsearch.common.bytes.BytesReference;
|
|||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.geo.builders.LineStringBuilder;
|
||||
import org.elasticsearch.common.geo.builders.MultiPolygonBuilder;
|
||||
import org.elasticsearch.common.geo.builders.PointListBuilder;
|
||||
import org.elasticsearch.common.geo.builders.PolygonBuilder;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilders;
|
||||
import org.elasticsearch.common.io.Streams;
|
||||
|
@ -119,30 +120,30 @@ public class GeoFilterIT extends ESIntegTestCase {
|
|||
public void testShapeBuilders() {
|
||||
try {
|
||||
// self intersection polygon
|
||||
ShapeBuilders.newPolygon()
|
||||
ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-10, -10)
|
||||
.point(10, 10)
|
||||
.point(-10, 10)
|
||||
.point(10, -10)
|
||||
.close().build();
|
||||
.close()
|
||||
.list())
|
||||
.build();
|
||||
fail("Self intersection not detected");
|
||||
} catch (InvalidShapeException e) {
|
||||
}
|
||||
|
||||
// polygon with hole
|
||||
ShapeBuilders.newPolygon()
|
||||
.point(-10, -10).point(-10, 10).point(10, 10).point(10, -10)
|
||||
.hole(new LineStringBuilder()
|
||||
.point(-5, -5).point(-5, 5).point(5, 5).point(5, -5)
|
||||
.close()).close().build();
|
||||
|
||||
ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-10, -10).point(-10, 10).point(10, 10).point(10, -10).close().list())
|
||||
.hole(new LineStringBuilder(new PointListBuilder().point(-5, -5).point(-5, 5).point(5, 5).point(5, -5).close().list()))
|
||||
.build();
|
||||
try {
|
||||
// polygon with overlapping hole
|
||||
ShapeBuilders.newPolygon()
|
||||
.point(-10, -10).point(-10, 10).point(10, 10).point(10, -10)
|
||||
.hole(new LineStringBuilder()
|
||||
.point(-5, -5).point(-5, 11).point(5, 11).point(5, -5)
|
||||
.close()).close().build();
|
||||
ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-10, -10).point(-10, 10).point(10, 10).point(10, -10).close().list())
|
||||
.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(-5, -5).point(-5, 11).point(5, 11).point(5, -5).close().list()))
|
||||
.build();
|
||||
|
||||
fail("Self intersection not detected");
|
||||
} catch (InvalidShapeException e) {
|
||||
|
@ -150,22 +151,18 @@ public class GeoFilterIT extends ESIntegTestCase {
|
|||
|
||||
try {
|
||||
// polygon with intersection holes
|
||||
ShapeBuilders.newPolygon()
|
||||
.point(-10, -10).point(-10, 10).point(10, 10).point(10, -10)
|
||||
.hole(new LineStringBuilder()
|
||||
.point(-5, -5).point(-5, 5).point(5, 5).point(5, -5)
|
||||
.close())
|
||||
.hole(new LineStringBuilder()
|
||||
.point(-5, -6).point(5, -6).point(5, -4).point(-5, -4)
|
||||
.close())
|
||||
.close().build();
|
||||
ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-10, -10).point(-10, 10).point(10, 10).point(10, -10).close().list())
|
||||
.hole(new LineStringBuilder(new PointListBuilder().point(-5, -5).point(-5, 5).point(5, 5).point(5, -5).close().list()))
|
||||
.hole(new LineStringBuilder(new PointListBuilder().point(-5, -6).point(5, -6).point(5, -4).point(-5, -4).close().list()))
|
||||
.build();
|
||||
fail("Intersection of holes not detected");
|
||||
} catch (InvalidShapeException e) {
|
||||
}
|
||||
|
||||
try {
|
||||
// Common line in polygon
|
||||
ShapeBuilders.newPolygon()
|
||||
ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-10, -10)
|
||||
.point(-10, 10)
|
||||
.point(-5, 10)
|
||||
|
@ -173,7 +170,9 @@ public class GeoFilterIT extends ESIntegTestCase {
|
|||
.point(-5, 20)
|
||||
.point(10, 20)
|
||||
.point(10, -10)
|
||||
.close().build();
|
||||
.close()
|
||||
.list())
|
||||
.build();
|
||||
fail("Self intersection not detected");
|
||||
} catch (InvalidShapeException e) {
|
||||
}
|
||||
|
@ -181,23 +180,22 @@ public class GeoFilterIT extends ESIntegTestCase {
|
|||
// Multipolygon: polygon with hole and polygon within the whole
|
||||
ShapeBuilders
|
||||
.newMultiPolygon()
|
||||
.polygon(new PolygonBuilder()
|
||||
.point(-10, -10)
|
||||
.polygon(new PolygonBuilder(
|
||||
new PointListBuilder().point(-10, -10)
|
||||
.point(-10, 10)
|
||||
.point(10, 10)
|
||||
.point(10, -10)
|
||||
.hole(new LineStringBuilder().point(-5, -5)
|
||||
.point(10, -10).close().list())
|
||||
.hole(new LineStringBuilder(
|
||||
new PointListBuilder().point(-5, -5)
|
||||
.point(-5, 5)
|
||||
.point(5, 5)
|
||||
.point(5, -5)
|
||||
.close())
|
||||
.close())
|
||||
.polygon(new PolygonBuilder()
|
||||
.point(5, -5).close().list())))
|
||||
.polygon(new PolygonBuilder(
|
||||
new PointListBuilder()
|
||||
.point(-4, -4)
|
||||
.point(-4, 4)
|
||||
.point(4, 4)
|
||||
.point(4, -4)
|
||||
.close())
|
||||
.point(4, -4).close().list()))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -226,14 +224,12 @@ public class GeoFilterIT extends ESIntegTestCase {
|
|||
// with a hole of size 5x5 equidistant from all sides. This hole in turn contains
|
||||
// the second polygon of size 4x4 equidistant from all sites
|
||||
MultiPolygonBuilder polygon = ShapeBuilders.newMultiPolygon()
|
||||
.polygon(new PolygonBuilder()
|
||||
.point(-10, -10).point(-10, 10).point(10, 10).point(10, -10)
|
||||
.hole(new LineStringBuilder()
|
||||
.point(-5, -5).point(-5, 5).point(5, 5).point(5, -5).close())
|
||||
.close())
|
||||
.polygon(new PolygonBuilder()
|
||||
.point(-4, -4).point(-4, 4).point(4, 4).point(4, -4).close());
|
||||
|
||||
.polygon(new PolygonBuilder(
|
||||
new PointListBuilder().point(-10, -10).point(-10, 10).point(10, 10).point(10, -10).close().list())
|
||||
.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(-5, -5).point(-5, 5).point(5, 5).point(5, -5).close().list())))
|
||||
.polygon(new PolygonBuilder(
|
||||
new PointListBuilder().point(-4, -4).point(-4, 4).point(4, 4).point(4, -4).close().list()));
|
||||
BytesReference data = jsonBuilder().startObject().field("area", polygon).endObject().bytes();
|
||||
|
||||
client().prepareIndex("shapes", "polygon", "1").setSource(data).execute().actionGet();
|
||||
|
@ -292,11 +288,10 @@ public class GeoFilterIT extends ESIntegTestCase {
|
|||
}
|
||||
|
||||
// Create a polygon that fills the empty area of the polygon defined above
|
||||
PolygonBuilder inverse = ShapeBuilders.newPolygon()
|
||||
.point(-5, -5).point(-5, 5).point(5, 5).point(5, -5)
|
||||
.hole(new LineStringBuilder()
|
||||
.point(-4, -4).point(-4, 4).point(4, 4).point(4, -4).close())
|
||||
.close();
|
||||
PolygonBuilder inverse = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-5, -5).point(-5, 5).point(5, 5).point(5, -5).close().list())
|
||||
.hole(new LineStringBuilder(
|
||||
new PointListBuilder().point(-4, -4).point(-4, 4).point(4, 4).point(4, -4).close().list()));
|
||||
|
||||
data = jsonBuilder().startObject().field("area", inverse).endObject().bytes();
|
||||
client().prepareIndex("shapes", "polygon", "2").setSource(data).execute().actionGet();
|
||||
|
@ -311,16 +306,15 @@ public class GeoFilterIT extends ESIntegTestCase {
|
|||
assertFirstHit(result, hasId("2"));
|
||||
|
||||
// Create Polygon with hole and common edge
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon()
|
||||
.point(-10, -10).point(-10, 10).point(10, 10).point(10, -10)
|
||||
.hole(new LineStringBuilder()
|
||||
.point(-5, -5).point(-5, 5).point(10, 5).point(10, -5).close())
|
||||
.close();
|
||||
PolygonBuilder builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-10, -10).point(-10, 10).point(10, 10).point(10, -10).close().list())
|
||||
.hole(new LineStringBuilder(new PointListBuilder()
|
||||
.point(-5, -5).point(-5, 5).point(10, 5).point(10, -5).close().list()));
|
||||
|
||||
if (withinSupport) {
|
||||
// Polygon WithIn Polygon
|
||||
builder = ShapeBuilders.newPolygon()
|
||||
.point(-30, -30).point(-30, 30).point(30, 30).point(30, -30).close();
|
||||
builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(-30, -30).point(-30, 30).point(30, 30).point(30, -30).close().list());
|
||||
|
||||
result = client().prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
|
@ -330,19 +324,17 @@ public class GeoFilterIT extends ESIntegTestCase {
|
|||
}
|
||||
|
||||
// Create a polygon crossing longitude 180.
|
||||
builder = ShapeBuilders.newPolygon()
|
||||
.point(170, -10).point(190, -10).point(190, 10).point(170, 10)
|
||||
.close();
|
||||
builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(170, -10).point(190, -10).point(190, 10).point(170, 10).close().list());
|
||||
|
||||
data = jsonBuilder().startObject().field("area", builder).endObject().bytes();
|
||||
client().prepareIndex("shapes", "polygon", "1").setSource(data).execute().actionGet();
|
||||
client().admin().indices().prepareRefresh().execute().actionGet();
|
||||
|
||||
// Create a polygon crossing longitude 180 with hole.
|
||||
builder = ShapeBuilders.newPolygon()
|
||||
.point(170, -10).point(190, -10).point(190, 10).point(170, 10)
|
||||
.hole(new LineStringBuilder().point(175, -5).point(185, -5).point(185, 5).point(175, 5).close())
|
||||
.close();
|
||||
builder = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(170, -10).point(190, -10).point(190, 10).point(170, 10).close().list())
|
||||
.hole(new LineStringBuilder(new PointListBuilder().point(175, -5).point(185, -5).point(185, 5).point(175, 5).close().list()));
|
||||
|
||||
data = jsonBuilder().startObject().field("area", builder).endObject().bytes();
|
||||
client().prepareIndex("shapes", "polygon", "1").setSource(data).execute().actionGet();
|
||||
|
|
|
@ -20,12 +20,15 @@
|
|||
package org.elasticsearch.search.geo;
|
||||
|
||||
import com.spatial4j.core.shape.Rectangle;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.geo.builders.EnvelopeBuilder;
|
||||
import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder;
|
||||
import org.elasticsearch.common.geo.builders.LineStringBuilder;
|
||||
import org.elasticsearch.common.geo.builders.PointListBuilder;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilders;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
@ -94,7 +97,7 @@ public class GeoShapeQueryTests extends ESSingleNodeTestCase {
|
|||
.endObject()
|
||||
.endObject()).setRefresh(true).execute().actionGet();
|
||||
|
||||
ShapeBuilder shape = ShapeBuilders.newEnvelope().topLeft(-45, 45).bottomRight(45, -45);
|
||||
ShapeBuilder shape = ShapeBuilders.newEnvelope(new Coordinate(-45, 45), new Coordinate(45, -45));
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch("test").setTypes("type1")
|
||||
.setQuery(geoIntersectionQuery("location", shape))
|
||||
|
@ -138,7 +141,7 @@ public class GeoShapeQueryTests extends ESSingleNodeTestCase {
|
|||
.endObject()
|
||||
.endObject()).setRefresh(true).execute().actionGet();
|
||||
|
||||
ShapeBuilder query = ShapeBuilders.newEnvelope().topLeft(-122.88, 48.62).bottomRight(-122.82, 48.54);
|
||||
ShapeBuilder query = ShapeBuilders.newEnvelope(new Coordinate(-122.88, 48.62), new Coordinate(-122.82, 48.54));
|
||||
|
||||
// This search would fail if both geoshape indexing and geoshape filtering
|
||||
// used the bottom-level optimization in SpatialPrefixTree#recursiveGetNodes.
|
||||
|
@ -163,7 +166,7 @@ public class GeoShapeQueryTests extends ESSingleNodeTestCase {
|
|||
createIndex("shapes");
|
||||
ensureGreen();
|
||||
|
||||
ShapeBuilder shape = ShapeBuilders.newEnvelope().topLeft(-45, 45).bottomRight(45, -45);
|
||||
ShapeBuilder shape = ShapeBuilders.newEnvelope(new Coordinate(-45, 45), new Coordinate(45, -45));
|
||||
|
||||
client().prepareIndex("shapes", "shape_type", "Big_Rectangle").setSource(jsonBuilder().startObject()
|
||||
.field("shape", shape).endObject()).setRefresh(true).execute().actionGet();
|
||||
|
@ -195,14 +198,13 @@ public class GeoShapeQueryTests extends ESSingleNodeTestCase {
|
|||
}
|
||||
|
||||
public void testReusableBuilder() throws IOException {
|
||||
ShapeBuilder polygon = ShapeBuilders.newPolygon()
|
||||
.point(170, -10).point(190, -10).point(190, 10).point(170, 10)
|
||||
.hole(new LineStringBuilder().point(175, -5).point(185, -5).point(185, 5).point(175, 5).close())
|
||||
.close();
|
||||
ShapeBuilder polygon = ShapeBuilders.newPolygon(new PointListBuilder()
|
||||
.point(170, -10).point(190, -10).point(190, 10).point(170, 10).close().list())
|
||||
.hole(new LineStringBuilder(new PointListBuilder().point(175, -5).point(185, -5).point(185, 5).point(175, 5).close().list()));
|
||||
assertUnmodified(polygon);
|
||||
|
||||
ShapeBuilder linestring = ShapeBuilders.newLineString()
|
||||
.point(170, -10).point(190, -10).point(190, 10).point(170, 10);
|
||||
ShapeBuilder linestring = ShapeBuilders.newLineString(new PointListBuilder()
|
||||
.point(170, -10).point(190, -10).point(190, 10).point(170, 10).close().list());
|
||||
assertUnmodified(linestring);
|
||||
}
|
||||
|
||||
|
@ -327,7 +329,7 @@ public class GeoShapeQueryTests extends ESSingleNodeTestCase {
|
|||
client().prepareIndex("test", "type", "1").setSource(docSource).setRefresh(true).execute().actionGet();
|
||||
|
||||
// index the mbr of the collection
|
||||
EnvelopeBuilder env = new EnvelopeBuilder().topLeft(mbr.getMinX(), mbr.getMaxY()).bottomRight(mbr.getMaxX(), mbr.getMinY());
|
||||
EnvelopeBuilder env = new EnvelopeBuilder(new Coordinate(mbr.getMinX(), mbr.getMaxY()), new Coordinate(mbr.getMaxX(), mbr.getMinY()));
|
||||
docSource = env.toXContent(jsonBuilder().startObject().field("location"), null).endObject();
|
||||
client().prepareIndex("test", "type", "2").setSource(docSource).setRefresh(true).execute().actionGet();
|
||||
|
||||
|
@ -375,8 +377,8 @@ public class GeoShapeQueryTests extends ESSingleNodeTestCase {
|
|||
"location",
|
||||
ShapeBuilders.newGeometryCollection()
|
||||
.polygon(
|
||||
ShapeBuilders.newPolygon().point(99.0, -1.0).point(99.0, 3.0).point(103.0, 3.0).point(103.0, -1.0)
|
||||
.point(99.0, -1.0))).relation(ShapeRelation.INTERSECTS);
|
||||
ShapeBuilders.newPolygon(new PointListBuilder().point(99.0, -1.0).point(99.0, 3.0).point(103.0, 3.0).point(103.0, -1.0)
|
||||
.point(99.0, -1.0).list()))).relation(ShapeRelation.INTERSECTS);
|
||||
SearchResponse result = client().prepareSearch("test").setTypes("type").setQuery(QueryBuilders.matchAllQuery())
|
||||
.setPostFilter(filter).get();
|
||||
assertSearchResponse(result);
|
||||
|
@ -384,17 +386,17 @@ public class GeoShapeQueryTests extends ESSingleNodeTestCase {
|
|||
filter = QueryBuilders.geoShapeQuery(
|
||||
"location",
|
||||
ShapeBuilders.newGeometryCollection().polygon(
|
||||
ShapeBuilders.newPolygon().point(199.0, -11.0).point(199.0, 13.0).point(193.0, 13.0).point(193.0, -11.0)
|
||||
.point(199.0, -11.0))).relation(ShapeRelation.INTERSECTS);
|
||||
ShapeBuilders.newPolygon(new PointListBuilder().point(199.0, -11.0).point(199.0, 13.0).point(193.0, 13.0).point(193.0, -11.0)
|
||||
.point(199.0, -11.0).list()))).relation(ShapeRelation.INTERSECTS);
|
||||
result = client().prepareSearch("test").setTypes("type").setQuery(QueryBuilders.matchAllQuery())
|
||||
.setPostFilter(filter).get();
|
||||
assertSearchResponse(result);
|
||||
assertHitCount(result, 0);
|
||||
filter = QueryBuilders.geoShapeQuery("location", ShapeBuilders.newGeometryCollection()
|
||||
.polygon(ShapeBuilders.newPolygon().point(99.0, -1.0).point(99.0, 3.0).point(103.0, 3.0).point(103.0, -1.0).point(99.0, -1.0))
|
||||
.polygon(ShapeBuilders.newPolygon(new PointListBuilder().point(99.0, -1.0).point(99.0, 3.0).point(103.0, 3.0).point(103.0, -1.0).point(99.0, -1.0).list()))
|
||||
.polygon(
|
||||
ShapeBuilders.newPolygon().point(199.0, -11.0).point(199.0, 13.0).point(193.0, 13.0).point(193.0, -11.0)
|
||||
.point(199.0, -11.0))).relation(ShapeRelation.INTERSECTS);
|
||||
ShapeBuilders.newPolygon(new PointListBuilder().point(199.0, -11.0).point(199.0, 13.0).point(193.0, 13.0).point(193.0, -11.0)
|
||||
.point(199.0, -11.0).list()))).relation(ShapeRelation.INTERSECTS);
|
||||
result = client().prepareSearch("test").setTypes("type").setQuery(QueryBuilders.matchAllQuery())
|
||||
.setPostFilter(filter).get();
|
||||
assertSearchResponse(result);
|
||||
|
|
|
@ -29,6 +29,7 @@ import com.spatial4j.core.shape.impl.Range;
|
|||
import com.vividsolutions.jts.algorithm.ConvexHull;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import com.vividsolutions.jts.geom.Geometry;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder;
|
||||
import org.elasticsearch.common.geo.builders.LineStringBuilder;
|
||||
|
@ -36,6 +37,7 @@ import org.elasticsearch.common.geo.builders.MultiLineStringBuilder;
|
|||
import org.elasticsearch.common.geo.builders.MultiPointBuilder;
|
||||
import org.elasticsearch.common.geo.builders.PointBuilder;
|
||||
import org.elasticsearch.common.geo.builders.PointCollection;
|
||||
import org.elasticsearch.common.geo.builders.PointListBuilder;
|
||||
import org.elasticsearch.common.geo.builders.PolygonBuilder;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
||||
import org.elasticsearch.search.geo.GeoShapeQueryTests;
|
||||
|
@ -187,11 +189,12 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
|||
// if this number gets out of hand, the number of self intersections for a linestring can become
|
||||
// (n^2-n)/2 and computing the relation intersection matrix will become NP-Hard
|
||||
int numPoints = RandomInts.randomIntBetween(r, 3, 10);
|
||||
PointCollection pcb = (st == ShapeType.MULTIPOINT) ? new MultiPointBuilder() : new LineStringBuilder();
|
||||
PointListBuilder pl = new PointListBuilder();
|
||||
for (int i=0; i<numPoints; ++i) {
|
||||
p = xRandomPointIn(r, within);
|
||||
pcb.point(p.getX(), p.getY());
|
||||
pl.point(p.getX(), p.getY());
|
||||
}
|
||||
PointCollection pcb = (st == ShapeType.MULTIPOINT) ? new MultiPointBuilder(pl.list()) : new LineStringBuilder(pl.list());
|
||||
return pcb;
|
||||
case MULTILINESTRING:
|
||||
MultiLineStringBuilder mlsb = new MultiLineStringBuilder();
|
||||
|
@ -219,7 +222,7 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
|||
shellCoords[2] = new Coordinate(within.getMaxX(), within.getMaxY());
|
||||
shellCoords[3] = new Coordinate(within.getMaxX(), within.getMinY());
|
||||
}
|
||||
PolygonBuilder pgb = new PolygonBuilder().points(shellCoords).close();
|
||||
PolygonBuilder pgb = new PolygonBuilder(new PointListBuilder().points(shellCoords).close().list());
|
||||
if (validate) {
|
||||
// This test framework builds semi-random geometry (in the sense that points are not truly random due to spatial
|
||||
// auto-correlation) As a result of the semi-random nature of the geometry, one can not predict the orientation
|
||||
|
|
Loading…
Reference in New Issue