[GEO] Update GeoPolygonFilter to handle ambiguous polygons
PR #8672 addresses ambiguous polygons - those that either cross the dateline or span the map - by complying with the OGC standard right-hand rule. Since ```GeoPolygonFilter``` is self contained logic, the fix in #8672 did not address the issue for the ```GeoPolygonFilter```. This was identified in issue #5968 This fixes the ambiguous polygon issue in ```GeoPolygonFilter``` by moving the dateline crossing code from ```ShapeBuilder``` to ```GeoUtils``` and reusing the logic inside the ```pointInPolygon``` method. Unit tests are added to ensure support for coordinates specified in either standard lat/lon or great-circle coordinate systems. closes #5968 closes #9304
This commit is contained in:
parent
9ac6d78308
commit
06667c6aa8
|
@ -20,13 +20,12 @@
|
|||
package org.elasticsearch.common.geo;
|
||||
|
||||
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final class GeoPoint {
|
||||
|
||||
private double lat;
|
||||
private double lon;
|
||||
public final class GeoPoint extends Coordinate {
|
||||
|
||||
public GeoPoint() {
|
||||
}
|
||||
|
@ -41,32 +40,36 @@ public final class GeoPoint {
|
|||
this.resetFromString(value);
|
||||
}
|
||||
|
||||
public GeoPoint(GeoPoint other) {
|
||||
super(other);
|
||||
}
|
||||
|
||||
public GeoPoint(double lat, double lon) {
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
this.y = lat;
|
||||
this.x = lon;
|
||||
}
|
||||
|
||||
public GeoPoint reset(double lat, double lon) {
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
this.y = lat;
|
||||
this.x = lon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GeoPoint resetLat(double lat) {
|
||||
this.lat = lat;
|
||||
this.y = lat;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GeoPoint resetLon(double lon) {
|
||||
this.lon = lon;
|
||||
this.x = lon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GeoPoint resetFromString(String value) {
|
||||
int comma = value.indexOf(',');
|
||||
if (comma != -1) {
|
||||
lat = Double.parseDouble(value.substring(0, comma).trim());
|
||||
lon = Double.parseDouble(value.substring(comma + 1).trim());
|
||||
this.y = Double.parseDouble(value.substring(0, comma).trim());
|
||||
this.x = Double.parseDouble(value.substring(comma + 1).trim());
|
||||
} else {
|
||||
resetFromGeoHash(value);
|
||||
}
|
||||
|
@ -79,38 +82,40 @@ public final class GeoPoint {
|
|||
}
|
||||
|
||||
public final double lat() {
|
||||
return this.lat;
|
||||
return this.y;
|
||||
}
|
||||
|
||||
public final double getLat() {
|
||||
return this.lat;
|
||||
return this.y;
|
||||
}
|
||||
|
||||
public final double lon() {
|
||||
return this.lon;
|
||||
return this.x;
|
||||
}
|
||||
|
||||
public final double getLon() {
|
||||
return this.lon;
|
||||
return this.x;
|
||||
}
|
||||
|
||||
public final String geohash() {
|
||||
return GeoHashUtils.encode(lat, lon);
|
||||
return GeoHashUtils.encode(y, x);
|
||||
}
|
||||
|
||||
public final String getGeohash() {
|
||||
return GeoHashUtils.encode(lat, lon);
|
||||
return GeoHashUtils.encode(y, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
GeoPoint geoPoint = (GeoPoint) o;
|
||||
|
||||
if (Double.compare(geoPoint.lat, lat) != 0) return false;
|
||||
if (Double.compare(geoPoint.lon, lon) != 0) return false;
|
||||
if (o == null) return false;
|
||||
if (o instanceof Coordinate) {
|
||||
Coordinate c = (Coordinate)o;
|
||||
return Double.compare(c.x, this.x) == 0
|
||||
&& Double.compare(c.y, this.y) == 0
|
||||
&& Double.compare(c.z, this.z) == 0;
|
||||
}
|
||||
if (getClass() != o.getClass()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -119,15 +124,15 @@ public final class GeoPoint {
|
|||
public int hashCode() {
|
||||
int result;
|
||||
long temp;
|
||||
temp = lat != +0.0d ? Double.doubleToLongBits(lat) : 0L;
|
||||
temp = y != +0.0d ? Double.doubleToLongBits(y) : 0L;
|
||||
result = (int) (temp ^ (temp >>> 32));
|
||||
temp = lon != +0.0d ? Double.doubleToLongBits(lon) : 0L;
|
||||
temp = x != +0.0d ? Double.doubleToLongBits(x) : 0L;
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "[" + lat + ", " + lon + "]";
|
||||
return "[" + y + ", " + x + "]";
|
||||
}
|
||||
|
||||
public static GeoPoint parseFromLatLon(String latLon) {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.elasticsearch.common.geo;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
|
||||
import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree;
|
||||
import org.apache.lucene.util.SloppyMath;
|
||||
|
@ -38,6 +39,8 @@ public class GeoUtils {
|
|||
public static final String LONGITUDE = GeoPointFieldMapper.Names.LON;
|
||||
public static final String GEOHASH = GeoPointFieldMapper.Names.GEOHASH;
|
||||
|
||||
public static final double DATELINE = 180.0D;
|
||||
|
||||
/** Earth ellipsoid major axis defined by WGS 84 in meters */
|
||||
public static final double EARTH_SEMI_MAJOR_AXIS = 6378137.0; // meters (WGS 84)
|
||||
|
||||
|
@ -422,6 +425,113 @@ public class GeoUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean correctPolyAmbiguity(GeoPoint[] points, boolean handedness) {
|
||||
return correctPolyAmbiguity(points, handedness, computePolyOrientation(points), 0, points.length, false);
|
||||
}
|
||||
|
||||
public static boolean correctPolyAmbiguity(GeoPoint[] points, boolean handedness, boolean orientation, int component, int length,
|
||||
boolean shellCorrected) {
|
||||
// OGC requires shell as ccw (Right-Handedness) and holes as cw (Left-Handedness)
|
||||
// since GeoJSON doesn't specify (and doesn't need to) GEO core will assume OGC standards
|
||||
// thus if orientation is computed as cw, the logic will translate points across dateline
|
||||
// and convert to a right handed system
|
||||
|
||||
// compute the bounding box and calculate range
|
||||
Pair<Pair, Pair> range = GeoUtils.computeBBox(points, length);
|
||||
final double rng = (Double)range.getLeft().getRight() - (Double)range.getLeft().getLeft();
|
||||
// translate the points if the following is true
|
||||
// 1. shell orientation is cw and range is greater than a hemisphere (180 degrees) but not spanning 2 hemispheres
|
||||
// (translation would result in a collapsed poly)
|
||||
// 2. the shell of the candidate hole has been translated (to preserve the coordinate system)
|
||||
boolean incorrectOrientation = component == 0 && handedness != orientation;
|
||||
boolean translated = ((incorrectOrientation && (rng > DATELINE && rng != 360.0)) || (shellCorrected && component != 0));
|
||||
if (translated) {
|
||||
for (GeoPoint c : points) {
|
||||
if (c.x < 0.0) {
|
||||
c.x += 360.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return translated;
|
||||
}
|
||||
|
||||
public static boolean computePolyOrientation(GeoPoint[] points) {
|
||||
return computePolyOrientation(points, points.length);
|
||||
}
|
||||
|
||||
public static boolean computePolyOrientation(GeoPoint[] points, int length) {
|
||||
// calculate the direction of the points:
|
||||
// find the point at the top of the set and check its
|
||||
// neighbors orientation. So direction is equivalent
|
||||
// to clockwise/counterclockwise
|
||||
final int top = computePolyOrigin(points, length);
|
||||
final int prev = ((top + length - 1) % length);
|
||||
final int next = ((top + 1) % length);
|
||||
return (points[prev].x > points[next].x);
|
||||
}
|
||||
|
||||
private static final int computePolyOrigin(GeoPoint[] points, int length) {
|
||||
int top = 0;
|
||||
// we start at 1 here since top points to 0
|
||||
for (int i = 1; i < length; i++) {
|
||||
if (points[i].y < points[top].y) {
|
||||
top = i;
|
||||
} else if (points[i].y == points[top].y) {
|
||||
if (points[i].x < points[top].x) {
|
||||
top = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
public static final Pair computeBBox(GeoPoint[] points) {
|
||||
return computeBBox(points, 0);
|
||||
}
|
||||
|
||||
public static final Pair computeBBox(GeoPoint[] points, int length) {
|
||||
double minX = points[0].x;
|
||||
double maxX = points[0].x;
|
||||
double minY = points[0].y;
|
||||
double maxY = points[0].y;
|
||||
// compute the bounding coordinates (@todo: cleanup brute force)
|
||||
for (int i = 1; i < length; ++i) {
|
||||
if (points[i].x < minX) {
|
||||
minX = points[i].x;
|
||||
}
|
||||
if (points[i].x > maxX) {
|
||||
maxX = points[i].x;
|
||||
}
|
||||
if (points[i].y < minY) {
|
||||
minY = points[i].y;
|
||||
}
|
||||
if (points[i].y > maxY) {
|
||||
maxY = points[i].y;
|
||||
}
|
||||
}
|
||||
// return a pair of ranges on the X and Y axis, respectively
|
||||
return Pair.of(Pair.of(minX, maxX), Pair.of(minY, maxY));
|
||||
}
|
||||
|
||||
public static GeoPoint convertToGreatCircle(GeoPoint point) {
|
||||
return convertToGreatCircle(point.y, point.x);
|
||||
}
|
||||
|
||||
public static GeoPoint convertToGreatCircle(double lat, double lon) {
|
||||
GeoPoint p = new GeoPoint(lat, lon);
|
||||
// convert the point to standard lat/lon bounds
|
||||
normalizePoint(p);
|
||||
|
||||
if (p.x < 0.0D) {
|
||||
p.x += 360.0D;
|
||||
}
|
||||
|
||||
if (p.y < 0.0D) {
|
||||
p.y +=180.0D;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private GeoUtils() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.spatial4j.core.shape.ShapeCollection;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.geo.GeoUtils;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import com.spatial4j.core.shape.Shape;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import com.vividsolutions.jts.geom.Geometry;
|
||||
import com.vividsolutions.jts.geom.GeometryFactory;
|
||||
import com.vividsolutions.jts.geom.LineString;
|
||||
|
@ -35,10 +35,10 @@ import com.vividsolutions.jts.geom.LineString;
|
|||
public abstract class BaseLineStringBuilder<E extends BaseLineStringBuilder<E>> extends PointCollection<E> {
|
||||
|
||||
protected BaseLineStringBuilder() {
|
||||
this(new ArrayList<Coordinate>());
|
||||
this(new ArrayList<GeoPoint>());
|
||||
}
|
||||
|
||||
protected BaseLineStringBuilder(ArrayList<Coordinate> points) {
|
||||
protected BaseLineStringBuilder(ArrayList<GeoPoint> points) {
|
||||
super(points);
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ public abstract class BaseLineStringBuilder<E extends BaseLineStringBuilder<E>>
|
|||
|
||||
@Override
|
||||
public Shape build() {
|
||||
Coordinate[] coordinates = points.toArray(new Coordinate[points.size()]);
|
||||
GeoPoint[] coordinates = points.toArray(new GeoPoint[points.size()]);
|
||||
Geometry geometry;
|
||||
if(wrapdateline) {
|
||||
ArrayList<LineString> strings = decompose(FACTORY, coordinates, new ArrayList<LineString>());
|
||||
|
@ -67,9 +67,9 @@ public abstract class BaseLineStringBuilder<E extends BaseLineStringBuilder<E>>
|
|||
return jtsGeometry(geometry);
|
||||
}
|
||||
|
||||
protected static ArrayList<LineString> decompose(GeometryFactory factory, Coordinate[] coordinates, ArrayList<LineString> strings) {
|
||||
for(Coordinate[] part : decompose(+DATELINE, coordinates)) {
|
||||
for(Coordinate[] line : decompose(-DATELINE, part)) {
|
||||
protected static ArrayList<LineString> decompose(GeometryFactory factory, GeoPoint[] coordinates, ArrayList<LineString> strings) {
|
||||
for(GeoPoint[] part : decompose(+DATELINE, coordinates)) {
|
||||
for(GeoPoint[] line : decompose(-DATELINE, part)) {
|
||||
strings.add(factory.createLineString(line));
|
||||
}
|
||||
}
|
||||
|
@ -83,16 +83,16 @@ public abstract class BaseLineStringBuilder<E extends BaseLineStringBuilder<E>>
|
|||
* @param coordinates coordinates forming the linestring
|
||||
* @return array of linestrings given as coordinate arrays
|
||||
*/
|
||||
protected static Coordinate[][] decompose(double dateline, Coordinate[] coordinates) {
|
||||
protected static GeoPoint[][] decompose(double dateline, GeoPoint[] coordinates) {
|
||||
int offset = 0;
|
||||
ArrayList<Coordinate[]> parts = new ArrayList<>();
|
||||
ArrayList<GeoPoint[]> parts = new ArrayList<>();
|
||||
|
||||
double shift = coordinates[0].x > DATELINE ? DATELINE : (coordinates[0].x < -DATELINE ? -DATELINE : 0);
|
||||
|
||||
for (int i = 1; i < coordinates.length; i++) {
|
||||
double t = intersection(coordinates[i-1], coordinates[i], dateline);
|
||||
if(!Double.isNaN(t)) {
|
||||
Coordinate[] part;
|
||||
GeoPoint[] part;
|
||||
if(t<1) {
|
||||
part = Arrays.copyOfRange(coordinates, offset, i+1);
|
||||
part[part.length-1] = Edge.position(coordinates[i-1], coordinates[i], t);
|
||||
|
@ -111,16 +111,16 @@ public abstract class BaseLineStringBuilder<E extends BaseLineStringBuilder<E>>
|
|||
if(offset == 0) {
|
||||
parts.add(shift(shift, coordinates));
|
||||
} else if(offset < coordinates.length-1) {
|
||||
Coordinate[] part = Arrays.copyOfRange(coordinates, offset, coordinates.length);
|
||||
GeoPoint[] part = Arrays.copyOfRange(coordinates, offset, coordinates.length);
|
||||
parts.add(shift(shift, part));
|
||||
}
|
||||
return parts.toArray(new Coordinate[parts.size()][]);
|
||||
return parts.toArray(new GeoPoint[parts.size()][]);
|
||||
}
|
||||
|
||||
private static Coordinate[] shift(double shift, Coordinate...coordinates) {
|
||||
private static GeoPoint[] shift(double shift, GeoPoint...coordinates) {
|
||||
if(shift != 0) {
|
||||
for (int j = 0; j < coordinates.length; j++) {
|
||||
coordinates[j] = new Coordinate(coordinates[j].x - 2 * shift, coordinates[j].y);
|
||||
coordinates[j] = new GeoPoint(coordinates[j].y, coordinates[j].x - 2 * shift);
|
||||
}
|
||||
}
|
||||
return coordinates;
|
||||
|
|
|
@ -20,8 +20,14 @@
|
|||
package org.elasticsearch.common.geo.builders;
|
||||
|
||||
import com.spatial4j.core.shape.Shape;
|
||||
import com.vividsolutions.jts.geom.*;
|
||||
import com.vividsolutions.jts.geom.Geometry;
|
||||
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.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.geo.GeoUtils;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -67,7 +73,7 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
|
|||
* @param coordinate coordinate of the new point
|
||||
* @return this
|
||||
*/
|
||||
public E point(Coordinate coordinate) {
|
||||
public E point(GeoPoint coordinate) {
|
||||
shell.point(coordinate);
|
||||
return thisRef();
|
||||
}
|
||||
|
@ -77,7 +83,7 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
|
|||
* @param coordinates coordinates of the new points to add
|
||||
* @return this
|
||||
*/
|
||||
public E points(Coordinate...coordinates) {
|
||||
public E points(GeoPoint...coordinates) {
|
||||
shell.points(coordinates);
|
||||
return thisRef();
|
||||
}
|
||||
|
@ -121,7 +127,7 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
|
|||
*
|
||||
* @return coordinates of the polygon
|
||||
*/
|
||||
public Coordinate[][][] coordinates() {
|
||||
public GeoPoint[][][] coordinates() {
|
||||
int numEdges = shell.points.size()-1; // Last point is repeated
|
||||
for (int i = 0; i < holes.size(); i++) {
|
||||
numEdges += holes.get(i).points.size()-1;
|
||||
|
@ -170,7 +176,7 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
|
|||
|
||||
public Geometry buildGeometry(GeometryFactory factory, boolean fixDateline) {
|
||||
if(fixDateline) {
|
||||
Coordinate[][][] polygons = coordinates();
|
||||
GeoPoint[][][] polygons = coordinates();
|
||||
return polygons.length == 1
|
||||
? polygon(factory, polygons[0])
|
||||
: multipolygon(factory, polygons);
|
||||
|
@ -193,8 +199,8 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
|
|||
return factory.createPolygon(shell, holes);
|
||||
}
|
||||
|
||||
protected static LinearRing linearRing(GeometryFactory factory, ArrayList<Coordinate> coordinates) {
|
||||
return factory.createLinearRing(coordinates.toArray(new Coordinate[coordinates.size()]));
|
||||
protected static LinearRing linearRing(GeometryFactory factory, ArrayList<GeoPoint> coordinates) {
|
||||
return factory.createLinearRing(coordinates.toArray(new GeoPoint[coordinates.size()]));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -202,7 +208,7 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
|
|||
return TYPE;
|
||||
}
|
||||
|
||||
protected static Polygon polygon(GeometryFactory factory, Coordinate[][] polygon) {
|
||||
protected static Polygon polygon(GeometryFactory factory, GeoPoint[][] polygon) {
|
||||
LinearRing shell = factory.createLinearRing(polygon[0]);
|
||||
LinearRing[] holes;
|
||||
|
||||
|
@ -227,7 +233,7 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
|
|||
* @param polygons definition of polygons
|
||||
* @return a new Multipolygon
|
||||
*/
|
||||
protected static MultiPolygon multipolygon(GeometryFactory factory, Coordinate[][][] polygons) {
|
||||
protected static MultiPolygon multipolygon(GeometryFactory factory, GeoPoint[][][] polygons) {
|
||||
Polygon[] polygonSet = new Polygon[polygons.length];
|
||||
for (int i = 0; i < polygonSet.length; i++) {
|
||||
polygonSet[i] = polygon(factory, polygons[i]);
|
||||
|
@ -283,18 +289,18 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
|
|||
* @param coordinates Array of coordinates to write the result to
|
||||
* @return the coordinates parameter
|
||||
*/
|
||||
private static Coordinate[] coordinates(Edge component, Coordinate[] coordinates) {
|
||||
private static GeoPoint[] coordinates(Edge component, GeoPoint[] coordinates) {
|
||||
for (int i = 0; i < coordinates.length; i++) {
|
||||
coordinates[i] = (component = component.next).coordinate;
|
||||
}
|
||||
return coordinates;
|
||||
}
|
||||
|
||||
private static Coordinate[][][] buildCoordinates(ArrayList<ArrayList<Coordinate[]>> components) {
|
||||
Coordinate[][][] result = new Coordinate[components.size()][][];
|
||||
private static GeoPoint[][][] buildCoordinates(ArrayList<ArrayList<GeoPoint[]>> components) {
|
||||
GeoPoint[][][] result = new GeoPoint[components.size()][][];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
ArrayList<Coordinate[]> component = components.get(i);
|
||||
result[i] = component.toArray(new Coordinate[component.size()][]);
|
||||
ArrayList<GeoPoint[]> component = components.get(i);
|
||||
result[i] = component.toArray(new GeoPoint[component.size()][]);
|
||||
}
|
||||
|
||||
if(debugEnabled()) {
|
||||
|
@ -309,30 +315,30 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
|
|||
return result;
|
||||
}
|
||||
|
||||
private static final Coordinate[][] EMPTY = new Coordinate[0][];
|
||||
private static final GeoPoint[][] EMPTY = new GeoPoint[0][];
|
||||
|
||||
private static Coordinate[][] holes(Edge[] holes, int numHoles) {
|
||||
private static GeoPoint[][] holes(Edge[] holes, int numHoles) {
|
||||
if (numHoles == 0) {
|
||||
return EMPTY;
|
||||
}
|
||||
final Coordinate[][] points = new Coordinate[numHoles][];
|
||||
final GeoPoint[][] points = new GeoPoint[numHoles][];
|
||||
|
||||
for (int i = 0; i < numHoles; i++) {
|
||||
int length = component(holes[i], -(i+1), null); // mark as visited by inverting the sign
|
||||
points[i] = coordinates(holes[i], new Coordinate[length+1]);
|
||||
points[i] = coordinates(holes[i], new GeoPoint[length+1]);
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private static Edge[] edges(Edge[] edges, int numHoles, ArrayList<ArrayList<Coordinate[]>> components) {
|
||||
private static Edge[] edges(Edge[] edges, int numHoles, ArrayList<ArrayList<GeoPoint[]>> components) {
|
||||
ArrayList<Edge> mainEdges = new ArrayList<>(edges.length);
|
||||
|
||||
for (int i = 0; i < edges.length; i++) {
|
||||
if (edges[i].component >= 0) {
|
||||
int length = component(edges[i], -(components.size()+numHoles+1), mainEdges);
|
||||
ArrayList<Coordinate[]> component = new ArrayList<>();
|
||||
component.add(coordinates(edges[i], new Coordinate[length+1]));
|
||||
ArrayList<GeoPoint[]> component = new ArrayList<>();
|
||||
component.add(coordinates(edges[i], new GeoPoint[length+1]));
|
||||
components.add(component);
|
||||
}
|
||||
}
|
||||
|
@ -340,13 +346,14 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
|
|||
return mainEdges.toArray(new Edge[mainEdges.size()]);
|
||||
}
|
||||
|
||||
private static Coordinate[][][] compose(Edge[] edges, Edge[] holes, int numHoles) {
|
||||
final ArrayList<ArrayList<Coordinate[]>> components = new ArrayList<>();
|
||||
private static GeoPoint[][][] compose(Edge[] edges, Edge[] holes, int numHoles) {
|
||||
final ArrayList<ArrayList<GeoPoint[]>> components = new ArrayList<>();
|
||||
assign(holes, holes(holes, numHoles), numHoles, edges(edges, numHoles, components), components);
|
||||
return buildCoordinates(components);
|
||||
}
|
||||
|
||||
private static void assign(Edge[] holes, Coordinate[][] points, int numHoles, Edge[] edges, ArrayList<ArrayList<Coordinate[]>> components) {
|
||||
private static void assign(Edge[] holes, GeoPoint[][] points, int numHoles, Edge[] edges, ArrayList<ArrayList<GeoPoint[]>>
|
||||
components) {
|
||||
// Assign Hole to related components
|
||||
// To find the new component the hole belongs to all intersections of the
|
||||
// polygon edges with a vertical line are calculated. This vertical line
|
||||
|
@ -461,14 +468,13 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
|
|||
}
|
||||
|
||||
private static int createEdges(int component, Orientation orientation, BaseLineStringBuilder<?> shell,
|
||||
BaseLineStringBuilder<?> hole,
|
||||
Edge[] edges, int offset) {
|
||||
BaseLineStringBuilder<?> hole, Edge[] edges, int edgeOffset) {
|
||||
// inner rings (holes) have an opposite direction than the outer rings
|
||||
// XOR will invert the orientation for outer ring cases (Truth Table:, T/T = F, T/F = T, F/T = T, F/F = F)
|
||||
boolean direction = (component != 0 ^ orientation == Orientation.RIGHT);
|
||||
// set the points array accordingly (shell or hole)
|
||||
Coordinate[] points = (hole != null) ? hole.coordinates(false) : shell.coordinates(false);
|
||||
Edge.ring(component, direction, orientation == Orientation.LEFT, shell, points, 0, edges, offset, points.length-1);
|
||||
GeoPoint[] points = (hole != null) ? hole.coordinates(false) : shell.coordinates(false);
|
||||
Edge.ring(component, direction, orientation == Orientation.LEFT, shell, points, edges, edgeOffset, points.length-1);
|
||||
return points.length-1;
|
||||
}
|
||||
|
||||
|
@ -477,17 +483,17 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
|
|||
private final P parent;
|
||||
|
||||
protected Ring(P parent) {
|
||||
this(parent, new ArrayList<Coordinate>());
|
||||
this(parent, new ArrayList<GeoPoint>());
|
||||
}
|
||||
|
||||
protected Ring(P parent, ArrayList<Coordinate> points) {
|
||||
protected Ring(P parent, ArrayList<GeoPoint> points) {
|
||||
super(points);
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public P close() {
|
||||
Coordinate start = points.get(0);
|
||||
Coordinate end = points.get(points.size()-1);
|
||||
GeoPoint start = points.get(0);
|
||||
GeoPoint end = points.get(points.size()-1);
|
||||
if(start.x != end.x || start.y != end.y) {
|
||||
points.add(start);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
package org.elasticsearch.common.geo.builders;
|
||||
|
||||
import com.spatial4j.core.shape.Circle;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.unit.DistanceUnit;
|
||||
import org.elasticsearch.common.unit.DistanceUnit.Distance;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
@ -34,7 +34,7 @@ public class CircleBuilder extends ShapeBuilder {
|
|||
|
||||
private DistanceUnit unit;
|
||||
private double radius;
|
||||
private Coordinate center;
|
||||
private GeoPoint center;
|
||||
|
||||
/**
|
||||
* Set the center of the circle
|
||||
|
@ -42,7 +42,7 @@ public class CircleBuilder extends ShapeBuilder {
|
|||
* @param center coordinate of the circles center
|
||||
* @return this
|
||||
*/
|
||||
public CircleBuilder center(Coordinate center) {
|
||||
public CircleBuilder center(GeoPoint center) {
|
||||
this.center = center;
|
||||
return this;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ public class CircleBuilder extends ShapeBuilder {
|
|||
* @return this
|
||||
*/
|
||||
public CircleBuilder center(double lon, double lat) {
|
||||
return center(new Coordinate(lon, lat));
|
||||
return center(new GeoPoint(lat, lon));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
package org.elasticsearch.common.geo.builders;
|
||||
|
||||
import com.spatial4j.core.shape.Rectangle;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -29,8 +29,8 @@ public class EnvelopeBuilder extends ShapeBuilder {
|
|||
|
||||
public static final GeoShapeType TYPE = GeoShapeType.ENVELOPE;
|
||||
|
||||
protected Coordinate topLeft;
|
||||
protected Coordinate bottomRight;
|
||||
protected GeoPoint topLeft;
|
||||
protected GeoPoint bottomRight;
|
||||
|
||||
public EnvelopeBuilder() {
|
||||
this(Orientation.RIGHT);
|
||||
|
@ -40,7 +40,7 @@ public class EnvelopeBuilder extends ShapeBuilder {
|
|||
super(orientation);
|
||||
}
|
||||
|
||||
public EnvelopeBuilder topLeft(Coordinate topLeft) {
|
||||
public EnvelopeBuilder topLeft(GeoPoint topLeft) {
|
||||
this.topLeft = topLeft;
|
||||
return this;
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ public class EnvelopeBuilder extends ShapeBuilder {
|
|||
return topLeft(coordinate(longitude, latitude));
|
||||
}
|
||||
|
||||
public EnvelopeBuilder bottomRight(Coordinate bottomRight) {
|
||||
public EnvelopeBuilder bottomRight(GeoPoint bottomRight) {
|
||||
this.bottomRight = bottomRight;
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -19,11 +19,10 @@
|
|||
|
||||
package org.elasticsearch.common.geo.builders;
|
||||
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import com.spatial4j.core.shape.Shape;
|
||||
import com.spatial4j.core.shape.jts.JtsGeometry;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import com.vividsolutions.jts.geom.Geometry;
|
||||
import com.vividsolutions.jts.geom.LineString;
|
||||
|
||||
|
@ -48,8 +47,8 @@ public class MultiLineStringBuilder extends ShapeBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Coordinate[][] coordinates() {
|
||||
Coordinate[][] result = new Coordinate[lines.size()][];
|
||||
public GeoPoint[][] coordinates() {
|
||||
GeoPoint[][] result = new GeoPoint[lines.size()][];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = lines.get(i).coordinates(false);
|
||||
}
|
||||
|
@ -113,7 +112,7 @@ public class MultiLineStringBuilder extends ShapeBuilder {
|
|||
return collection;
|
||||
}
|
||||
|
||||
public Coordinate[] coordinates() {
|
||||
public GeoPoint[] coordinates() {
|
||||
return super.coordinates(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ package org.elasticsearch.common.geo.builders;
|
|||
import com.spatial4j.core.shape.Point;
|
||||
import com.spatial4j.core.shape.Shape;
|
||||
import com.spatial4j.core.shape.ShapeCollection;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -48,7 +48,7 @@ public class MultiPointBuilder extends PointCollection<MultiPointBuilder> {
|
|||
//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) {
|
||||
for (GeoPoint coord : points) {
|
||||
shapes.add(SPATIAL_CONTEXT.makePoint(coord.x, coord.y));
|
||||
}
|
||||
return new ShapeCollection<>(shapes, SPATIAL_CONTEXT);
|
||||
|
|
|
@ -24,10 +24,10 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import com.spatial4j.core.shape.ShapeCollection;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import com.spatial4j.core.shape.Shape;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
public class MultiPolygonBuilder extends ShapeBuilder {
|
||||
|
||||
|
@ -84,7 +84,7 @@ public class MultiPolygonBuilder extends ShapeBuilder {
|
|||
|
||||
if(wrapdateline) {
|
||||
for (BasePolygonBuilder<?> polygon : this.polygons) {
|
||||
for(Coordinate[][] part : polygon.coordinates()) {
|
||||
for(GeoPoint[][] part : polygon.coordinates()) {
|
||||
shapes.add(jtsGeometry(PolygonBuilder.polygon(FACTORY, part)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,18 +21,18 @@ package org.elasticsearch.common.geo.builders;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import com.spatial4j.core.shape.Point;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
public class PointBuilder extends ShapeBuilder {
|
||||
|
||||
public static final GeoShapeType TYPE = GeoShapeType.POINT;
|
||||
|
||||
private Coordinate coordinate;
|
||||
private GeoPoint coordinate;
|
||||
|
||||
public PointBuilder coordinate(Coordinate coordinate) {
|
||||
public PointBuilder coordinate(GeoPoint coordinate) {
|
||||
this.coordinate = coordinate;
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -24,23 +24,22 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
|
||||
/**
|
||||
* 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 ArrayList<GeoPoint> points;
|
||||
protected boolean translated = false;
|
||||
|
||||
protected PointCollection() {
|
||||
this(new ArrayList<Coordinate>());
|
||||
this(new ArrayList<GeoPoint>());
|
||||
}
|
||||
|
||||
protected PointCollection(ArrayList<Coordinate> points) {
|
||||
protected PointCollection(ArrayList<GeoPoint> points) {
|
||||
this.points = points;
|
||||
}
|
||||
|
||||
|
@ -64,7 +63,7 @@ public abstract class PointCollection<E extends PointCollection<E>> extends Shap
|
|||
* @param coordinate coordinate of the point
|
||||
* @return this
|
||||
*/
|
||||
public E point(Coordinate coordinate) {
|
||||
public E point(GeoPoint coordinate) {
|
||||
this.points.add(coordinate);
|
||||
return thisRef();
|
||||
}
|
||||
|
@ -72,20 +71,20 @@ public abstract class PointCollection<E extends PointCollection<E>> extends Shap
|
|||
/**
|
||||
* Add a array of points to the collection
|
||||
*
|
||||
* @param coordinates array of {@link Coordinate}s to add
|
||||
* @param coordinates array of {@link GeoPoint}s to add
|
||||
* @return this
|
||||
*/
|
||||
public E points(Coordinate...coordinates) {
|
||||
public E points(GeoPoint...coordinates) {
|
||||
return this.points(Arrays.asList(coordinates));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a collection of points to the collection
|
||||
*
|
||||
* @param coordinates array of {@link Coordinate}s to add
|
||||
* @param coordinates array of {@link GeoPoint}s to add
|
||||
* @return this
|
||||
*/
|
||||
public E points(Collection<? extends Coordinate> coordinates) {
|
||||
public E points(Collection<? extends GeoPoint> coordinates) {
|
||||
this.points.addAll(coordinates);
|
||||
return thisRef();
|
||||
}
|
||||
|
@ -96,8 +95,8 @@ public abstract class PointCollection<E extends PointCollection<E>> extends Shap
|
|||
* @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)]);
|
||||
protected GeoPoint[] coordinates(boolean closed) {
|
||||
GeoPoint[] result = points.toArray(new GeoPoint[points.size() + (closed?1:0)]);
|
||||
if(closed) {
|
||||
result[result.length-1] = result[0];
|
||||
}
|
||||
|
@ -114,12 +113,12 @@ 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) {
|
||||
for(GeoPoint point : points) {
|
||||
toXContent(builder, point);
|
||||
}
|
||||
if(closed) {
|
||||
Coordinate start = points.get(0);
|
||||
Coordinate end = points.get(points.size()-1);
|
||||
GeoPoint start = points.get(0);
|
||||
GeoPoint end = points.get(points.size()-1);
|
||||
if(start.x != end.x || start.y != end.y) {
|
||||
toXContent(builder, points.get(0));
|
||||
}
|
||||
|
|
|
@ -21,19 +21,19 @@ package org.elasticsearch.common.geo.builders;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
|
||||
public class PolygonBuilder extends BasePolygonBuilder<PolygonBuilder> {
|
||||
|
||||
public PolygonBuilder() {
|
||||
this(new ArrayList<Coordinate>(), Orientation.RIGHT);
|
||||
this(new ArrayList<GeoPoint>(), Orientation.RIGHT);
|
||||
}
|
||||
|
||||
public PolygonBuilder(Orientation orientation) {
|
||||
this(new ArrayList<Coordinate>(), orientation);
|
||||
this(new ArrayList<GeoPoint>(), orientation);
|
||||
}
|
||||
|
||||
protected PolygonBuilder(ArrayList<Coordinate> points, Orientation orientation) {
|
||||
protected PolygonBuilder(ArrayList<GeoPoint> points, Orientation orientation) {
|
||||
super(orientation);
|
||||
this.shell = new Ring<>(this, points);
|
||||
}
|
||||
|
|
|
@ -22,12 +22,12 @@ package org.elasticsearch.common.geo.builders;
|
|||
import com.spatial4j.core.context.jts.JtsSpatialContext;
|
||||
import com.spatial4j.core.shape.Shape;
|
||||
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.apache.commons.lang3.tuple.Pair;
|
||||
import org.elasticsearch.ElasticsearchIllegalArgumentException;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.geo.GeoUtils;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.ESLoggerFactory;
|
||||
import org.elasticsearch.common.unit.DistanceUnit.Distance;
|
||||
|
@ -57,7 +57,7 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
DEBUG = debug;
|
||||
}
|
||||
|
||||
public static final double DATELINE = 180;
|
||||
public static final double DATELINE = GeoUtils.DATELINE;
|
||||
// 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();
|
||||
|
@ -84,8 +84,8 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
this.orientation = orientation;
|
||||
}
|
||||
|
||||
protected static Coordinate coordinate(double longitude, double latitude) {
|
||||
return new Coordinate(longitude, latitude);
|
||||
protected static GeoPoint coordinate(double longitude, double latitude) {
|
||||
return new GeoPoint(latitude, longitude);
|
||||
}
|
||||
|
||||
protected JtsGeometry jtsGeometry(Geometry geom) {
|
||||
|
@ -106,15 +106,15 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
* @return a new {@link PointBuilder}
|
||||
*/
|
||||
public static PointBuilder newPoint(double longitude, double latitude) {
|
||||
return newPoint(new Coordinate(longitude, latitude));
|
||||
return newPoint(new GeoPoint(latitude, longitude));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link PointBuilder} from a {@link Coordinate}
|
||||
* Create a new {@link PointBuilder} from a {@link GeoPoint}
|
||||
* @param coordinate coordinate defining the position of the point
|
||||
* @return a new {@link PointBuilder}
|
||||
*/
|
||||
public static PointBuilder newPoint(Coordinate coordinate) {
|
||||
public static PointBuilder newPoint(GeoPoint coordinate) {
|
||||
return new PointBuilder().coordinate(coordinate);
|
||||
}
|
||||
|
||||
|
@ -250,7 +250,7 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
token = parser.nextToken();
|
||||
double lat = parser.doubleValue();
|
||||
token = parser.nextToken();
|
||||
return new CoordinateNode(new Coordinate(lon, lat));
|
||||
return new CoordinateNode(new GeoPoint(lat, lon));
|
||||
} else if (token == XContentParser.Token.VALUE_NULL) {
|
||||
throw new ElasticsearchIllegalArgumentException("coordinates cannot contain NULL values)");
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
return GeoShapeType.parse(parser, geoDocMapper);
|
||||
}
|
||||
|
||||
protected static XContentBuilder toXContent(XContentBuilder builder, Coordinate coordinate) throws IOException {
|
||||
protected static XContentBuilder toXContent(XContentBuilder builder, GeoPoint coordinate) throws IOException {
|
||||
return builder.startArray().value(coordinate.x).value(coordinate.y).endArray();
|
||||
}
|
||||
|
||||
|
@ -309,11 +309,11 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
}
|
||||
}
|
||||
|
||||
protected static Coordinate shift(Coordinate coordinate, double dateline) {
|
||||
protected static GeoPoint shift(GeoPoint coordinate, double dateline) {
|
||||
if (dateline == 0) {
|
||||
return coordinate;
|
||||
} else {
|
||||
return new Coordinate(-2 * dateline + coordinate.x, coordinate.y);
|
||||
return new GeoPoint(coordinate.y, -2 * dateline + coordinate.x);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,7 +336,7 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
* segment intersects with the line segment. Otherwise this method
|
||||
* returns {@link Double#NaN}
|
||||
*/
|
||||
protected static final double intersection(Coordinate p1, Coordinate p2, double dateline) {
|
||||
protected static final double intersection(GeoPoint p1, GeoPoint p2, double dateline) {
|
||||
if (p1.x == p2.x && p1.x != dateline) {
|
||||
return Double.NaN;
|
||||
} else if (p1.x == p2.x && p1.x == dateline) {
|
||||
|
@ -366,8 +366,8 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
int numIntersections = 0;
|
||||
assert !Double.isNaN(dateline);
|
||||
for (int i = 0; i < edges.length; i++) {
|
||||
Coordinate p1 = edges[i].coordinate;
|
||||
Coordinate p2 = edges[i].next.coordinate;
|
||||
GeoPoint p1 = edges[i].coordinate;
|
||||
GeoPoint p2 = edges[i].next.coordinate;
|
||||
assert !Double.isNaN(p2.x) && !Double.isNaN(p1.x);
|
||||
edges[i].intersect = Edge.MAX_COORDINATE;
|
||||
|
||||
|
@ -384,21 +384,21 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
/**
|
||||
* Node used to represent a tree of coordinates.
|
||||
* <p/>
|
||||
* Can either be a leaf node consisting of a Coordinate, or a parent with
|
||||
* Can either be a leaf node consisting of a GeoPoint, or a parent with
|
||||
* children
|
||||
*/
|
||||
protected static class CoordinateNode implements ToXContent {
|
||||
|
||||
protected final Coordinate coordinate;
|
||||
protected final GeoPoint coordinate;
|
||||
protected final List<CoordinateNode> children;
|
||||
|
||||
/**
|
||||
* Creates a new leaf CoordinateNode
|
||||
*
|
||||
* @param coordinate
|
||||
* Coordinate for the Node
|
||||
* GeoPoint for the Node
|
||||
*/
|
||||
protected CoordinateNode(Coordinate coordinate) {
|
||||
protected CoordinateNode(GeoPoint coordinate) {
|
||||
this.coordinate = coordinate;
|
||||
this.children = null;
|
||||
}
|
||||
|
@ -434,17 +434,17 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
}
|
||||
|
||||
/**
|
||||
* This helper class implements a linked list for {@link Coordinate}. It contains
|
||||
* This helper class implements a linked list for {@link GeoPoint}. It contains
|
||||
* fields for a dateline intersection and component id
|
||||
*/
|
||||
protected static final class Edge {
|
||||
Coordinate coordinate; // coordinate of the start point
|
||||
GeoPoint coordinate; // coordinate of the start point
|
||||
Edge next; // next segment
|
||||
Coordinate intersect; // potential intersection with dateline
|
||||
GeoPoint intersect; // potential intersection with dateline
|
||||
int component = -1; // id of the component this edge belongs to
|
||||
public static final Coordinate MAX_COORDINATE = new Coordinate(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
|
||||
public static final GeoPoint MAX_COORDINATE = new GeoPoint(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
|
||||
|
||||
protected Edge(Coordinate coordinate, Edge next, Coordinate intersection) {
|
||||
protected Edge(GeoPoint coordinate, Edge next, GeoPoint intersection) {
|
||||
this.coordinate = coordinate;
|
||||
this.next = next;
|
||||
this.intersect = intersection;
|
||||
|
@ -453,11 +453,11 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
}
|
||||
}
|
||||
|
||||
protected Edge(Coordinate coordinate, Edge next) {
|
||||
protected Edge(GeoPoint coordinate, Edge next) {
|
||||
this(coordinate, next, Edge.MAX_COORDINATE);
|
||||
}
|
||||
|
||||
private static final int top(Coordinate[] points, int offset, int length) {
|
||||
private static final int top(GeoPoint[] points, int offset, int length) {
|
||||
int top = 0; // we start at 1 here since top points to 0
|
||||
for (int i = 1; i < length; i++) {
|
||||
if (points[offset + i].y < points[offset + top].y) {
|
||||
|
@ -471,29 +471,6 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
return top;
|
||||
}
|
||||
|
||||
private static final Pair range(Coordinate[] points, int offset, int length) {
|
||||
double minX = points[0].x;
|
||||
double maxX = points[0].x;
|
||||
double minY = points[0].y;
|
||||
double maxY = points[0].y;
|
||||
// compute the bounding coordinates (@todo: cleanup brute force)
|
||||
for (int i = 1; i < length; ++i) {
|
||||
if (points[offset + i].x < minX) {
|
||||
minX = points[offset + i].x;
|
||||
}
|
||||
if (points[offset + i].x > maxX) {
|
||||
maxX = points[offset + i].x;
|
||||
}
|
||||
if (points[offset + i].y < minY) {
|
||||
minY = points[offset + i].y;
|
||||
}
|
||||
if (points[offset + i].y > maxY) {
|
||||
maxY = points[offset + i].y;
|
||||
}
|
||||
}
|
||||
return Pair.of(Pair.of(minX, maxX), Pair.of(minY, maxY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate a set of points to a polygon
|
||||
*
|
||||
|
@ -503,8 +480,6 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
* direction of the ring
|
||||
* @param points
|
||||
* list of points to concatenate
|
||||
* @param pointOffset
|
||||
* index of the first point
|
||||
* @param edges
|
||||
* Array of edges to write the result to
|
||||
* @param edgeOffset
|
||||
|
@ -513,27 +488,29 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
* number of points to use
|
||||
* @return the edges creates
|
||||
*/
|
||||
private static Edge[] concat(int component, boolean direction, Coordinate[] points, final int pointOffset, Edge[] edges, final int edgeOffset,
|
||||
private static Edge[] concat(int component, boolean direction, GeoPoint[] points, Edge[] edges, final int edgeOffset,
|
||||
int length) {
|
||||
assert edges.length >= length+edgeOffset;
|
||||
assert points.length >= length+pointOffset;
|
||||
edges[edgeOffset] = new Edge(points[pointOffset], null);
|
||||
for (int i = 1; i < length; i++) {
|
||||
assert points.length >= length;
|
||||
edges[edgeOffset] = new Edge(points[0], null);
|
||||
int edgeEnd = edgeOffset + length;
|
||||
|
||||
for (int i = edgeOffset+1, p = 1; i < edgeEnd; ++i, ++p) {
|
||||
if (direction) {
|
||||
edges[edgeOffset + i] = new Edge(points[pointOffset + i], edges[edgeOffset + i - 1]);
|
||||
edges[edgeOffset + i].component = component;
|
||||
edges[i] = new Edge(points[p], edges[i - 1]);
|
||||
edges[i].component = component;
|
||||
} else {
|
||||
edges[edgeOffset + i - 1].next = edges[edgeOffset + i] = new Edge(points[pointOffset + i], null);
|
||||
edges[edgeOffset + i - 1].component = component;
|
||||
edges[i - 1].next = edges[i] = new Edge(points[p], null);
|
||||
edges[i - 1].component = component;
|
||||
}
|
||||
}
|
||||
|
||||
if (direction) {
|
||||
edges[edgeOffset].next = edges[edgeOffset + length - 1];
|
||||
edges[edgeOffset].next = edges[edgeEnd - 1];
|
||||
edges[edgeOffset].component = component;
|
||||
} else {
|
||||
edges[edgeOffset + length - 1].next = edges[edgeOffset];
|
||||
edges[edgeOffset + length - 1].component = component;
|
||||
edges[edgeEnd - 1].next = edges[edgeOffset];
|
||||
edges[edgeEnd - 1].component = component;
|
||||
}
|
||||
|
||||
return edges;
|
||||
|
@ -544,60 +521,25 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
*
|
||||
* @param points
|
||||
* array of point
|
||||
* @param offset
|
||||
* index of the first point
|
||||
* @param length
|
||||
* number of points
|
||||
* @return Array of edges
|
||||
*/
|
||||
protected static Edge[] ring(int component, boolean direction, boolean handedness, BaseLineStringBuilder<?> shell,
|
||||
Coordinate[] points, int offset, Edge[] edges, int toffset, int length) {
|
||||
GeoPoint[] points, Edge[] edges, int edgeOffset, int length) {
|
||||
// calculate the direction of the points:
|
||||
// find the point a the top of the set and check its
|
||||
// neighbors orientation. So direction is equivalent
|
||||
// to clockwise/counterclockwise
|
||||
final int top = top(points, offset, length);
|
||||
final int prev = (offset + ((top + length - 1) % length));
|
||||
final int next = (offset + ((top + 1) % length));
|
||||
boolean orientation = points[offset + prev].x > points[offset + next].x;
|
||||
boolean orientation = GeoUtils.computePolyOrientation(points, length);
|
||||
boolean corrected = GeoUtils.correctPolyAmbiguity(points, handedness, orientation, component, length,
|
||||
shell.translated);
|
||||
|
||||
// OGC requires shell as ccw (Right-Handedness) and holes as cw (Left-Handedness)
|
||||
// since GeoJSON doesn't specify (and doesn't need to) GEO core will assume OGC standards
|
||||
// thus if orientation is computed as cw, the logic will translate points across dateline
|
||||
// and convert to a right handed system
|
||||
|
||||
// compute the bounding box and calculate range
|
||||
Pair<Pair, Pair> range = range(points, offset, length);
|
||||
final double rng = (Double)range.getLeft().getRight() - (Double)range.getLeft().getLeft();
|
||||
// translate the points if the following is true
|
||||
// 1. shell orientation is cw and range is greater than a hemisphere (180 degrees) but not spanning 2 hemispheres
|
||||
// (translation would result in a collapsed poly)
|
||||
// 2. the shell of the candidate hole has been translated (to preserve the coordinate system)
|
||||
boolean incorrectOrientation = component == 0 && handedness != orientation;
|
||||
if ( (incorrectOrientation && (rng > DATELINE && rng != 2*DATELINE)) || (shell.translated && component != 0)) {
|
||||
translate(points);
|
||||
// flip the translation bit if the shell is being translated
|
||||
if (component == 0) {
|
||||
shell.translated = true;
|
||||
}
|
||||
// correct the orientation post translation (ccw for shell, cw for holes)
|
||||
if (component == 0 || (component != 0 && handedness == orientation)) {
|
||||
if (corrected && (component == 0 || (component != 0 && handedness == orientation))) {
|
||||
if (component == 0) {
|
||||
shell.translated = corrected;
|
||||
}
|
||||
orientation = !orientation;
|
||||
}
|
||||
}
|
||||
return concat(component, direction ^ orientation, points, offset, edges, toffset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms coordinates in the eastern hemisphere (-180:0) to a (180:360) range
|
||||
* @param points
|
||||
*/
|
||||
protected static void translate(Coordinate[] points) {
|
||||
for (Coordinate c : points) {
|
||||
if (c.x < 0) {
|
||||
c.x += 2*DATELINE;
|
||||
}
|
||||
}
|
||||
return concat(component, direction ^ orientation, points, edges, edgeOffset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -605,13 +547,13 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
*
|
||||
* @param position
|
||||
* position of the intersection [0..1]
|
||||
* @return the {@link Coordinate} of the intersection
|
||||
* @return the {@link GeoPoint} of the intersection
|
||||
*/
|
||||
protected Coordinate intersection(double position) {
|
||||
protected GeoPoint intersection(double position) {
|
||||
return intersect = position(coordinate, next.coordinate, position);
|
||||
}
|
||||
|
||||
public static Coordinate position(Coordinate p1, Coordinate p2, double position) {
|
||||
public static GeoPoint position(GeoPoint p1, GeoPoint p2, double position) {
|
||||
if (position == 0) {
|
||||
return p1;
|
||||
} else if (position == 1) {
|
||||
|
@ -619,7 +561,7 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
} else {
|
||||
final double x = p1.x + position * (p2.x - p1.x);
|
||||
final double y = p1.y + position * (p2.y - p1.y);
|
||||
return new Coordinate(x, y);
|
||||
return new GeoPoint(y, x);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -793,12 +735,12 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
"geo_shape ('envelope') when expecting an array of 2 coordinates");
|
||||
}
|
||||
// verify coordinate bounds, correct if necessary
|
||||
Coordinate uL = coordinates.children.get(0).coordinate;
|
||||
Coordinate lR = coordinates.children.get(1).coordinate;
|
||||
GeoPoint uL = coordinates.children.get(0).coordinate;
|
||||
GeoPoint lR = coordinates.children.get(1).coordinate;
|
||||
if (((lR.x < uL.x) || (uL.y < lR.y))) {
|
||||
Coordinate uLtmp = uL;
|
||||
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));
|
||||
GeoPoint uLtmp = uL;
|
||||
uL = new GeoPoint(Math.max(uL.y, lR.y), Math.min(uL.x, lR.x));
|
||||
lR = new GeoPoint(Math.min(uLtmp.y, lR.y), Math.max(uLtmp.x, lR.x));
|
||||
}
|
||||
return newEnvelope(orientation).topLeft(uL).bottomRight(lR);
|
||||
}
|
||||
|
|
|
@ -294,6 +294,10 @@ public class GeoShapeFieldMapper extends AbstractFieldMapper<String> {
|
|||
if (includeDefaults || defaultStrategy.getDistErrPct() != Defaults.DISTANCE_ERROR_PCT) {
|
||||
builder.field(Names.DISTANCE_ERROR_PCT, defaultStrategy.getDistErrPct());
|
||||
}
|
||||
|
||||
if (includeDefaults || shapeOrientation != Defaults.ORIENTATION ) {
|
||||
builder.field(Names.ORIENTATION, shapeOrientation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.lucene.search.Filter;
|
|||
import org.apache.lucene.util.Bits;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.geo.GeoPoint;
|
||||
import org.elasticsearch.common.geo.GeoUtils;
|
||||
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
|
||||
import org.elasticsearch.index.fielddata.MultiGeoPointValues;
|
||||
|
||||
|
@ -93,15 +94,27 @@ public class GeoPolygonFilter extends Filter {
|
|||
|
||||
private static boolean pointInPolygon(GeoPoint[] points, double lat, double lon) {
|
||||
boolean inPoly = false;
|
||||
// @TODO handedness will be an option provided by the parser
|
||||
boolean corrected = GeoUtils.correctPolyAmbiguity(points, false);
|
||||
GeoPoint p = (corrected) ?
|
||||
GeoUtils.convertToGreatCircle(lat, lon) :
|
||||
new GeoPoint(lat, lon);
|
||||
|
||||
GeoPoint pp0 = (corrected) ? GeoUtils.convertToGreatCircle(points[0]) : points[0] ;
|
||||
GeoPoint pp1;
|
||||
// simple even-odd PIP computation
|
||||
// 1. Determine if point is contained in the longitudinal range
|
||||
// 2. Determine whether point crosses the edge by computing the latitudinal delta
|
||||
// between the end-point of a parallel vector (originating at the point) and the
|
||||
// y-component of the edge sink
|
||||
for (int i = 1; i < points.length; i++) {
|
||||
if (points[i].lon() < lon && points[i-1].lon() >= lon
|
||||
|| points[i-1].lon() < lon && points[i].lon() >= lon) {
|
||||
if (points[i].lat() + (lon - points[i].lon()) /
|
||||
(points[i-1].lon() - points[i].lon()) * (points[i-1].lat() - points[i].lat()) < lat) {
|
||||
pp1 = points[i];
|
||||
if (pp1.x < p.x && pp0.x >= p.x || pp0.x < p.x && pp1.x >= p.x) {
|
||||
if (pp1.y + (p.x - pp1.x) / (pp0.x - pp1.x) * (pp0.y - pp1.y) < p.y) {
|
||||
inPoly = !inPoly;
|
||||
}
|
||||
}
|
||||
pp0 = pp1;
|
||||
}
|
||||
return inPoly;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,13 @@ import com.spatial4j.core.shape.Shape;
|
|||
import com.spatial4j.core.shape.ShapeCollection;
|
||||
import com.spatial4j.core.shape.jts.JtsGeometry;
|
||||
import com.spatial4j.core.shape.jts.JtsPoint;
|
||||
import com.vividsolutions.jts.geom.*;
|
||||
import com.vividsolutions.jts.geom.Geometry;
|
||||
import com.vividsolutions.jts.geom.GeometryFactory;
|
||||
import com.vividsolutions.jts.geom.LineString;
|
||||
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.ElasticsearchIllegalArgumentException;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
||||
|
@ -57,7 +63,7 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
|
|||
.startArray("coordinates").value(100.0).value(0.0).endArray()
|
||||
.endObject().string();
|
||||
|
||||
Point expected = GEOMETRY_FACTORY.createPoint(new Coordinate(100.0, 0.0));
|
||||
Point expected = GEOMETRY_FACTORY.createPoint(new GeoPoint(0.0, 100.0));
|
||||
assertGeometryEquals(new JtsPoint(expected, SPATIAL_CONTEXT), pointGeoJson);
|
||||
}
|
||||
|
||||
|
@ -69,12 +75,12 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
|
|||
.endArray()
|
||||
.endObject().string();
|
||||
|
||||
List<Coordinate> lineCoordinates = new ArrayList<>();
|
||||
lineCoordinates.add(new Coordinate(100, 0));
|
||||
lineCoordinates.add(new Coordinate(101, 1));
|
||||
List<GeoPoint> lineCoordinates = new ArrayList<>();
|
||||
lineCoordinates.add(new GeoPoint(0, 100));
|
||||
lineCoordinates.add(new GeoPoint(1, 101));
|
||||
|
||||
LineString expected = GEOMETRY_FACTORY.createLineString(
|
||||
lineCoordinates.toArray(new Coordinate[lineCoordinates.size()]));
|
||||
lineCoordinates.toArray(new GeoPoint[lineCoordinates.size()]));
|
||||
assertGeometryEquals(jtsGeom(expected), lineGeoJson);
|
||||
}
|
||||
|
||||
|
@ -93,13 +99,13 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
|
|||
.endObject().string();
|
||||
|
||||
MultiLineString expected = GEOMETRY_FACTORY.createMultiLineString(new LineString[]{
|
||||
GEOMETRY_FACTORY.createLineString(new Coordinate[]{
|
||||
new Coordinate(100, 0),
|
||||
new Coordinate(101, 1),
|
||||
GEOMETRY_FACTORY.createLineString(new GeoPoint[]{
|
||||
new GeoPoint(0, 100),
|
||||
new GeoPoint(1, 101),
|
||||
}),
|
||||
GEOMETRY_FACTORY.createLineString(new Coordinate[]{
|
||||
new Coordinate(102, 2),
|
||||
new Coordinate(103, 3),
|
||||
GEOMETRY_FACTORY.createLineString(new GeoPoint[]{
|
||||
new GeoPoint(2, 102),
|
||||
new GeoPoint(3, 103),
|
||||
}),
|
||||
});
|
||||
assertGeometryEquals(jtsGeom(expected), multilinesGeoJson);
|
||||
|
@ -173,14 +179,14 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
|
|||
.endArray()
|
||||
.endObject().string();
|
||||
|
||||
List<Coordinate> shellCoordinates = new ArrayList<>();
|
||||
shellCoordinates.add(new Coordinate(100, 0));
|
||||
shellCoordinates.add(new Coordinate(101, 0));
|
||||
shellCoordinates.add(new Coordinate(101, 1));
|
||||
shellCoordinates.add(new Coordinate(100, 1));
|
||||
shellCoordinates.add(new Coordinate(100, 0));
|
||||
List<GeoPoint> shellCoordinates = new ArrayList<>();
|
||||
shellCoordinates.add(new GeoPoint(0, 100));
|
||||
shellCoordinates.add(new GeoPoint(0, 101));
|
||||
shellCoordinates.add(new GeoPoint(1, 101));
|
||||
shellCoordinates.add(new GeoPoint(1, 100));
|
||||
shellCoordinates.add(new GeoPoint(0, 100));
|
||||
|
||||
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(shellCoordinates.toArray(new Coordinate[shellCoordinates.size()]));
|
||||
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(shellCoordinates.toArray(new GeoPoint[shellCoordinates.size()]));
|
||||
Polygon expected = GEOMETRY_FACTORY.createPolygon(shell, null);
|
||||
assertGeometryEquals(jtsGeom(expected), polygonGeoJson);
|
||||
}
|
||||
|
@ -567,25 +573,25 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
|
|||
.endArray()
|
||||
.endObject().string();
|
||||
|
||||
List<Coordinate> shellCoordinates = new ArrayList<>();
|
||||
shellCoordinates.add(new Coordinate(100, 0));
|
||||
shellCoordinates.add(new Coordinate(101, 0));
|
||||
shellCoordinates.add(new Coordinate(101, 1));
|
||||
shellCoordinates.add(new Coordinate(100, 1));
|
||||
shellCoordinates.add(new Coordinate(100, 0));
|
||||
List<GeoPoint> shellCoordinates = new ArrayList<>();
|
||||
shellCoordinates.add(new GeoPoint(0, 100));
|
||||
shellCoordinates.add(new GeoPoint(0, 101));
|
||||
shellCoordinates.add(new GeoPoint(1, 101));
|
||||
shellCoordinates.add(new GeoPoint(1, 100));
|
||||
shellCoordinates.add(new GeoPoint(0, 100));
|
||||
|
||||
List<Coordinate> holeCoordinates = new ArrayList<>();
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.2));
|
||||
holeCoordinates.add(new Coordinate(100.8, 0.2));
|
||||
holeCoordinates.add(new Coordinate(100.8, 0.8));
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.8));
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.2));
|
||||
List<GeoPoint> holeCoordinates = new ArrayList<>();
|
||||
holeCoordinates.add(new GeoPoint(0.2, 100.2));
|
||||
holeCoordinates.add(new GeoPoint(0.2, 100.8));
|
||||
holeCoordinates.add(new GeoPoint(0.8, 100.8));
|
||||
holeCoordinates.add(new GeoPoint(0.8, 100.2));
|
||||
holeCoordinates.add(new GeoPoint(0.2, 100.2));
|
||||
|
||||
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(
|
||||
shellCoordinates.toArray(new Coordinate[shellCoordinates.size()]));
|
||||
shellCoordinates.toArray(new GeoPoint[shellCoordinates.size()]));
|
||||
LinearRing[] holes = new LinearRing[1];
|
||||
holes[0] = GEOMETRY_FACTORY.createLinearRing(
|
||||
holeCoordinates.toArray(new Coordinate[holeCoordinates.size()]));
|
||||
holeCoordinates.toArray(new GeoPoint[holeCoordinates.size()]));
|
||||
Polygon expected = GEOMETRY_FACTORY.createPolygon(shell, holes);
|
||||
assertGeometryEquals(jtsGeom(expected), polygonGeoJson);
|
||||
}
|
||||
|
@ -657,34 +663,34 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
|
|||
.endArray()
|
||||
.endObject().string();
|
||||
|
||||
List<Coordinate> shellCoordinates = new ArrayList<>();
|
||||
shellCoordinates.add(new Coordinate(100, 0));
|
||||
shellCoordinates.add(new Coordinate(101, 0));
|
||||
shellCoordinates.add(new Coordinate(101, 1));
|
||||
shellCoordinates.add(new Coordinate(100, 1));
|
||||
shellCoordinates.add(new Coordinate(100, 0));
|
||||
List<GeoPoint> shellCoordinates = new ArrayList<>();
|
||||
shellCoordinates.add(new GeoPoint(0, 100));
|
||||
shellCoordinates.add(new GeoPoint(0, 101));
|
||||
shellCoordinates.add(new GeoPoint(1, 101));
|
||||
shellCoordinates.add(new GeoPoint(1, 100));
|
||||
shellCoordinates.add(new GeoPoint(0, 100));
|
||||
|
||||
List<Coordinate> holeCoordinates = new ArrayList<>();
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.2));
|
||||
holeCoordinates.add(new Coordinate(100.8, 0.2));
|
||||
holeCoordinates.add(new Coordinate(100.8, 0.8));
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.8));
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.2));
|
||||
List<GeoPoint> holeCoordinates = new ArrayList<>();
|
||||
holeCoordinates.add(new GeoPoint(0.2, 100.2));
|
||||
holeCoordinates.add(new GeoPoint(0.2, 100.8));
|
||||
holeCoordinates.add(new GeoPoint(0.8, 100.8));
|
||||
holeCoordinates.add(new GeoPoint(0.8, 100.2));
|
||||
holeCoordinates.add(new GeoPoint(0.2, 100.2));
|
||||
|
||||
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(shellCoordinates.toArray(new Coordinate[shellCoordinates.size()]));
|
||||
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(shellCoordinates.toArray(new GeoPoint[shellCoordinates.size()]));
|
||||
LinearRing[] holes = new LinearRing[1];
|
||||
holes[0] = GEOMETRY_FACTORY.createLinearRing(holeCoordinates.toArray(new Coordinate[holeCoordinates.size()]));
|
||||
holes[0] = GEOMETRY_FACTORY.createLinearRing(holeCoordinates.toArray(new GeoPoint[holeCoordinates.size()]));
|
||||
Polygon withHoles = GEOMETRY_FACTORY.createPolygon(shell, holes);
|
||||
|
||||
shellCoordinates = new ArrayList<>();
|
||||
shellCoordinates.add(new Coordinate(102, 3));
|
||||
shellCoordinates.add(new Coordinate(103, 3));
|
||||
shellCoordinates.add(new Coordinate(103, 2));
|
||||
shellCoordinates.add(new Coordinate(102, 2));
|
||||
shellCoordinates.add(new Coordinate(102, 3));
|
||||
shellCoordinates.add(new GeoPoint(3, 102));
|
||||
shellCoordinates.add(new GeoPoint(3, 103));
|
||||
shellCoordinates.add(new GeoPoint(2, 103));
|
||||
shellCoordinates.add(new GeoPoint(2, 102));
|
||||
shellCoordinates.add(new GeoPoint(3, 102));
|
||||
|
||||
|
||||
shell = GEOMETRY_FACTORY.createLinearRing(shellCoordinates.toArray(new Coordinate[shellCoordinates.size()]));
|
||||
shell = GEOMETRY_FACTORY.createLinearRing(shellCoordinates.toArray(new GeoPoint[shellCoordinates.size()]));
|
||||
Polygon withoutHoles = GEOMETRY_FACTORY.createPolygon(shell, null);
|
||||
|
||||
Shape expected = shapeCollection(withoutHoles, withHoles);
|
||||
|
@ -716,22 +722,22 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
|
|||
.endObject().string();
|
||||
|
||||
shellCoordinates = new ArrayList<>();
|
||||
shellCoordinates.add(new Coordinate(100, 1));
|
||||
shellCoordinates.add(new Coordinate(101, 1));
|
||||
shellCoordinates.add(new Coordinate(101, 0));
|
||||
shellCoordinates.add(new Coordinate(100, 0));
|
||||
shellCoordinates.add(new Coordinate(100, 1));
|
||||
shellCoordinates.add(new GeoPoint(1, 100));
|
||||
shellCoordinates.add(new GeoPoint(1, 101));
|
||||
shellCoordinates.add(new GeoPoint(0, 101));
|
||||
shellCoordinates.add(new GeoPoint(0, 100));
|
||||
shellCoordinates.add(new GeoPoint(1, 100));
|
||||
|
||||
holeCoordinates = new ArrayList<>();
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.8));
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.2));
|
||||
holeCoordinates.add(new Coordinate(100.8, 0.2));
|
||||
holeCoordinates.add(new Coordinate(100.8, 0.8));
|
||||
holeCoordinates.add(new Coordinate(100.2, 0.8));
|
||||
holeCoordinates.add(new GeoPoint(0.8, 100.2));
|
||||
holeCoordinates.add(new GeoPoint(0.2, 100.2));
|
||||
holeCoordinates.add(new GeoPoint(0.2, 100.8));
|
||||
holeCoordinates.add(new GeoPoint(0.8, 100.8));
|
||||
holeCoordinates.add(new GeoPoint(0.8, 100.2));
|
||||
|
||||
shell = GEOMETRY_FACTORY.createLinearRing(shellCoordinates.toArray(new Coordinate[shellCoordinates.size()]));
|
||||
shell = GEOMETRY_FACTORY.createLinearRing(shellCoordinates.toArray(new GeoPoint[shellCoordinates.size()]));
|
||||
holes = new LinearRing[1];
|
||||
holes[0] = GEOMETRY_FACTORY.createLinearRing(holeCoordinates.toArray(new Coordinate[holeCoordinates.size()]));
|
||||
holes[0] = GEOMETRY_FACTORY.createLinearRing(holeCoordinates.toArray(new GeoPoint[holeCoordinates.size()]));
|
||||
withHoles = GEOMETRY_FACTORY.createPolygon(shell, holes);
|
||||
|
||||
assertGeometryEquals(jtsGeom(withHoles), multiPolygonGeoJson);
|
||||
|
@ -757,12 +763,12 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
|
|||
.string();
|
||||
|
||||
Shape[] expected = new Shape[2];
|
||||
LineString expectedLineString = GEOMETRY_FACTORY.createLineString(new Coordinate[]{
|
||||
new Coordinate(100, 0),
|
||||
new Coordinate(101, 1),
|
||||
LineString expectedLineString = GEOMETRY_FACTORY.createLineString(new GeoPoint[]{
|
||||
new GeoPoint(0, 100),
|
||||
new GeoPoint(1, 101),
|
||||
});
|
||||
expected[0] = jtsGeom(expectedLineString);
|
||||
Point expectedPoint = GEOMETRY_FACTORY.createPoint(new Coordinate(102.0, 2.0));
|
||||
Point expectedPoint = GEOMETRY_FACTORY.createPoint(new GeoPoint(2.0, 102.0));
|
||||
expected[1] = new JtsPoint(expectedPoint, SPATIAL_CONTEXT);
|
||||
|
||||
//equals returns true only if geometries are in the same order
|
||||
|
@ -785,7 +791,7 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
|
|||
.startObject("lala").field("type", "NotAPoint").endObject()
|
||||
.endObject().string();
|
||||
|
||||
Point expected = GEOMETRY_FACTORY.createPoint(new Coordinate(100.0, 0.0));
|
||||
Point expected = GEOMETRY_FACTORY.createPoint(new GeoPoint(0.0, 100.0));
|
||||
assertGeometryEquals(new JtsPoint(expected, SPATIAL_CONTEXT), pointGeoJson);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ import com.spatial4j.core.shape.Point;
|
|||
import com.spatial4j.core.shape.Rectangle;
|
||||
import com.spatial4j.core.shape.Shape;
|
||||
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.PolygonBuilder;
|
||||
|
@ -64,38 +63,39 @@ public class ShapeBuilderTests extends ElasticsearchTestCase {
|
|||
.point(-45, 30).toPolygon();
|
||||
|
||||
LineString exterior = polygon.getExteriorRing();
|
||||
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
|
||||
assertEquals(exterior.getCoordinateN(1), new Coordinate(45, 30));
|
||||
assertEquals(exterior.getCoordinateN(2), new Coordinate(45, -30));
|
||||
assertEquals(exterior.getCoordinateN(3), new Coordinate(-45, -30));
|
||||
assertEquals(exterior.getCoordinateN(0), new GeoPoint(30, -45));
|
||||
assertEquals(exterior.getCoordinateN(1), new GeoPoint(30, 45));
|
||||
assertEquals(exterior.getCoordinateN(2), new GeoPoint(-30, 45));
|
||||
assertEquals(exterior.getCoordinateN(3), new GeoPoint(-30, -45));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewPolygon_coordinate() {
|
||||
Polygon polygon = ShapeBuilder.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();
|
||||
.point(new GeoPoint(30, -45))
|
||||
.point(new GeoPoint(30, 45))
|
||||
.point(new GeoPoint(-30, 45))
|
||||
.point(new GeoPoint(-30, -45))
|
||||
.point(new GeoPoint(30, -45)).toPolygon();
|
||||
|
||||
LineString exterior = polygon.getExteriorRing();
|
||||
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
|
||||
assertEquals(exterior.getCoordinateN(1), new Coordinate(45, 30));
|
||||
assertEquals(exterior.getCoordinateN(2), new Coordinate(45, -30));
|
||||
assertEquals(exterior.getCoordinateN(3), new Coordinate(-45, -30));
|
||||
assertEquals(exterior.getCoordinateN(0), new GeoPoint(30, -45));
|
||||
assertEquals(exterior.getCoordinateN(1), new GeoPoint(30, 45));
|
||||
assertEquals(exterior.getCoordinateN(2), new GeoPoint(-30, 45));
|
||||
assertEquals(exterior.getCoordinateN(3), new GeoPoint(-30, -45));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewPolygon_coordinates() {
|
||||
Polygon polygon = ShapeBuilder.newPolygon()
|
||||
.points(new Coordinate(-45, 30), new Coordinate(45, 30), new Coordinate(45, -30), new Coordinate(-45, -30), new Coordinate(-45, 30)).toPolygon();
|
||||
.points(new GeoPoint(30, -45), new GeoPoint(30, 45), new GeoPoint(-30, 45), new GeoPoint(-30, -45),
|
||||
new GeoPoint(30, -45)).toPolygon();
|
||||
|
||||
LineString exterior = polygon.getExteriorRing();
|
||||
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
|
||||
assertEquals(exterior.getCoordinateN(1), new Coordinate(45, 30));
|
||||
assertEquals(exterior.getCoordinateN(2), new Coordinate(45, -30));
|
||||
assertEquals(exterior.getCoordinateN(3), new Coordinate(-45, -30));
|
||||
assertEquals(exterior.getCoordinateN(0), new GeoPoint(30, -45));
|
||||
assertEquals(exterior.getCoordinateN(1), new GeoPoint(30, 45));
|
||||
assertEquals(exterior.getCoordinateN(2), new GeoPoint(-30, 45));
|
||||
assertEquals(exterior.getCoordinateN(3), new GeoPoint(-30, -45));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue