Geo: Issue with polygons near date line

If a polygon is constructed which overlaps the date line but has a hole which lies entirely one to one side of the date line, JTS error saying that the hole is not within the bounds of the polygon because the code which splits the polygon either side of the date line does not add the hole to the correct component of the final set of polygons.  The fix ensures this selection happens correctly.

Closes #6179
This commit is contained in:
Colin Goodheart-Smithe 2014-05-22 14:35:41 +01:00
parent ea80b381c0
commit a23e4aefaa
2 changed files with 49 additions and 11 deletions

View File

@ -19,21 +19,15 @@
package org.elasticsearch.common.geo.builders;
import com.spatial4j.core.shape.Shape;
import com.vividsolutions.jts.geom.*;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
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.LinearRing;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;
/**
* The {@link BasePolygonBuilder} implements the groundwork to create polygons. This contains
* Methods to wrap polygons at the dateline and building shapes from the data held by the
@ -358,7 +352,10 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
LOGGER.debug("Holes: " + Arrays.toString(holes));
}
for (int i = 0; i < numHoles; i++) {
final Edge current = holes[i];
final Edge current = new Edge(holes[i].coordinate, holes[i].next);
// the edge intersects with itself at its own coordinate. We need intersect to be set this way so the binary search
// will get the correct position in the edge list and therefore the correct component to add the hole
current.intersect = current.coordinate;
final int intersections = intersections(current.coordinate.x, edges);
final int pos = Arrays.binarySearch(edges, 0, intersections, current, INTERSECTION_ORDER);
assert pos < 0 : "illegal state: two edges cross the datum at the same position";

View File

@ -25,6 +25,7 @@ import com.spatial4j.core.shape.Shape;
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;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.junit.Test;
@ -192,5 +193,45 @@ public class ShapeBuilderTests extends ElasticsearchTestCase {
assertMultiLineString(shape);
}
@Test
public void testDateline() {
// view shape at https://gist.github.com/anonymous/7f1bb6d7e9cd72f5977c
// expect 3 polygons, 1 with a hole
// a giant c shape
PolygonBuilder builder = ShapeBuilder.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);
// 3/4 of an embedded 'c', crossing dateline once
builder.hole()
.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);
// embedded hole right of the dateline
builder.hole()
.point(-179,1)
.point(-177,1)
.point(-177,2)
.point(-179,2)
.point(-179,1);
Shape shape = builder.close().build();
assertMultiPolygon(shape);
}
}