Merge pull request #15551 from cbuescher/shapes-add-validation

Geo: Add validation of shapes to ShapeBuilders
This commit is contained in:
Christoph Büscher 2016-01-12 19:15:26 +01:00
commit ab456f6174
27 changed files with 978 additions and 638 deletions

View File

@ -21,6 +21,7 @@ package org.elasticsearch.common.geo.builders;
import com.spatial4j.core.shape.Circle;
import com.vividsolutions.jts.geom.Coordinate;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.unit.DistanceUnit;
@ -35,12 +36,20 @@ public class CircleBuilder extends ShapeBuilder {
public static final String FIELD_RADIUS = "radius";
public static final GeoShapeType TYPE = GeoShapeType.CIRCLE;
public static final CircleBuilder PROTOTYPE = new CircleBuilder();
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
*

View File

@ -20,26 +20,32 @@
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.
* The {@link CoordinateCollection} is an abstract base implementation for {@link LineStringBuilder} and {@link MultiPointBuilder}.
* It holds a common list of {@link Coordinate}, provides setters for adding elements to the list and can render this to XContent.
*/
public abstract class PointCollection<E extends PointCollection<E>> extends ShapeBuilder {
public abstract class CoordinateCollection<E extends CoordinateCollection<E>> extends ShapeBuilder {
protected final ArrayList<Coordinate> points;
protected final List<Coordinate> coordinates;
protected PointCollection() {
this(new ArrayList<Coordinate>());
}
protected PointCollection(ArrayList<Coordinate> points) {
this.points = points;
/**
* Construct a new collection of coordinates.
* @param coordinates an initial list of coordinates
* @throws IllegalArgumentException if coordinates is <tt>null</tt> or empty
*/
protected CoordinateCollection(List<Coordinate> coordinates) {
if (coordinates == null || coordinates.size() == 0) {
throw new IllegalArgumentException("cannot create point collection with empty set of points");
}
this.coordinates = coordinates;
}
@SuppressWarnings("unchecked")
@ -48,54 +54,54 @@ public abstract class PointCollection<E extends PointCollection<E>> extends Shap
}
/**
* Add a new point to the collection
* Add a new coordinate to the collection
* @param longitude longitude of the coordinate
* @param latitude latitude of the coordinate
* @return this
*/
public E point(double longitude, double latitude) {
return this.point(coordinate(longitude, latitude));
public E coordinate(double longitude, double latitude) {
return this.coordinate(new Coordinate(longitude, latitude));
}
/**
* Add a new point to the collection
* Add a new coordinate to the collection
* @param coordinate coordinate of the point
* @return this
*/
public E point(Coordinate coordinate) {
this.points.add(coordinate);
public E coordinate(Coordinate coordinate) {
this.coordinates.add(coordinate);
return thisRef();
}
/**
* Add a array of points to the collection
* Add a array of coordinates to the collection
*
* @param coordinates array of {@link Coordinate}s to add
* @return this
*/
public E points(Coordinate...coordinates) {
return this.points(Arrays.asList(coordinates));
public E coordinates(Coordinate...coordinates) {
return this.coordinates(Arrays.asList(coordinates));
}
/**
* Add a collection of points to the collection
* Add a collection of coordinates to the collection
*
* @param coordinates array of {@link Coordinate}s to add
* @return this
*/
public E points(Collection<? extends Coordinate> coordinates) {
this.points.addAll(coordinates);
public E coordinates(Collection<? extends Coordinate> coordinates) {
this.coordinates.addAll(coordinates);
return thisRef();
}
/**
* Copy all points to a new Array
* Copy all coordinate to a new Array
*
* @param closed if set to true the first point of the array is repeated as last element
* @return Array of coordinates
*/
protected Coordinate[] coordinates(boolean closed) {
Coordinate[] result = points.toArray(new Coordinate[points.size() + (closed?1:0)]);
Coordinate[] result = coordinates.toArray(new Coordinate[coordinates.size() + (closed?1:0)]);
if(closed) {
result[result.length-1] = result[0];
}
@ -111,14 +117,14 @@ public abstract class PointCollection<E extends PointCollection<E>> extends Shap
*/
protected XContentBuilder coordinatesToXcontent(XContentBuilder builder, boolean closed) throws IOException {
builder.startArray();
for(Coordinate point : points) {
toXContent(builder, point);
for(Coordinate coord : coordinates) {
toXContent(builder, coord);
}
if(closed) {
Coordinate start = points.get(0);
Coordinate end = points.get(points.size()-1);
Coordinate start = coordinates.get(0);
Coordinate end = coordinates.get(coordinates.size()-1);
if(start.x != end.x || start.y != end.y) {
toXContent(builder, points.get(0));
toXContent(builder, coordinates.get(0));
}
}
builder.endArray();

View File

@ -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 coordinates.
* Enables chaining of individual coordinates either as long/lat pairs
* or as {@link Coordinate} elements, arrays or collections.
*/
public class CoordinatesBuilder {
private final List<Coordinate> points = new ArrayList<>();
/**
* Add a new coordinate to the collection
* @param coordinate the coordinate to add
* @return this
*/
public CoordinatesBuilder coordinate(Coordinate coordinate) {
this.points.add(coordinate);
return this;
}
/**
* Add a new coordinate to the collection
* @param longitude longitude of the coordinate
* @param latitude latitude of the coordinate
* @return this
*/
public CoordinatesBuilder coordinate(double longitude, double latitude) {
return this.coordinate(new Coordinate(longitude, latitude));
}
/**
* Add an array of coordinates to the current coordinates
*
* @param coordinates array of {@link Coordinate}s to add
* @return this
*/
public CoordinatesBuilder coordinates(Coordinate...coordinates) {
return this.coordinates(Arrays.asList(coordinates));
}
/**
* Add a collection of coordinates to the current coordinates
*
* @param coordinates collection of {@link Coordinate}s to add
* @return this
*/
public CoordinatesBuilder coordinates(Collection<? extends Coordinate> coordinates) {
this.points.addAll(coordinates);
return this;
}
/**
* Makes a closed ring out of the current coordinates by adding the starting point as the end point.
* Will have no effect of starting and end point are already the same coordinate.
*/
public CoordinatesBuilder 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 a list containing the current coordinates
*/
public List<Coordinate> build() {
return new ArrayList<>(this.points);
}
}

View File

@ -21,6 +21,7 @@ package org.elasticsearch.common.geo.builders;
import com.spatial4j.core.shape.Rectangle;
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;
@ -32,33 +33,22 @@ public class EnvelopeBuilder extends ShapeBuilder {
public static final GeoShapeType TYPE = GeoShapeType.ENVELOPE;
public static final EnvelopeBuilder PROTOTYPE = new EnvelopeBuilder();
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 +100,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));
}
}

View File

@ -20,6 +20,7 @@
package org.elasticsearch.common.geo.builders;
import com.spatial4j.core.shape.Shape;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.geo.XShapeCollection;
import org.elasticsearch.common.io.stream.StreamInput;
@ -35,7 +36,7 @@ public class GeometryCollectionBuilder extends ShapeBuilder {
public static final GeoShapeType TYPE = GeoShapeType.GEOMETRYCOLLECTION;
public static final GeometryCollectionBuilder PROTOTYPE = new GeometryCollectionBuilder();
static final GeometryCollectionBuilder PROTOTYPE = new GeometryCollectionBuilder();
protected final ArrayList<ShapeBuilder> shapes = new ArrayList<>();

View File

@ -24,6 +24,7 @@ import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -31,13 +32,32 @@ 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> {
public class LineStringBuilder extends CoordinateCollection<LineStringBuilder> {
/**
* Construct a new LineString.
* Per GeoJSON spec (http://geojson.org/geojson-spec.html#linestring)
* a LineString must contain two or more coordinates
* @param coordinates the initial list of coordinates
* @throw {@link IllegalArgumentException} if there are less then two coordinates defined
*/
public LineStringBuilder(List<Coordinate> coordinates) {
super(coordinates);
if (coordinates.size() < 2) {
throw new IllegalArgumentException("invalid number of points in LineString (found [" + coordinates.size()+ "] - must be >= 2)");
}
}
public LineStringBuilder(CoordinatesBuilder coordinates) {
this(coordinates.build());
}
public static final GeoShapeType TYPE = GeoShapeType.LINESTRING;
public static final LineStringBuilder PROTOTYPE = new LineStringBuilder();
static final LineStringBuilder PROTOTYPE = new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0).coordinate(1.0, 1.0));
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
@ -50,13 +70,14 @@ public class LineStringBuilder extends PointCollection<LineStringBuilder> {
}
/**
* Closes the current lineString by adding the starting point as the end point
* Closes the current lineString by adding the starting point as the end point.
* This will have no effect if starting and end point are already the same.
*/
public LineStringBuilder close() {
Coordinate start = points.get(0);
Coordinate end = points.get(points.size()-1);
Coordinate start = coordinates.get(0);
Coordinate end = coordinates.get(coordinates.size() - 1);
if(start.x != end.x || start.y != end.y) {
points.add(start);
coordinates.add(start);
}
return this;
}
@ -68,7 +89,7 @@ public class LineStringBuilder extends PointCollection<LineStringBuilder> {
@Override
public Shape build() {
Coordinate[] coordinates = points.toArray(new Coordinate[points.size()]);
Coordinate[] coordinates = this.coordinates.toArray(new Coordinate[this.coordinates.size()]);
Geometry geometry;
if(wrapdateline) {
ArrayList<LineString> strings = decompose(FACTORY, coordinates, new ArrayList<LineString>());
@ -147,7 +168,7 @@ public class LineStringBuilder extends PointCollection<LineStringBuilder> {
@Override
public int hashCode() {
return Objects.hash(points);
return Objects.hash(coordinates);
}
@Override
@ -159,24 +180,25 @@ public class LineStringBuilder extends PointCollection<LineStringBuilder> {
return false;
}
LineStringBuilder other = (LineStringBuilder) obj;
return Objects.equals(points, other.points);
return Objects.equals(coordinates, other.coordinates);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVInt(points.size());
for (Coordinate point : points) {
out.writeVInt(coordinates.size());
for (Coordinate point : coordinates) {
writeCoordinateTo(point, out);
}
}
@Override
public LineStringBuilder readFrom(StreamInput in) throws IOException {
LineStringBuilder lineStringBuilder = new LineStringBuilder();
CoordinatesBuilder coordinates = new CoordinatesBuilder();
int size = in.readVInt();
for (int i=0; i < size; i++) {
lineStringBuilder.point(readCoordinateFrom(in));
coordinates.coordinate(readCoordinateFrom(in));
}
LineStringBuilder lineStringBuilder = new LineStringBuilder(coordinates);
return lineStringBuilder;
}
}

View File

@ -23,6 +23,7 @@ import com.spatial4j.core.shape.Shape;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -36,7 +37,7 @@ public class MultiLineStringBuilder extends ShapeBuilder {
public static final GeoShapeType TYPE = GeoShapeType.MULTILINESTRING;
public static final MultiLineStringBuilder PROTOTYPE = new MultiLineStringBuilder();
static final MultiLineStringBuilder PROTOTYPE = new MultiLineStringBuilder();
private final ArrayList<LineStringBuilder> lines = new ArrayList<>();
@ -45,10 +46,6 @@ public class MultiLineStringBuilder extends ShapeBuilder {
return this;
}
public MultiLineStringBuilder linestring(Coordinate[] coordinates) {
return this.linestring(new LineStringBuilder().points(coordinates));
}
public Coordinate[][] coordinates() {
Coordinate[][] result = new Coordinate[lines.size()][];
for (int i = 0; i < result.length; i++) {

View File

@ -22,6 +22,7 @@ package org.elasticsearch.common.geo.builders;
import com.spatial4j.core.shape.Point;
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;
@ -32,11 +33,19 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class MultiPointBuilder extends PointCollection<MultiPointBuilder> {
public class MultiPointBuilder extends CoordinateCollection<MultiPointBuilder> {
public static final GeoShapeType TYPE = GeoShapeType.MULTIPOINT;
public final static MultiPointBuilder PROTOTYPE = new MultiPointBuilder();
final static MultiPointBuilder PROTOTYPE = new MultiPointBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0).build());
/**
* Create a new {@link MultiPointBuilder}.
* @param coordinates needs at least two coordinates to be valid, otherwise will throw an exception
*/
public MultiPointBuilder(List<Coordinate> coordinates) {
super(coordinates);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
@ -52,8 +61,8 @@ public class MultiPointBuilder extends PointCollection<MultiPointBuilder> {
public Shape build() {
//Could wrap JtsGeometry but probably slower due to conversions to/from JTS in relate()
//MultiPoint geometry = FACTORY.createMultiPoint(points.toArray(new Coordinate[points.size()]));
List<Point> shapes = new ArrayList<>(points.size());
for (Coordinate coord : points) {
List<Point> shapes = new ArrayList<>(coordinates.size());
for (Coordinate coord : coordinates) {
shapes.add(SPATIAL_CONTEXT.makePoint(coord.x, coord.y));
}
XShapeCollection<Point> multiPoints = new XShapeCollection<>(shapes, SPATIAL_CONTEXT);
@ -68,7 +77,7 @@ public class MultiPointBuilder extends PointCollection<MultiPointBuilder> {
@Override
public int hashCode() {
return Objects.hash(points);
return Objects.hash(coordinates);
}
@Override
@ -80,24 +89,26 @@ public class MultiPointBuilder extends PointCollection<MultiPointBuilder> {
return false;
}
MultiPointBuilder other = (MultiPointBuilder) obj;
return Objects.equals(points, other.points);
return Objects.equals(coordinates, other.coordinates);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVInt(points.size());
for (Coordinate point : points) {
out.writeVInt(coordinates.size());
for (Coordinate point : coordinates) {
writeCoordinateTo(point, out);
}
}
@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;
}
}

View File

@ -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;
@ -35,7 +36,7 @@ import java.util.Objects;
public class MultiPolygonBuilder extends ShapeBuilder {
public static final GeoShapeType TYPE = GeoShapeType.MULTIPOLYGON;
public static final MultiPolygonBuilder PROTOTYPE = new MultiPolygonBuilder();
static final MultiPolygonBuilder PROTOTYPE = new MultiPolygonBuilder();
private final ArrayList<PolygonBuilder> polygons = new ArrayList<>();
@ -58,8 +59,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(new CoordinatesBuilder().coordinates(polygon.shell().coordinates(false)), this.orientation);
for (LineStringBuilder hole : polygon.holes()) {
pb.hole(hole);
}

View File

@ -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;
@ -31,10 +32,17 @@ import java.util.Objects;
public class PointBuilder extends ShapeBuilder {
public static final GeoShapeType TYPE = GeoShapeType.POINT;
public static final PointBuilder PROTOTYPE = new PointBuilder();
static final PointBuilder PROTOTYPE = new PointBuilder();
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;

View File

@ -27,6 +27,7 @@ import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
@ -52,7 +53,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();
static final PolygonBuilder PROTOTYPE = new PolygonBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0).coordinate(0.0, 1.0)
.coordinate(1.0, 0.0).coordinate(0.0, 0.0));
private static final Coordinate[][] EMPTY = new Coordinate[0][];
@ -64,54 +66,51 @@ 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(Orientation orientation) {
this(new ArrayList<Coordinate>(), orientation);
}
public PolygonBuilder(ArrayList<Coordinate> points, Orientation orientation) {
public PolygonBuilder(LineStringBuilder lineString, Orientation orientation, boolean coerce) {
this.orientation = orientation;
this.shell = new LineStringBuilder().points(points);
if (coerce) {
lineString.close();
}
validateLinearRing(lineString);
this.shell = lineString;
}
public PolygonBuilder(LineStringBuilder lineString, Orientation orientation) {
this(lineString, orientation, false);
}
public PolygonBuilder(CoordinatesBuilder coordinates, Orientation orientation) {
this(new LineStringBuilder(coordinates), orientation, false);
}
public PolygonBuilder(CoordinatesBuilder coordinates) {
this(coordinates, 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) {
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, it will try to close the hole by adding starting point as end point
* @return this
*/
public PolygonBuilder hole(LineStringBuilder hole, boolean coerce) {
if (coerce) {
hole.close();
}
validateLinearRing(hole);
holes.add(hole);
return this;
}
@ -138,12 +137,30 @@ public class PolygonBuilder extends ShapeBuilder {
return this;
}
private static void validateLinearRing(LineStringBuilder lineString) {
/**
* 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.
*/
List<Coordinate> points = lineString.coordinates;
if (points.size() < 4) {
throw new IllegalArgumentException(
"invalid number of points in LinearRing (found [" + points.size() + "] - must be >= 4)");
}
if (!points.get(0).equals(points.get(points.size() - 1))) {
throw new IllegalArgumentException("invalid LinearRing found (coordinates are not closed)");
}
}
/**
* Validates only 1 vertex is tangential (shared) between the interior and exterior of a polygon
*/
protected void validateHole(LineStringBuilder shell, LineStringBuilder hole) {
HashSet<Coordinate> exterior = Sets.newHashSet(shell.points);
HashSet<Coordinate> interior = Sets.newHashSet(hole.points);
HashSet<Coordinate> exterior = Sets.newHashSet(shell.coordinates);
HashSet<Coordinate> interior = Sets.newHashSet(hole.coordinates);
exterior.retainAll(interior);
if (exterior.size() >= 2) {
throw new InvalidShapeException("Invalid polygon, interior cannot share more than one point with the exterior");
@ -161,9 +178,9 @@ public class PolygonBuilder extends ShapeBuilder {
* @return coordinates of the polygon
*/
public Coordinate[][][] coordinates() {
int numEdges = shell.points.size()-1; // Last point is repeated
int numEdges = shell.coordinates.size()-1; // Last point is repeated
for (int i = 0; i < holes.size(); i++) {
numEdges += holes.get(i).points.size()-1;
numEdges += holes.get(i).coordinates.size()-1;
validateHole(shell, this.holes.get(i));
}
@ -226,16 +243,16 @@ public class PolygonBuilder extends ShapeBuilder {
}
protected Polygon toPolygon(GeometryFactory factory) {
final LinearRing shell = linearRing(factory, this.shell.points);
final LinearRing shell = linearRing(factory, this.shell.coordinates);
final LinearRing[] holes = new LinearRing[this.holes.size()];
Iterator<LineStringBuilder> iterator = this.holes.iterator();
for (int i = 0; iterator.hasNext(); i++) {
holes[i] = linearRing(factory, iterator.next().points);
holes[i] = linearRing(factory, iterator.next().coordinates);
}
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 +728,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 +738,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, orientation);
int holes = in.readVInt();
for (int i = 0; i < holes; i++) {
polyBuilder.hole(LineStringBuilder.PROTOTYPE.readFrom(in));

View File

@ -26,6 +26,7 @@ import com.spatial4j.core.shape.jts.JtsGeometry;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.action.support.ToXContentToBytes;
import org.elasticsearch.common.io.stream.NamedWriteable;
@ -64,6 +65,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();
@ -81,11 +87,6 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
protected final boolean autoIndexJtsGeometry = true;//may want to turn off once SpatialStrategy impls do it.
protected ShapeBuilder() {
}
protected static Coordinate coordinate(double longitude, double latitude) {
return new Coordinate(longitude, latitude);
}
protected JtsGeometry jtsGeometry(Geometry geom) {
@ -569,7 +570,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 +590,11 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
protected static MultiPointBuilder parseMultiPoint(CoordinateNode coordinates) {
validateMultiPointNode(coordinates);
MultiPointBuilder points = new MultiPointBuilder();
CoordinatesBuilder points = new CoordinatesBuilder();
for (CoordinateNode node : coordinates.children) {
points.point(node.coordinate);
points.coordinate(node.coordinate);
}
return points;
return new MultiPointBuilder(points.build());
}
protected static LineStringBuilder parseLineString(CoordinateNode coordinates) {
@ -607,11 +607,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();
CoordinatesBuilder line = new CoordinatesBuilder();
for (CoordinateNode node : coordinates.children) {
line.point(node.coordinate);
line.coordinate(node.coordinate);
}
return line;
return ShapeBuilders.newLineString(line);
}
protected static MultiLineStringBuilder parseMultiLine(CoordinateNode coordinates) {
@ -659,7 +659,7 @@ public abstract class ShapeBuilder extends ToXContentToBytes implements NamedWri
}
LineStringBuilder shell = parseLinearRing(coordinates.children.get(0), coerce);
PolygonBuilder polygon = new PolygonBuilder(shell.points, orientation);
PolygonBuilder polygon = new PolygonBuilder(shell, orientation);
for (int i = 1; i < coordinates.children.size(); i++) {
polygon.hole(parseLinearRing(coordinates.children.get(i), coerce));
}

View File

@ -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,24 @@ 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);
}
/**
* Create a new lineString
* @return a new {@link LineStringBuilder}
*/
public static LineStringBuilder newLineString(CoordinatesBuilder coordinates) {
return new LineStringBuilder(coordinates);
}
/**
@ -71,19 +81,19 @@ public class ShapeBuilders {
}
/**
* Create a new Polygon
* @return a new {@link PointBuilder}
* Create a new PolygonBuilder
* @return a new {@link PolygonBuilder}
*/
public static PolygonBuilder newPolygon() {
return new PolygonBuilder();
public static PolygonBuilder newPolygon(List<Coordinate> shell) {
return new PolygonBuilder(new CoordinatesBuilder().coordinates(shell));
}
/**
* Create a new Polygon
* @return a new {@link PointBuilder}
* Create a new PolygonBuilder
* @return a new {@link PolygonBuilder}
*/
public static PolygonBuilder newPolygon(ShapeBuilder.Orientation orientation) {
return new PolygonBuilder(orientation);
public static PolygonBuilder newPolygon(CoordinatesBuilder shell) {
return new PolygonBuilder(shell);
}
/**
@ -124,7 +134,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);
}
}

View File

@ -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;

View File

@ -28,6 +28,8 @@ import com.spatial4j.core.shape.impl.PointImpl;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Polygon;
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
import org.elasticsearch.common.geo.builders.LineStringBuilder;
import org.elasticsearch.common.geo.builders.PolygonBuilder;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
@ -50,7 +52,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 +60,12 @@ public class ShapeBuilderTests extends ESTestCase {
}
public void testNewPolygon() {
Polygon polygon = ShapeBuilders.newPolygon()
.point(-45, 30)
.point(45, 30)
.point(45, -30)
.point(-45, -30)
.point(-45, 30).toPolygon();
Polygon polygon = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-45, 30)
.coordinate(45, 30)
.coordinate(45, -30)
.coordinate(-45, -30)
.coordinate(-45, 30)).toPolygon();
LineString exterior = polygon.getExteriorRing();
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
@ -73,12 +75,12 @@ public class ShapeBuilderTests extends ESTestCase {
}
public void testNewPolygon_coordinate() {
Polygon polygon = ShapeBuilders.newPolygon()
.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();
Polygon polygon = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(new Coordinate(-45, 30))
.coordinate(new Coordinate(45, 30))
.coordinate(new Coordinate(45, -30))
.coordinate(new Coordinate(-45, -30))
.coordinate(new Coordinate(-45, 30))).toPolygon();
LineString exterior = polygon.getExteriorRing();
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
@ -88,8 +90,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 CoordinatesBuilder()
.coordinates(new Coordinate(-45, 30), new Coordinate(45, 30), new Coordinate(45, -30), new Coordinate(-45, -30), new Coordinate(-45, 30))
).toPolygon();
LineString exterior = polygon.getExteriorRing();
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
@ -100,86 +103,93 @@ public class ShapeBuilderTests extends ESTestCase {
public void testLineStringBuilder() {
// Building a simple LineString
ShapeBuilders.newLineString()
.point(-130.0, 55.0)
.point(-130.0, -40.0)
.point(-15.0, -40.0)
.point(-20.0, 50.0)
.point(-45.0, 50.0)
.point(-45.0, -15.0)
.point(-110.0, -15.0)
.point(-110.0, 55.0).build();
ShapeBuilders.newLineString(new CoordinatesBuilder()
.coordinate(-130.0, 55.0)
.coordinate(-130.0, -40.0)
.coordinate(-15.0, -40.0)
.coordinate(-20.0, 50.0)
.coordinate(-45.0, 50.0)
.coordinate(-45.0, -15.0)
.coordinate(-110.0, -15.0)
.coordinate(-110.0, 55.0)).build();
// Building a linestring that needs to be wrapped
ShapeBuilders.newLineString()
.point(100.0, 50.0)
.point(110.0, -40.0)
.point(240.0, -40.0)
.point(230.0, 60.0)
.point(200.0, 60.0)
.point(200.0, -30.0)
.point(130.0, -30.0)
.point(130.0, 60.0)
ShapeBuilders.newLineString(new CoordinatesBuilder()
.coordinate(100.0, 50.0)
.coordinate(110.0, -40.0)
.coordinate(240.0, -40.0)
.coordinate(230.0, 60.0)
.coordinate(200.0, 60.0)
.coordinate(200.0, -30.0)
.coordinate(130.0, -30.0)
.coordinate(130.0, 60.0)
)
.build();
// Building a lineString on the dateline
ShapeBuilders.newLineString()
.point(-180.0, 80.0)
.point(-180.0, 40.0)
.point(-180.0, -40.0)
.point(-180.0, -80.0)
ShapeBuilders.newLineString(new CoordinatesBuilder()
.coordinate(-180.0, 80.0)
.coordinate(-180.0, 40.0)
.coordinate(-180.0, -40.0)
.coordinate(-180.0, -80.0)
)
.build();
// Building a lineString on the dateline
ShapeBuilders.newLineString()
.point(180.0, 80.0)
.point(180.0, 40.0)
.point(180.0, -40.0)
.point(180.0, -80.0)
ShapeBuilders.newLineString(new CoordinatesBuilder()
.coordinate(180.0, 80.0)
.coordinate(180.0, 40.0)
.coordinate(180.0, -40.0)
.coordinate(180.0, -80.0)
)
.build();
}
public void testMultiLineString() {
ShapeBuilders.newMultiLinestring()
.linestring(new LineStringBuilder()
.point(-100.0, 50.0)
.point(50.0, 50.0)
.point(50.0, 20.0)
.point(-100.0, 20.0)
.linestring(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(-100.0, 50.0)
.coordinate(50.0, 50.0)
.coordinate(50.0, 20.0)
.coordinate(-100.0, 20.0)
)
)
.linestring(new LineStringBuilder()
.point(-100.0, 20.0)
.point(50.0, 20.0)
.point(50.0, 0.0)
.point(-100.0, 0.0)
.linestring(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(-100.0, 20.0)
.coordinate(50.0, 20.0)
.coordinate(50.0, 0.0)
.coordinate(-100.0, 0.0)
)
)
.build();
// LineString that needs to be wrappped
ShapeBuilders.newMultiLinestring()
.linestring(new LineStringBuilder()
.point(150.0, 60.0)
.point(200.0, 60.0)
.point(200.0, 40.0)
.point(150.0, 40.0)
.linestring(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(150.0, 60.0)
.coordinate(200.0, 60.0)
.coordinate(200.0, 40.0)
.coordinate(150.0, 40.0)
)
)
.linestring(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(150.0, 20.0)
.coordinate(200.0, 20.0)
.coordinate(200.0, 0.0)
.coordinate(150.0, 0.0)
)
.linestring(new LineStringBuilder()
.point(150.0, 20.0)
.point(200.0, 20.0)
.point(200.0, 0.0)
.point(150.0, 0.0)
)
.build();
}
public void testPolygonSelfIntersection() {
try {
ShapeBuilders.newPolygon()
.point(-40.0, 50.0)
.point(40.0, 50.0)
.point(-40.0, -50.0)
.point(40.0, -50.0)
.close().build();
ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-40.0, 50.0)
.coordinate(40.0, 50.0)
.coordinate(-40.0, -50.0)
.coordinate(40.0, -50.0).close())
.build();
fail("Expected InvalidShapeException");
} catch (InvalidShapeException e) {
assertThat(e.getMessage(), containsString("Self-intersection at or near point (0.0"));
@ -212,22 +222,26 @@ public class ShapeBuilderTests extends ESTestCase {
}
public void testPolygonWrapping() {
Shape shape = ShapeBuilders.newPolygon()
.point(-150.0, 65.0)
.point(-250.0, 65.0)
.point(-250.0, -65.0)
.point(-150.0, -65.0)
.close().build();
Shape shape = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-150.0, 65.0)
.coordinate(-250.0, 65.0)
.coordinate(-250.0, -65.0)
.coordinate(-150.0, -65.0)
.close()
)
.build();
assertMultiPolygon(shape);
}
public void testLineStringWrapping() {
Shape shape = ShapeBuilders.newLineString()
.point(-150.0, 65.0)
.point(-250.0, 65.0)
.point(-250.0, -65.0)
.point(-150.0, -65.0)
Shape shape = ShapeBuilders.newLineString(new CoordinatesBuilder()
.coordinate(-150.0, 65.0)
.coordinate(-250.0, 65.0)
.coordinate(-250.0, -65.0)
.coordinate(-150.0, -65.0)
.close()
)
.build();
assertMultiLineString(shape);
}
@ -238,36 +252,39 @@ public class ShapeBuilderTests extends ESTestCase {
// expected results: 3 polygons, 1 with a hole
// a giant c shape
PolygonBuilder builder = ShapeBuilders.newPolygon()
.point(174,0)
.point(-176,0)
.point(-176,3)
.point(177,3)
.point(177,5)
.point(-176,5)
.point(-176,8)
.point(174,8)
.point(174,0);
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(174,0)
.coordinate(-176,0)
.coordinate(-176,3)
.coordinate(177,3)
.coordinate(177,5)
.coordinate(-176,5)
.coordinate(-176,8)
.coordinate(174,8)
.coordinate(174,0)
);
// 3/4 of an embedded 'c', crossing dateline once
builder.hole(new LineStringBuilder()
.point(175, 1)
.point(175, 7)
.point(-178, 7)
.point(-178, 6)
.point(176, 6)
.point(176, 2)
.point(179, 2)
.point(179,1)
.point(175, 1));
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(175, 1)
.coordinate(175, 7)
.coordinate(-178, 7)
.coordinate(-178, 6)
.coordinate(176, 6)
.coordinate(176, 2)
.coordinate(179, 2)
.coordinate(179,1)
.coordinate(175, 1)
));
// embedded hole right of the dateline
builder.hole(new LineStringBuilder()
.point(-179, 1)
.point(-179, 2)
.point(-177, 2)
.point(-177,1)
.point(-179,1));
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(-179, 1)
.coordinate(-179, 2)
.coordinate(-177, 2)
.coordinate(-177,1)
.coordinate(-179,1)
));
Shape shape = builder.close().build();
assertMultiPolygon(shape);
@ -279,141 +296,150 @@ public class ShapeBuilderTests extends ESTestCase {
// expected results: 3 polygons, 1 with a hole
// a giant c shape
PolygonBuilder builder = ShapeBuilders.newPolygon()
.point(-186,0)
.point(-176,0)
.point(-176,3)
.point(-183,3)
.point(-183,5)
.point(-176,5)
.point(-176,8)
.point(-186,8)
.point(-186,0);
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-186,0)
.coordinate(-176,0)
.coordinate(-176,3)
.coordinate(-183,3)
.coordinate(-183,5)
.coordinate(-176,5)
.coordinate(-176,8)
.coordinate(-186,8)
.coordinate(-186,0)
);
// 3/4 of an embedded 'c', crossing dateline once
builder.hole(new LineStringBuilder()
.point(-185,1)
.point(-181,1)
.point(-181,2)
.point(-184,2)
.point(-184,6)
.point(-178,6)
.point(-178,7)
.point(-185,7)
.point(-185,1));
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(-185,1)
.coordinate(-181,1)
.coordinate(-181,2)
.coordinate(-184,2)
.coordinate(-184,6)
.coordinate(-178,6)
.coordinate(-178,7)
.coordinate(-185,7)
.coordinate(-185,1)
));
// embedded hole right of the dateline
builder.hole(new LineStringBuilder()
.point(-179,1)
.point(-177,1)
.point(-177,2)
.point(-179,2)
.point(-179,1));
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(-179,1)
.coordinate(-177,1)
.coordinate(-177,2)
.coordinate(-179,2)
.coordinate(-179,1)
));
Shape shape = builder.close().build();
assertMultiPolygon(shape);
}
public void testComplexShapeWithHole() {
PolygonBuilder builder = ShapeBuilders.newPolygon()
.point(-85.0018514,37.1311314)
.point(-85.0016645,37.1315293)
.point(-85.0016246,37.1317069)
.point(-85.0016526,37.1318183)
.point(-85.0017119,37.1319196)
.point(-85.0019371,37.1321182)
.point(-85.0019972,37.1322115)
.point(-85.0019942,37.1323234)
.point(-85.0019543,37.1324336)
.point(-85.001906,37.1324985)
.point(-85.001834,37.1325497)
.point(-85.0016965,37.1325907)
.point(-85.0016011,37.1325873)
.point(-85.0014816,37.1325353)
.point(-85.0011755,37.1323509)
.point(-85.000955,37.1322802)
.point(-85.0006241,37.1322529)
.point(-85.0000002,37.1322307)
.point(-84.9994,37.1323001)
.point(-84.999109,37.1322864)
.point(-84.998934,37.1322415)
.point(-84.9988639,37.1321888)
.point(-84.9987841,37.1320944)
.point(-84.9987208,37.131954)
.point(-84.998736,37.1316611)
.point(-84.9988091,37.131334)
.point(-84.9989283,37.1311337)
.point(-84.9991943,37.1309198)
.point(-84.9993573,37.1308459)
.point(-84.9995888,37.1307924)
.point(-84.9998746,37.130806)
.point(-85.0000002,37.1308358)
.point(-85.0004984,37.1310658)
.point(-85.0008008,37.1311625)
.point(-85.0009461,37.1311684)
.point(-85.0011373,37.1311515)
.point(-85.0016455,37.1310491)
.point(-85.0018514,37.1311314);
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-85.0018514,37.1311314)
.coordinate(-85.0016645,37.1315293)
.coordinate(-85.0016246,37.1317069)
.coordinate(-85.0016526,37.1318183)
.coordinate(-85.0017119,37.1319196)
.coordinate(-85.0019371,37.1321182)
.coordinate(-85.0019972,37.1322115)
.coordinate(-85.0019942,37.1323234)
.coordinate(-85.0019543,37.1324336)
.coordinate(-85.001906,37.1324985)
.coordinate(-85.001834,37.1325497)
.coordinate(-85.0016965,37.1325907)
.coordinate(-85.0016011,37.1325873)
.coordinate(-85.0014816,37.1325353)
.coordinate(-85.0011755,37.1323509)
.coordinate(-85.000955,37.1322802)
.coordinate(-85.0006241,37.1322529)
.coordinate(-85.0000002,37.1322307)
.coordinate(-84.9994,37.1323001)
.coordinate(-84.999109,37.1322864)
.coordinate(-84.998934,37.1322415)
.coordinate(-84.9988639,37.1321888)
.coordinate(-84.9987841,37.1320944)
.coordinate(-84.9987208,37.131954)
.coordinate(-84.998736,37.1316611)
.coordinate(-84.9988091,37.131334)
.coordinate(-84.9989283,37.1311337)
.coordinate(-84.9991943,37.1309198)
.coordinate(-84.9993573,37.1308459)
.coordinate(-84.9995888,37.1307924)
.coordinate(-84.9998746,37.130806)
.coordinate(-85.0000002,37.1308358)
.coordinate(-85.0004984,37.1310658)
.coordinate(-85.0008008,37.1311625)
.coordinate(-85.0009461,37.1311684)
.coordinate(-85.0011373,37.1311515)
.coordinate(-85.0016455,37.1310491)
.coordinate(-85.0018514,37.1311314)
);
builder.hole(new LineStringBuilder()
.point(-85.0000002,37.1317672)
.point(-85.0001983,37.1317538)
.point(-85.0003378,37.1317582)
.point(-85.0004697,37.131792)
.point(-85.0008048,37.1319439)
.point(-85.0009342,37.1319838)
.point(-85.0010184,37.1319463)
.point(-85.0010618,37.13184)
.point(-85.0010057,37.1315102)
.point(-85.000977,37.1314403)
.point(-85.0009182,37.1313793)
.point(-85.0005366,37.1312209)
.point(-85.000224,37.1311466)
.point(-85.000087,37.1311356)
.point(-85.0000002,37.1311433)
.point(-84.9995021,37.1312336)
.point(-84.9993308,37.1312859)
.point(-84.9992567,37.1313252)
.point(-84.9991868,37.1314277)
.point(-84.9991593,37.1315381)
.point(-84.9991841,37.1316527)
.point(-84.9992329,37.1317117)
.point(-84.9993527,37.1317788)
.point(-84.9994931,37.1318061)
.point(-84.9996815,37.1317979)
.point(-85.0000002,37.1317672));
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(-85.0000002,37.1317672)
.coordinate(-85.0001983,37.1317538)
.coordinate(-85.0003378,37.1317582)
.coordinate(-85.0004697,37.131792)
.coordinate(-85.0008048,37.1319439)
.coordinate(-85.0009342,37.1319838)
.coordinate(-85.0010184,37.1319463)
.coordinate(-85.0010618,37.13184)
.coordinate(-85.0010057,37.1315102)
.coordinate(-85.000977,37.1314403)
.coordinate(-85.0009182,37.1313793)
.coordinate(-85.0005366,37.1312209)
.coordinate(-85.000224,37.1311466)
.coordinate(-85.000087,37.1311356)
.coordinate(-85.0000002,37.1311433)
.coordinate(-84.9995021,37.1312336)
.coordinate(-84.9993308,37.1312859)
.coordinate(-84.9992567,37.1313252)
.coordinate(-84.9991868,37.1314277)
.coordinate(-84.9991593,37.1315381)
.coordinate(-84.9991841,37.1316527)
.coordinate(-84.9992329,37.1317117)
.coordinate(-84.9993527,37.1317788)
.coordinate(-84.9994931,37.1318061)
.coordinate(-84.9996815,37.1317979)
.coordinate(-85.0000002,37.1317672)
)
);
Shape shape = builder.close().build();
assertPolygon(shape);
}
public void testShapeWithHoleAtEdgeEndPoints() {
PolygonBuilder builder = ShapeBuilders.newPolygon()
.point(-4, 2)
.point(4, 2)
.point(6, 0)
.point(4, -2)
.point(-4, -2)
.point(-6, 0)
.point(-4, 2);
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-4, 2)
.coordinate(4, 2)
.coordinate(6, 0)
.coordinate(4, -2)
.coordinate(-4, -2)
.coordinate(-6, 0)
.coordinate(-4, 2)
);
builder.hole(new LineStringBuilder()
.point(4, 1)
.point(4, -1)
.point(-4, -1)
.point(-4, 1)
.point(4, 1));
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(4, 1)
.coordinate(4, -1)
.coordinate(-4, -1)
.coordinate(-4, 1)
.coordinate(4, 1)
));
Shape shape = builder.close().build();
assertPolygon(shape);
}
public void testShapeWithPointOnDateline() {
PolygonBuilder builder = ShapeBuilders.newPolygon()
.point(180, 0)
.point(176, 4)
.point(176, -4)
.point(180, 0);
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(180, 0)
.coordinate(176, 4)
.coordinate(176, -4)
.coordinate(180, 0)
);
Shape shape = builder.close().build();
assertPolygon(shape);
@ -421,21 +447,23 @@ public class ShapeBuilderTests extends ESTestCase {
public void testShapeWithEdgeAlongDateline() {
// test case 1: test the positive side of the dateline
PolygonBuilder builder = ShapeBuilders.newPolygon()
.point(180, 0)
.point(176, 4)
.point(180, -4)
.point(180, 0);
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(180, 0)
.coordinate(176, 4)
.coordinate(180, -4)
.coordinate(180, 0)
);
Shape shape = builder.close().build();
assertPolygon(shape);
// test case 2: test the negative side of the dateline
builder = ShapeBuilders.newPolygon()
.point(-176, 4)
.point(-180, 0)
.point(-180, -4)
.point(-176, 4);
builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-176, 4)
.coordinate(-180, 0)
.coordinate(-180, -4)
.coordinate(-176, 4)
);
shape = builder.close().build();
assertPolygon(shape);
@ -443,73 +471,85 @@ public class ShapeBuilderTests extends ESTestCase {
public void testShapeWithBoundaryHoles() {
// test case 1: test the positive side of the dateline
PolygonBuilder builder = ShapeBuilders.newPolygon()
.point(-177, 10)
.point(176, 15)
.point(172, 0)
.point(176, -15)
.point(-177, -10)
.point(-177, 10);
builder.hole(new LineStringBuilder()
.point(176, 10)
.point(180, 5)
.point(180, -5)
.point(176, -10)
.point(176, 10));
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-177, 10)
.coordinate(176, 15)
.coordinate(172, 0)
.coordinate(176, -15)
.coordinate(-177, -10)
.coordinate(-177, 10)
);
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(176, 10)
.coordinate(180, 5)
.coordinate(180, -5)
.coordinate(176, -10)
.coordinate(176, 10)
));
Shape shape = builder.close().build();
assertMultiPolygon(shape);
// test case 2: test the negative side of the dateline
builder = ShapeBuilders.newPolygon()
.point(-176, 15)
.point(179, 10)
.point(179, -10)
.point(-176, -15)
.point(-172, 0);
builder.hole(new LineStringBuilder()
.point(-176, 10)
.point(-176, -10)
.point(-180, -5)
.point(-180, 5)
.point(-176, 10));
builder = ShapeBuilders.newPolygon(
new CoordinatesBuilder()
.coordinate(-176, 15)
.coordinate(179, 10)
.coordinate(179, -10)
.coordinate(-176, -15)
.coordinate(-172, 0)
.close()
);
builder.hole(new LineStringBuilder(
new CoordinatesBuilder()
.coordinate(-176, 10)
.coordinate(-176, -10)
.coordinate(-180, -5)
.coordinate(-180, 5)
.coordinate(-176, 10)
.close()
));
shape = builder.close().build();
assertMultiPolygon(shape);
}
public void testShapeWithTangentialHole() {
// test a shape with one tangential (shared) vertex (should pass)
PolygonBuilder builder = ShapeBuilders.newPolygon()
.point(179, 10)
.point(168, 15)
.point(164, 0)
.point(166, -15)
.point(179, -10)
.point(179, 10);
builder.hole(new LineStringBuilder()
.point(-177, 10)
.point(-178, -10)
.point(-180, -5)
.point(-180, 5)
.point(-177, 10));
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(179, 10)
.coordinate(168, 15)
.coordinate(164, 0)
.coordinate(166, -15)
.coordinate(179, -10)
.coordinate(179, 10)
);
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(-177, 10)
.coordinate(-178, -10)
.coordinate(-180, -5)
.coordinate(-180, 5)
.coordinate(-177, 10)
));
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()
.point(179, 10)
.point(168, 15)
.point(164, 0)
.point(166, -15)
.point(179, -10)
.point(179, 10);
builder.hole(new LineStringBuilder()
.point(164, 0)
.point(175, 10)
.point(175, 5)
.point(179, -10)
.point(164, 0));
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(179, 10)
.coordinate(168, 15)
.coordinate(164, 0)
.coordinate(166, -15)
.coordinate(179, -10)
.coordinate(179, 10)
);
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(164, 0)
.coordinate(175, 10)
.coordinate(175, 5)
.coordinate(179, -10)
.coordinate(164, 0)
));
try {
builder.close().build();
fail("Expected InvalidShapeException");
@ -520,43 +560,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()
.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)
.point(-178, -10)
.point(-180, -5)
.point(-180, 5)
.point(-177, 10));
builder.hole(new LineStringBuilder()
.point(172, 0)
.point(176, 10)
.point(176, -5)
.point(172, 0));
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-177, 10)
.coordinate(176, 15)
.coordinate(172, 0)
.coordinate(176, -15)
.coordinate(-177, -10)
.coordinate(-177, 10)
);
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(-177, 10)
.coordinate(-178, -10)
.coordinate(-180, -5)
.coordinate(-180, 5)
.coordinate(-177, 10)
));
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(172, 0)
.coordinate(176, 10)
.coordinate(176, -5)
.coordinate(172, 0)
));
Shape shape = builder.close().build();
assertMultiPolygon(shape);
}
public void testBoundaryShapeWithInvalidTangentialHole() {
// test shape with two tangential (shared) vertices (should throw exception)
PolygonBuilder builder = ShapeBuilders.newPolygon()
.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)
.point(172, 0)
.point(180, -5)
.point(176, -10)
.point(-177, 10));
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-177, 10)
.coordinate(176, 15)
.coordinate(172, 0)
.coordinate(176, -15)
.coordinate(-177, -10)
.coordinate(-177, 10)
);
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(-177, 10)
.coordinate(172, 0)
.coordinate(180, -5)
.coordinate(176, -10)
.coordinate(-177, 10)
));
try {
builder.close().build();
fail("Expected InvalidShapeException");
@ -569,11 +614,12 @@ public class ShapeBuilderTests extends ESTestCase {
* Test an enveloping polygon around the max mercator bounds
*/
public void testBoundaryShape() {
PolygonBuilder builder = ShapeBuilders.newPolygon()
.point(-180, 90)
.point(180, 90)
.point(180, -90)
.point(-180, -90);
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-180, 90)
.coordinate(180, 90)
.coordinate(180, -90)
.coordinate(-180, 90)
);
Shape shape = builder.close().build();
@ -582,21 +628,23 @@ public class ShapeBuilderTests extends ESTestCase {
public void testShapeWithAlternateOrientation() {
// cw: should produce a multi polygon spanning hemispheres
PolygonBuilder builder = ShapeBuilders.newPolygon()
.point(180, 0)
.point(176, 4)
.point(-176, 4)
.point(180, 0);
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(180, 0)
.coordinate(176, 4)
.coordinate(-176, 4)
.coordinate(180, 0)
);
Shape shape = builder.close().build();
assertPolygon(shape);
// cw: geo core will convert to ccw across the dateline
builder = ShapeBuilders.newPolygon()
.point(180, 0)
.point(-176, 4)
.point(176, 4)
.point(180, 0);
builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(180, 0)
.coordinate(-176, 4)
.coordinate(176, 4)
.coordinate(180, 0)
);
shape = builder.close().build();
@ -604,12 +652,13 @@ public class ShapeBuilderTests extends ESTestCase {
}
public void testInvalidShapeWithConsecutiveDuplicatePoints() {
PolygonBuilder builder = ShapeBuilders.newPolygon()
.point(180, 0)
.point(176, 4)
.point(176, 4)
.point(-176, 4)
.point(180, 0);
PolygonBuilder builder = ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(180, 0)
.coordinate(176, 4)
.coordinate(176, 4)
.coordinate(-176, 4)
.coordinate(180, 0)
);
try {
builder.close().build();
fail("Expected InvalidShapeException");

View File

@ -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;
/**

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -20,13 +20,40 @@
package org.elasticsearch.common.geo.builders;
import com.vividsolutions.jts.geom.Coordinate;
import org.elasticsearch.test.geo.RandomShapeGenerator;
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
import java.io.IOException;
import java.util.List;
import static org.hamcrest.Matchers.equalTo;
public class LineStringBuilderTests extends AbstractShapeBuilderTestCase<LineStringBuilder> {
public void testInvalidConstructorArgs() {
try {
new LineStringBuilder((List<Coordinate>) null);
fail("Exception expected");
} catch (IllegalArgumentException e) {
assertThat("cannot create point collection with empty set of points", equalTo(e.getMessage()));
}
try {
new LineStringBuilder(new CoordinatesBuilder());
fail("Exception expected");
} catch (IllegalArgumentException e) {
assertThat("cannot create point collection with empty set of points", equalTo(e.getMessage()));
}
try {
new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0));
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();
@ -54,7 +81,7 @@ public class LineStringBuilderTests extends AbstractShapeBuilderTestCase<LineStr
coordinate.y = randomDoubleBetween(-90.0, 90.0, true);
}
}
return mutation.points(coordinates);
return mutation.coordinates(coordinates);
}
static LineStringBuilder createRandomShape() {

View File

@ -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);
}
}

View File

@ -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 CoordinatesBuilder().build());
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 CoordinatesBuilder().coordinate(0.0, 0.0).build());
}
@Override
protected MultiPointBuilder createTestShapeBuilder() {
return createRandomShape();
@ -40,21 +61,25 @@ 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);
return mutation.coordinates(coordinates);
}
static MultiPointBuilder createRandomShape() {

View File

@ -20,12 +20,15 @@
package org.elasticsearch.common.geo.builders;
import com.vividsolutions.jts.geom.Coordinate;
import org.elasticsearch.common.geo.builders.ShapeBuilder.Orientation;
import org.elasticsearch.test.geo.RandomShapeGenerator;
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
import java.io.IOException;
import static org.hamcrest.Matchers.equalTo;
public class PolygonBuilderTests extends AbstractShapeBuilderTestCase<PolygonBuilder> {
@Override
@ -77,8 +80,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(), pb.orientation() == Orientation.LEFT ? Orientation.RIGHT : Orientation.LEFT);
for (LineStringBuilder hole : pb.holes()) {
mutation.hole(hole);
}
@ -92,4 +94,33 @@ public class PolygonBuilderTests extends AbstractShapeBuilderTestCase<PolygonBui
}
return pgb;
}
public void testCoerceShell() {
try{
new PolygonBuilder(new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0)
.coordinate(1.0, 0.0).coordinate(1.0, 1.0).build()), Orientation.RIGHT);
fail("should raise validation exception");
} catch (IllegalArgumentException e) {
assertEquals("invalid number of points in LinearRing (found [3] - must be >= 4)", e.getMessage());
}
PolygonBuilder pb = new PolygonBuilder(new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0)
.coordinate(1.0, 0.0).coordinate(1.0, 1.0).build()), Orientation.RIGHT, true);
assertThat("Shell should have been closed via coerce", pb.shell().coordinates(false).length, equalTo(4));
}
public void testCoerceHole() {
PolygonBuilder pb = new PolygonBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0)
.coordinate(2.0, 0.0).coordinate(2.0, 2.0).coordinate(0.0, 0.0));
try{
pb.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0,0.0).coordinate(1.0,0.0).coordinate(1.0,1.0).build()));
fail("should raise validation exception");
} catch (IllegalArgumentException e) {
assertEquals("invalid number of points in LinearRing (found [3] - must be >= 4)", e.getMessage());
}
pb.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0,0.0).coordinate(1.0,0.0).coordinate(1.0,1.0).build()), true);
assertThat("hole should have been closed via coerce", pb.holes().get(0).coordinates(false).length, equalTo(4));
}
}

View File

@ -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();
}

View File

@ -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.CoordinatesBuilder;
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()
.point(0, 0)
.point(0, 10)
.point(10, 10)
.point(10, 0)
.point(0, 0));
ShapeBuilders.newMultiPoint(
new CoordinatesBuilder()
.coordinate(0, 0)
.coordinate(0, 10)
.coordinate(10, 10)
.coordinate(10, 0)
.coordinate(0, 0)
.build()));
qb.relation(ShapeRelation.WITHIN);
qb = geoShapeQuery(

View File

@ -23,6 +23,7 @@ import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
import com.spatial4j.core.exception.InvalidShapeException;
import com.spatial4j.core.shape.Shape;
import org.apache.lucene.spatial.prefix.RecursivePrefixTreeStrategy;
import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
import org.apache.lucene.spatial.query.SpatialArgs;
@ -40,6 +41,7 @@ import org.elasticsearch.common.Priority;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
import org.elasticsearch.common.geo.builders.LineStringBuilder;
import org.elasticsearch.common.geo.builders.MultiPolygonBuilder;
import org.elasticsearch.common.geo.builders.PolygonBuilder;
@ -119,30 +121,29 @@ public class GeoFilterIT extends ESIntegTestCase {
public void testShapeBuilders() {
try {
// self intersection polygon
ShapeBuilders.newPolygon()
.point(-10, -10)
.point(10, 10)
.point(-10, 10)
.point(10, -10)
.close().build();
ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-10, -10)
.coordinate(10, 10)
.coordinate(-10, 10)
.coordinate(10, -10)
.close())
.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 CoordinatesBuilder()
.coordinate(-10, -10).coordinate(-10, 10).coordinate(10, 10).coordinate(10, -10).close())
.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(-5, -5).coordinate(-5, 5).coordinate(5, 5).coordinate(5, -5).close()))
.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 CoordinatesBuilder()
.coordinate(-10, -10).coordinate(-10, 10).coordinate(10, 10).coordinate(10, -10).close())
.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(-5, -5).coordinate(-5, 11).coordinate(5, 11).coordinate(5, -5).close()))
.build();
fail("Self intersection not detected");
} catch (InvalidShapeException e) {
@ -150,30 +151,27 @@ 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 CoordinatesBuilder()
.coordinate(-10, -10).coordinate(-10, 10).coordinate(10, 10).coordinate(10, -10).close())
.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(-5, -5).coordinate(-5, 5).coordinate(5, 5).coordinate(5, -5).close()))
.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(-5, -6).coordinate(5, -6).coordinate(5, -4).coordinate(-5, -4).close()))
.build();
fail("Intersection of holes not detected");
} catch (InvalidShapeException e) {
}
try {
// Common line in polygon
ShapeBuilders.newPolygon()
.point(-10, -10)
.point(-10, 10)
.point(-5, 10)
.point(-5, -5)
.point(-5, 20)
.point(10, 20)
.point(10, -10)
.close().build();
ShapeBuilders.newPolygon(new CoordinatesBuilder()
.coordinate(-10, -10)
.coordinate(-10, 10)
.coordinate(-5, 10)
.coordinate(-5, -5)
.coordinate(-5, 20)
.coordinate(10, 20)
.coordinate(10, -10)
.close())
.build();
fail("Self intersection not detected");
} catch (InvalidShapeException e) {
}
@ -181,23 +179,22 @@ public class GeoFilterIT extends ESIntegTestCase {
// Multipolygon: polygon with hole and polygon within the whole
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 CoordinatesBuilder().coordinate(-10, -10)
.coordinate(-10, 10)
.coordinate(10, 10)
.coordinate(10, -10).close())
.hole(new LineStringBuilder(
new CoordinatesBuilder().coordinate(-5, -5)
.coordinate(-5, 5)
.coordinate(5, 5)
.coordinate(5, -5).close())))
.polygon(new PolygonBuilder(
new CoordinatesBuilder()
.coordinate(-4, -4)
.coordinate(-4, 4)
.coordinate(4, 4)
.coordinate(4, -4).close()))
.build();
}
@ -226,14 +223,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 CoordinatesBuilder().coordinate(-10, -10).coordinate(-10, 10).coordinate(10, 10).coordinate(10, -10).close())
.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(-5, -5).coordinate(-5, 5).coordinate(5, 5).coordinate(5, -5).close())))
.polygon(new PolygonBuilder(
new CoordinatesBuilder().coordinate(-4, -4).coordinate(-4, 4).coordinate(4, 4).coordinate(4, -4).close()));
BytesReference data = jsonBuilder().startObject().field("area", polygon).endObject().bytes();
client().prepareIndex("shapes", "polygon", "1").setSource(data).execute().actionGet();
@ -292,11 +287,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 CoordinatesBuilder()
.coordinate(-5, -5).coordinate(-5, 5).coordinate(5, 5).coordinate(5, -5).close())
.hole(new LineStringBuilder(
new CoordinatesBuilder().coordinate(-4, -4).coordinate(-4, 4).coordinate(4, 4).coordinate(4, -4).close()));
data = jsonBuilder().startObject().field("area", inverse).endObject().bytes();
client().prepareIndex("shapes", "polygon", "2").setSource(data).execute().actionGet();
@ -311,16 +305,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 CoordinatesBuilder()
.coordinate(-10, -10).coordinate(-10, 10).coordinate(10, 10).coordinate(10, -10).close())
.hole(new LineStringBuilder(new CoordinatesBuilder()
.coordinate(-5, -5).coordinate(-5, 5).coordinate(10, 5).coordinate(10, -5).close()));
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 CoordinatesBuilder()
.coordinate(-30, -30).coordinate(-30, 30).coordinate(30, 30).coordinate(30, -30).close());
result = client().prepareSearch()
.setQuery(matchAllQuery())
@ -330,19 +323,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 CoordinatesBuilder()
.coordinate(170, -10).coordinate(190, -10).coordinate(190, 10).coordinate(170, 10).close());
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 CoordinatesBuilder()
.coordinate(170, -10).coordinate(190, -10).coordinate(190, 10).coordinate(170, 10).close())
.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(175, -5).coordinate(185, -5).coordinate(185, 5).coordinate(175, 5).close()));
data = jsonBuilder().startObject().field("area", builder).endObject().bytes();
client().prepareIndex("shapes", "polygon", "1").setSource(data).execute().actionGet();

View File

@ -20,9 +20,12 @@
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.CoordinatesBuilder;
import org.elasticsearch.common.geo.builders.EnvelopeBuilder;
import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder;
import org.elasticsearch.common.geo.builders.LineStringBuilder;
@ -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 CoordinatesBuilder()
.coordinate(170, -10).coordinate(190, -10).coordinate(190, 10).coordinate(170, 10).close())
.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(175, -5).coordinate(185, -5).coordinate(185, 5).coordinate(175, 5).close()));
assertUnmodified(polygon);
ShapeBuilder linestring = ShapeBuilders.newLineString()
.point(170, -10).point(190, -10).point(190, 10).point(170, 10);
ShapeBuilder linestring = ShapeBuilders.newLineString(new CoordinatesBuilder()
.coordinate(170, -10).coordinate(190, -10).coordinate(190, 10).coordinate(170, 10).close());
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 CoordinatesBuilder().coordinate(99.0, -1.0).coordinate(99.0, 3.0).coordinate(103.0, 3.0).coordinate(103.0, -1.0)
.coordinate(99.0, -1.0)))).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 CoordinatesBuilder().coordinate(199.0, -11.0).coordinate(199.0, 13.0).coordinate(193.0, 13.0).coordinate(193.0, -11.0)
.coordinate(199.0, -11.0)))).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 CoordinatesBuilder().coordinate(99.0, -1.0).coordinate(99.0, 3.0).coordinate(103.0, 3.0).coordinate(103.0, -1.0).coordinate(99.0, -1.0)))
.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 CoordinatesBuilder().coordinate(199.0, -11.0).coordinate(199.0, 13.0).coordinate(193.0, 13.0).coordinate(193.0, -11.0)
.coordinate(199.0, -11.0)))).relation(ShapeRelation.INTERSECTS);
result = client().prepareSearch("test").setTypes("type").setQuery(QueryBuilders.matchAllQuery())
.setPostFilter(filter).get();
assertSearchResponse(result);

View File

@ -29,13 +29,15 @@ 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.CoordinateCollection;
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder;
import org.elasticsearch.common.geo.builders.LineStringBuilder;
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.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();
CoordinatesBuilder coordinatesBuilder = new CoordinatesBuilder();
for (int i=0; i<numPoints; ++i) {
p = xRandomPointIn(r, within);
pcb.point(p.getX(), p.getY());
coordinatesBuilder.coordinate(p.getX(), p.getY());
}
CoordinateCollection pcb = (st == ShapeType.MULTIPOINT) ? new MultiPointBuilder(coordinatesBuilder.build()) : new LineStringBuilder(coordinatesBuilder);
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 CoordinatesBuilder().coordinates(shellCoords).close());
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