Skip to content

Commit

Permalink
Revert "[GEO] Update GeoPolygonFilter to handle ambiguous polygons"
Browse files Browse the repository at this point in the history
This reverts commit 06667c6 which introduces an undesireable dependency on JTS.
  • Loading branch information
nknize committed Jan 28, 2015
1 parent 8978aa5 commit 9622f78
Show file tree
Hide file tree
Showing 17 changed files with 327 additions and 411 deletions.
59 changes: 27 additions & 32 deletions src/main/java/org/elasticsearch/common/geo/GeoPoint.java
Expand Up @@ -20,12 +20,13 @@
package org.elasticsearch.common.geo;


import com.vividsolutions.jts.geom.Coordinate;

/**
*
*/
public final class GeoPoint extends Coordinate {
public final class GeoPoint {

private double lat;
private double lon;

public GeoPoint() {
}
Expand All @@ -40,36 +41,32 @@ public GeoPoint(String value) {
this.resetFromString(value);
}

public GeoPoint(GeoPoint other) {
super(other);
}

public GeoPoint(double lat, double lon) {
this.y = lat;
this.x = lon;
this.lat = lat;
this.lon = lon;
}

public GeoPoint reset(double lat, double lon) {
this.y = lat;
this.x = lon;
this.lat = lat;
this.lon = lon;
return this;
}

public GeoPoint resetLat(double lat) {
this.y = lat;
this.lat = lat;
return this;
}

public GeoPoint resetLon(double lon) {
this.x = lon;
this.lon = lon;
return this;
}

public GeoPoint resetFromString(String value) {
int comma = value.indexOf(',');
if (comma != -1) {
this.y = Double.parseDouble(value.substring(0, comma).trim());
this.x = Double.parseDouble(value.substring(comma + 1).trim());
lat = Double.parseDouble(value.substring(0, comma).trim());
lon = Double.parseDouble(value.substring(comma + 1).trim());
} else {
resetFromGeoHash(value);
}
Expand All @@ -82,40 +79,38 @@ public GeoPoint resetFromGeoHash(String hash) {
}

public final double lat() {
return this.y;
return this.lat;
}

public final double getLat() {
return this.y;
return this.lat;
}

public final double lon() {
return this.x;
return this.lon;
}

public final double getLon() {
return this.x;
return this.lon;
}

public final String geohash() {
return GeoHashUtils.encode(y, x);
return GeoHashUtils.encode(lat, lon);
}

public final String getGeohash() {
return GeoHashUtils.encode(y, x);
return GeoHashUtils.encode(lat, lon);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
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;
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;

return true;
}
Expand All @@ -124,15 +119,15 @@ public boolean equals(Object o) {
public int hashCode() {
int result;
long temp;
temp = y != +0.0d ? Double.doubleToLongBits(y) : 0L;
temp = lat != +0.0d ? Double.doubleToLongBits(lat) : 0L;
result = (int) (temp ^ (temp >>> 32));
temp = x != +0.0d ? Double.doubleToLongBits(x) : 0L;
temp = lon != +0.0d ? Double.doubleToLongBits(lon) : 0L;
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}

public String toString() {
return "[" + y + ", " + x + "]";
return "[" + lat + ", " + lon + "]";
}

public static GeoPoint parseFromLatLon(String latLon) {
Expand Down
112 changes: 1 addition & 111 deletions src/main/java/org/elasticsearch/common/geo/GeoUtils.java
Expand Up @@ -19,7 +19,6 @@

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;
Expand All @@ -38,9 +37,7 @@ public class GeoUtils {
public static final String LATITUDE = GeoPointFieldMapper.Names.LAT;
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)

Expand Down Expand Up @@ -425,113 +422,6 @@ public static GeoPoint parseGeoPoint(XContentParser parser, GeoPoint point) thro
}
}

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() {
}
}
Expand Up @@ -23,22 +23,22 @@
import java.util.ArrayList;
import java.util.Arrays;

import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.GeoUtils;
import com.spatial4j.core.shape.ShapeCollection;
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;

public abstract class BaseLineStringBuilder<E extends BaseLineStringBuilder<E>> extends PointCollection<E> {

protected BaseLineStringBuilder() {
this(new ArrayList<GeoPoint>());
this(new ArrayList<Coordinate>());
}

protected BaseLineStringBuilder(ArrayList<GeoPoint> points) {
protected BaseLineStringBuilder(ArrayList<Coordinate> points) {
super(points);
}

Expand All @@ -49,7 +49,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws

@Override
public Shape build() {
GeoPoint[] coordinates = points.toArray(new GeoPoint[points.size()]);
Coordinate[] coordinates = points.toArray(new Coordinate[points.size()]);
Geometry geometry;
if(wrapdateline) {
ArrayList<LineString> strings = decompose(FACTORY, coordinates, new ArrayList<LineString>());
Expand All @@ -67,9 +67,9 @@ public Shape build() {
return jtsGeometry(geometry);
}

protected static ArrayList<LineString> decompose(GeometryFactory factory, GeoPoint[] coordinates, ArrayList<LineString> strings) {
for(GeoPoint[] part : decompose(+DATELINE, coordinates)) {
for(GeoPoint[] line : decompose(-DATELINE, part)) {
protected static ArrayList<LineString> decompose(GeometryFactory factory, Coordinate[] coordinates, ArrayList<LineString> strings) {
for(Coordinate[] part : decompose(+DATELINE, coordinates)) {
for(Coordinate[] line : decompose(-DATELINE, part)) {
strings.add(factory.createLineString(line));
}
}
Expand All @@ -83,16 +83,16 @@ protected static ArrayList<LineString> decompose(GeometryFactory factory, GeoPoi
* @param coordinates coordinates forming the linestring
* @return array of linestrings given as coordinate arrays
*/
protected static GeoPoint[][] decompose(double dateline, GeoPoint[] coordinates) {
protected static Coordinate[][] decompose(double dateline, Coordinate[] coordinates) {
int offset = 0;
ArrayList<GeoPoint[]> parts = new ArrayList<>();
ArrayList<Coordinate[]> 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)) {
GeoPoint[] part;
Coordinate[] part;
if(t<1) {
part = Arrays.copyOfRange(coordinates, offset, i+1);
part[part.length-1] = Edge.position(coordinates[i-1], coordinates[i], t);
Expand All @@ -111,16 +111,16 @@ protected static GeoPoint[][] decompose(double dateline, GeoPoint[] coordinates)
if(offset == 0) {
parts.add(shift(shift, coordinates));
} else if(offset < coordinates.length-1) {
GeoPoint[] part = Arrays.copyOfRange(coordinates, offset, coordinates.length);
Coordinate[] part = Arrays.copyOfRange(coordinates, offset, coordinates.length);
parts.add(shift(shift, part));
}
return parts.toArray(new GeoPoint[parts.size()][]);
return parts.toArray(new Coordinate[parts.size()][]);
}

private static GeoPoint[] shift(double shift, GeoPoint...coordinates) {
private static Coordinate[] shift(double shift, Coordinate...coordinates) {
if(shift != 0) {
for (int j = 0; j < coordinates.length; j++) {
coordinates[j] = new GeoPoint(coordinates[j].y, coordinates[j].x - 2 * shift);
coordinates[j] = new Coordinate(coordinates[j].x - 2 * shift, coordinates[j].y);
}
}
return coordinates;
Expand Down

0 comments on commit 9622f78

Please sign in to comment.