Răsfoiți Sursa

Adding unit test for self intersecting polygons. Relevant to #7751 even/odd discussion

Updating documentation to describe polygon ambiguity and vertex ordering.
Nicholas Knize 11 ani în urmă
părinte
comite
ac0e37449e

+ 31 - 1
docs/reference/mapping/types/geo-shape-type.asciidoc

@@ -157,7 +157,7 @@ units, which default to `METERS`.
 For all types, both the inner `type` and `coordinates` fields are
 required.
 
-Note: In GeoJSON, and therefore Elasticsearch, the correct *coordinate
+In GeoJSON, and therefore Elasticsearch, the correct *coordinate
 order is longitude, latitude (X, Y)* within coordinate arrays. This
 differs from many Geospatial APIs (e.g., Google Maps) that generally
 use the colloquial latitude, longitude (Y, X).
@@ -235,6 +235,36 @@ arrays represent the interior shapes ("holes"):
 }
 --------------------------------------------------
 
+*IMPORTANT NOTE:* GeoJSON does not mandate a specific order for vertices thus ambiguous
+polygons around the dateline and poles are possible. To alleviate ambiguity
+the Open Geospatial Consortium (OGC)
+http://www.opengeospatial.org/standards/sfa[Simple Feature Access] specification
+defines the following vertex ordering:
+
+* Outer Ring - Counterclockwise
+* Inner Ring(s) / Holes - Clockwise
+
+For polygons that do not cross the dateline, vertex order will not matter in
+Elasticsearch. For polygons that do cross the dateline, Elasticsearch requires
+vertex orderinging comply with the OGC specification. Otherwise, an unintended polygon
+may be created and unexpected query/filter results will be returned.
+
+The following provides an example of an ambiguous polygon.  Elasticsearch will apply
+OGC standards to eliminate ambiguity resulting in a polygon that crosses the dateline.
+
+[source,js]
+--------------------------------------------------
+{
+    "location" : {
+        "type" : "polygon",
+        "coordinates" : [
+            [ [-177.0, 10.0], [176.0, 15.0], [172.0, 0.0], [176.0, -15.0], [-177.0, -10.0], [-177.0, 10.0] ],
+            [ [178.2, 8.2], [-178.8, 8.2], [-180.8, -8.8], [178.2, 8.8] ]
+        ]
+    }
+}
+--------------------------------------------------
+
 [float]
 ===== http://www.geojson.org/geojson-spec.html#id5[MultiPoint]
 

+ 23 - 0
src/test/java/org/elasticsearch/common/geo/GeoJSONShapeParserTests.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.common.geo;
 
+import com.spatial4j.core.exception.InvalidShapeException;
 import com.spatial4j.core.shape.Circle;
 import com.spatial4j.core.shape.Rectangle;
 import com.spatial4j.core.shape.Shape;
@@ -430,6 +431,28 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
         assertGeometryEquals(jtsGeom(expected), polygonGeoJson);
     }
 
+    @Test
+    public void testParse_selfCrossingPolygon() throws IOException {
+        // test self crossing 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(-177.0).value(15.0).endArray()
+                .startArray().value(172.0).value(0.0).endArray()
+                .startArray().value(176.0).value(15.0).endArray()
+                .endArray()
+                .endArray()
+                .endObject().string();
+
+        XContentParser parser = JsonXContent.jsonXContent.createParser(polygonGeoJson);
+        parser.nextToken();
+        ElasticsearchGeoAssertions.assertValidException(parser, InvalidShapeException.class);
+    }
+
     @Test
     public void testParse_multiPoint() throws IOException {
         String multiPointGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "MultiPoint")

+ 1 - 1
src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchGeoAssertions.java

@@ -251,7 +251,7 @@ public class ElasticsearchGeoAssertions {
 
     public static void assertValidException(XContentParser parser, Class expectedException) {
         try {
-            ShapeBuilder.parse(parser);
+            ShapeBuilder.parse(parser).build();
             Assert.fail("process completed successfully when " + expectedException.getName() + " expected");
         } catch (Exception e) {
             assert(e.getClass().equals(expectedException)):