[GEO] GIS envelope validation
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
This commit is contained in:
parent
31652a8b3d
commit
0e24f34b0c
|
@ -787,8 +787,20 @@ public abstract class ShapeBuilder implements ToXContent {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -121,6 +121,7 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
|
|||
|
||||
@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()
|
||||
|
@ -130,6 +131,38 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase {
|
|||
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue