Skip to content

Commit

Permalink
[GEO] GIS envelope validation
Browse files Browse the repository at this point in the history
ShapeBuilder expected coordinates for Envelope types in strict Top-Left, Bottom-Right order. Given that GeoJSON does not enforce coordinate order (as seen in #8672) clients could specify envelope bounds in any order and be compliant with the GeoJSON spec but not the ES ShapeBuilder logic. This change loosens the ShapeBuilder requirements on envelope coordinate order, reordering where necessary.

closes #2544
closes #9067
closes #9079
closes #9080
  • Loading branch information
nknize committed Dec 30, 2014
1 parent d7cb94e commit 4679c37
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 2 deletions.
Expand Up @@ -787,8 +787,20 @@ protected static CircleBuilder parseCircle(CoordinateNode coordinates, Distance
}

protected static EnvelopeBuilder parseEnvelope(CoordinateNode coordinates, Orientation orientation) {
return newEnvelope(orientation).
topLeft(coordinates.children.get(0).coordinate).bottomRight(coordinates.children.get(1).coordinate);
// validate the coordinate array for envelope type
if (coordinates.children.size() != 2) {
throw new ElasticsearchParseException("Invalid number of points (" + coordinates.children.size() + ") provided for " +
"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;
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));
}
return newEnvelope(orientation).topLeft(uL).bottomRight(lR);
}

protected static void validateMultiPointNode(CoordinateNode coordinates) {
Expand Down
Expand Up @@ -121,6 +121,7 @@ public void testParse_circle() throws IOException {

@Test
public void testParse_envelope() throws IOException {
// test #1: envelope with expected coordinate order (TopLeft, BottomRight)
String multilinesGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "envelope")
.startArray("coordinates")
.startArray().value(-50).value(30).endArray()
Expand All @@ -130,6 +131,38 @@ public void testParse_envelope() throws IOException {

Rectangle expected = SPATIAL_CONTEXT.makeRectangle(-50, 50, -30, 30);
assertGeometryEquals(expected, multilinesGeoJson);

// test #2: envelope with agnostic coordinate order (TopRight, BottomLeft)
multilinesGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "envelope")
.startArray("coordinates")
.startArray().value(50).value(30).endArray()
.startArray().value(-50).value(-30).endArray()
.endArray()
.endObject().string();

expected = SPATIAL_CONTEXT.makeRectangle(-50, 50, -30, 30);
assertGeometryEquals(expected, multilinesGeoJson);

// test #3: "envelope" (actually a triangle) with invalid number of coordinates (TopRight, BottomLeft, BottomRight)
multilinesGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "envelope")
.startArray("coordinates")
.startArray().value(50).value(30).endArray()
.startArray().value(-50).value(-30).endArray()
.startArray().value(50).value(-39).endArray()
.endArray()
.endObject().string();
XContentParser parser = JsonXContent.jsonXContent.createParser(multilinesGeoJson);
parser.nextToken();
ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class);

// test #4: "envelope" with empty coordinates
multilinesGeoJson = XContentFactory.jsonBuilder().startObject().field("type", "envelope")
.startArray("coordinates")
.endArray()
.endObject().string();
parser = JsonXContent.jsonXContent.createParser(multilinesGeoJson);
parser.nextToken();
ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class);
}

@Test
Expand Down

0 comments on commit 4679c37

Please sign in to comment.