Updating translation gate check to disregard order of hole vertices for non dateline crossing polys.

Updating comments and code readability

Correcting code formatting
This commit is contained in:
Nicholas Knize 2014-12-03 07:16:06 -06:00
parent e9e13d5cfc
commit 85502ac40a
4 changed files with 94 additions and 39 deletions

View File

@ -403,9 +403,10 @@ public abstract class BasePolygonBuilder<E extends BasePolygonBuilder<E>> extend
// The connect method creates a new edge for these paired edges in the linked list. // The connect method creates a new edge for these paired edges in the linked list.
// For boundary conditions (e.g., intersect but not crossing) there is no sibling edge // For boundary conditions (e.g., intersect but not crossing) there is no sibling edge
// to connect. Thus the first logic check enforces the pairwise rule // to connect. Thus the first logic check enforces the pairwise rule
// 2. the second logic ensures the two candidate edges aren't already connected by an // 2. the second logic check ensures the two candidate edges aren't already connected by an
// existing along the dateline - this is necessary due to a logic change that // existing edge along the dateline - this is necessary due to a logic change in
// computes dateline edges as valid intersect points in support of OGC standards // ShapeBuilder.intersection that computes dateline edges as valid intersect points
// in support of OGC standards
if (e1.intersect != Edge.MAX_COORDINATE && e2.intersect != Edge.MAX_COORDINATE if (e1.intersect != Edge.MAX_COORDINATE && e2.intersect != Edge.MAX_COORDINATE
&& !(e1.next.next.coordinate.equals3D(e2.coordinate) && Math.abs(e1.next.coordinate.x) == DATELINE && !(e1.next.next.coordinate.equals3D(e2.coordinate) && Math.abs(e1.next.coordinate.x) == DATELINE
&& Math.abs(e2.coordinate.x) == DATELINE) ) { && Math.abs(e2.coordinate.x) == DATELINE) ) {

View File

@ -486,7 +486,7 @@ public abstract class ShapeBuilder implements ToXContent {
* @return Array of edges * @return Array of edges
*/ */
protected static Edge[] ring(int component, boolean direction, BaseLineStringBuilder<?> shell, Coordinate[] points, int offset, protected static Edge[] ring(int component, boolean direction, BaseLineStringBuilder<?> shell, Coordinate[] points, int offset,
Edge[] edges, int toffset, int length) { Edge[] edges, int toffset, int length) {
// calculate the direction of the points: // calculate the direction of the points:
// find the point a the top of the set and check its // find the point a the top of the set and check its
// neighbors orientation. So direction is equivalent // neighbors orientation. So direction is equivalent
@ -505,11 +505,11 @@ public abstract class ShapeBuilder implements ToXContent {
Pair<Pair, Pair> range = range(points, offset, length); Pair<Pair, Pair> range = range(points, offset, length);
final double rng = (Double)range.getLeft().getRight() - (Double)range.getLeft().getLeft(); final double rng = (Double)range.getLeft().getRight() - (Double)range.getLeft().getLeft();
// translate the points if the following is true // translate the points if the following is true
// 1. range is greater than a hemisphere (180 degrees) but not spanning 2 hemispheres (translation would result in // 1. shell orientation is cw and range is greater than a hemisphere (180 degrees) but not spanning 2 hemispheres
// a collapsed poly) // (translation would result in a collapsed poly)
// 2. the shell of the candidate hole has been translated (to preserve the coordinate system) // 2. the shell of the candidate hole has been translated (to preserve the coordinate system)
if ((rng > DATELINE && rng != 2*DATELINE && orientation) || (shell.translated && component != 0)) { if ((rng > DATELINE && rng != 2*DATELINE && orientation && component == 0) || (shell.translated && component != 0)) {
transform(points); translate(points);
// flip the translation bit if the shell is being translated // flip the translation bit if the shell is being translated
if (component == 0 && !shell.translated) { if (component == 0 && !shell.translated) {
shell.translated = true; shell.translated = true;
@ -526,7 +526,7 @@ public abstract class ShapeBuilder implements ToXContent {
* Transforms coordinates in the eastern hemisphere (-180:0) to a (180:360) range * Transforms coordinates in the eastern hemisphere (-180:0) to a (180:360) range
* @param points * @param points
*/ */
protected static void transform(Coordinate[] points) { protected static void translate(Coordinate[] points) {
for (Coordinate c : points) { for (Coordinate c : points) {
if (c.x < 0) { if (c.x < 0) {
c.x += 2*DATELINE; c.x += 2*DATELINE;

View File

@ -210,8 +210,8 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
} }
@Test @Test
public void testParse_polygonNoHolesOGCCompliance() throws IOException { public void testParse_OGCPolygonWithoutHoles() throws IOException {
// test ccw poly (large poly intended to not cross dateline) // test ccw poly not crossing dateline
String polygonGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "Polygon") String polygonGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "Polygon")
.startArray("coordinates") .startArray("coordinates")
.startArray() .startArray()
@ -229,7 +229,9 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
parser.nextToken(); parser.nextToken();
Shape shape = ShapeBuilder.parse(parser).build(); Shape shape = ShapeBuilder.parse(parser).build();
// test cw poly (small poly expected to cross dateline) ElasticsearchGeoAssertions.assertPolygon(shape);
// test ccw poly crossing dateline
polygonGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "Polygon") polygonGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "Polygon")
.startArray("coordinates") .startArray("coordinates")
.startArray() .startArray()
@ -246,12 +248,64 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
parser = JsonXContent.jsonXContent.createParser(polygonGeoJson); parser = JsonXContent.jsonXContent.createParser(polygonGeoJson);
parser.nextToken(); parser.nextToken();
shape = ShapeBuilder.parse(parser).build(); shape = ShapeBuilder.parse(parser).build();
ElasticsearchGeoAssertions.assertMultiPolygon(shape);
} }
// @Test @Test
// public void testParse_polygonWithHolesWKTReorder() throws IOException { public void testParse_OGCPolygonWithHoles() throws IOException {
// // test ccw poly not crossing dateline
// } String polygonGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "Polygon")
.startArray("coordinates")
.startArray()
.startArray().value(176.0).value(15.0).endArray()
.startArray().value(-177.0).value(10.0).endArray()
.startArray().value(-177.0).value(-10.0).endArray()
.startArray().value(176.0).value(-15.0).endArray()
.startArray().value(172.0).value(0.0).endArray()
.startArray().value(176.0).value(15.0).endArray()
.endArray()
.startArray()
.startArray().value(-172.0).value(8.0).endArray()
.startArray().value(174.0).value(10.0).endArray()
.startArray().value(-172.0).value(-8.0).endArray()
.startArray().value(-172.0).value(8.0).endArray()
.endArray()
.endArray()
.endObject().string();
XContentParser parser = JsonXContent.jsonXContent.createParser(polygonGeoJson);
parser.nextToken();
Shape shape = ShapeBuilder.parse(parser).build();
ElasticsearchGeoAssertions.assertPolygon(shape);
// test ccw poly crossing dateline
polygonGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "Polygon")
.startArray("coordinates")
.startArray()
.startArray().value(-177.0).value(10.0).endArray()
.startArray().value(176.0).value(15.0).endArray()
.startArray().value(172.0).value(0.0).endArray()
.startArray().value(176.0).value(-15.0).endArray()
.startArray().value(-177.0).value(-10.0).endArray()
.startArray().value(-177.0).value(10.0).endArray()
.endArray()
.startArray()
.startArray().value(178.0).value(8.0).endArray()
.startArray().value(-178.0).value(8.0).endArray()
.startArray().value(-180.0).value(-8.0).endArray()
.startArray().value(178.0).value(8.0).endArray()
.endArray()
.endArray()
.endObject().string();
parser = JsonXContent.jsonXContent.createParser(polygonGeoJson);
parser.nextToken();
shape = ShapeBuilder.parse(parser).build();
ElasticsearchGeoAssertions.assertMultiPolygon(shape);
}
@Test @Test
public void testParse_invalidPolygon() throws IOException { public void testParse_invalidPolygon() throws IOException {

View File

@ -246,35 +246,35 @@ public class ShapeBuilderTests extends ElasticsearchTestCase {
// a giant c shape // a giant c shape
PolygonBuilder builder = ShapeBuilder.newPolygon() PolygonBuilder builder = ShapeBuilder.newPolygon()
.point(174,0) .point(174,0)
.point(-176,0) .point(-176,0)
.point(-176,3) .point(-176,3)
.point(177,3) .point(177,3)
.point(177,5) .point(177,5)
.point(-176,5) .point(-176,5)
.point(-176,8) .point(-176,8)
.point(174,8) .point(174,8)
.point(174,0); .point(174,0);
// 3/4 of an embedded 'c', crossing dateline once // 3/4 of an embedded 'c', crossing dateline once
builder.hole() builder.hole()
.point(175, 1) .point(175, 1)
.point(175, 7) .point(175, 7)
.point(-178, 7) .point(-178, 7)
.point(-178, 6) .point(-178, 6)
.point(176, 6) .point(176, 6)
.point(176, 2) .point(176, 2)
.point(179, 2) .point(179, 2)
.point(179,1) .point(179,1)
.point(175, 1); .point(175, 1);
// embedded hole right of the dateline // embedded hole right of the dateline
builder.hole() builder.hole()
.point(-179, 1) .point(-179, 1)
.point(-179, 2) .point(-179, 2)
.point(-177, 2) .point(-177, 2)
.point(-177,1) .point(-177,1)
.point(-179,1); .point(-179,1);
Shape shape = builder.close().build(); Shape shape = builder.close().build();