diff --git a/x-pack/plugin/sql/qa/src/main/resources/ogc/ogc.sql-spec b/x-pack/plugin/sql/qa/src/main/resources/ogc/ogc.sql-spec index 0f29a3565826d..3976c5a8b181e 100644 --- a/x-pack/plugin/sql/qa/src/main/resources/ogc/ogc.sql-spec +++ b/x-pack/plugin/sql/qa/src/main/resources/ogc/ogc.sql-spec @@ -61,28 +61,25 @@ SELECT fid, UCASE(ST_GeometryType(boundary)) type FROM named_places ORDER BY fid selectMapNeatLinesProps SELECT fid, UCASE(ST_GeometryType(neatline)) type FROM map_neatlines ORDER BY fid; -// AwaitsFix https://github.com/elastic/elasticsearch/issues/40908 -// selectLakesXY -// SELECT fid, ST_X(shore) x, ST_Y(shore) y FROM lakes ORDER BY fid; +selectLakesXY +SELECT fid, ST_X(shore) x, ST_Y(shore) y FROM lakes ORDER BY fid; selectRoadSegmentsXY SELECT fid, ST_X(centerline) x, ST_Y(centerline) y FROM road_segments ORDER BY fid; selectDividedRoutesXY SELECT fid, ST_X(centerlines) x, ST_Y(centerlines) y FROM divided_routes ORDER BY fid; -// AwaitsFix https://github.com/elastic/elasticsearch/issues/40908 -// selectForestsXY -// SELECT fid, ST_X(boundary) x, ST_Y(boundary) y FROM forests ORDER BY fid; +selectForestsXY +SELECT fid, ST_X(boundary) x, ST_Y(boundary) y FROM forests ORDER BY fid; selectBridgesPositionsXY SELECT fid, ST_X(position) x, ST_Y(position) y FROM bridges ORDER BY fid; selectStreamsXY SELECT fid, ST_X(centerline) x, ST_Y(centerline) y FROM streams ORDER BY fid; selectBuildingsXY SELECT fid, ST_X(position) x, ST_Y(position) y FROM buildings ORDER BY fid; -// AwaitsFix https://github.com/elastic/elasticsearch/issues/40908 -// selectBuildingsFootprintsXY -// SELECT fid, ST_X(footprint) x, ST_Y(footprint) y FROM buildings ORDER BY fid; -// selectPondsXY -// SELECT fid, ST_X(shores) x, ST_Y(shores) y FROM ponds ORDER BY fid; -// selectNamedPlacesXY -// SELECT fid, ST_X(boundary) x, ST_Y(boundary) y FROM named_places ORDER BY fid; -// selectMapNeatLinesXY -// SELECT fid, ST_X(neatline) x, ST_Y(neatline) y FROM map_neatlines ORDER BY fid; +selectBuildingsFootprintsXY +SELECT fid, ST_X(footprint) x, ST_Y(footprint) y FROM buildings ORDER BY fid; +selectPondsXY +SELECT fid, ST_X(shores) x, ST_Y(shores) y FROM ponds ORDER BY fid; +selectNamedPlacesXY +SELECT fid, ST_X(boundary) x, ST_Y(boundary) y FROM named_places ORDER BY fid; +selectMapNeatLinesXY +SELECT fid, ST_X(neatline) x, ST_Y(neatline) y FROM map_neatlines ORDER BY fid; diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/GeoShape.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/GeoShape.java index 1f4ef78aafcf3..1738667a797a3 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/GeoShape.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/GeoShape.java @@ -5,15 +5,19 @@ */ package org.elasticsearch.xpack.sql.expression.function.scalar.geo; +import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.geo.GeoUtils; -import org.elasticsearch.common.geo.builders.PointBuilder; -import org.elasticsearch.common.geo.builders.ShapeBuilder; -import org.elasticsearch.common.geo.parsers.ShapeParser; +import org.elasticsearch.common.geo.GeometryParser; import org.elasticsearch.common.io.stream.NamedWriteable; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; +import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.ToXContentFragment; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.geo.geometry.Circle; import org.elasticsearch.geo.geometry.Geometry; import org.elasticsearch.geo.geometry.GeometryCollection; @@ -26,9 +30,12 @@ import org.elasticsearch.geo.geometry.Point; import org.elasticsearch.geo.geometry.Polygon; import org.elasticsearch.geo.geometry.Rectangle; +import org.elasticsearch.geo.utils.WellKnownText; import org.elasticsearch.xpack.sql.SqlIllegalArgumentException; import java.io.IOException; +import java.io.InputStream; +import java.text.ParseException; import java.util.Objects; /** @@ -41,41 +48,49 @@ public class GeoShape implements ToXContentFragment, NamedWriteable { public static final String NAME = "geo"; - private final ShapeBuilder shapeBuilder; + private final Geometry shape; public GeoShape(double lon, double lat) { - shapeBuilder = new PointBuilder(lon, lat); + shape = new Point(lat, lon); } public GeoShape(Object value) throws IOException { - shapeBuilder = ShapeParser.parse(value); + try { + shape = parse(value); + } catch (ParseException ex) { + throw new ElasticsearchParseException("cannot load shape", ex); + } } public GeoShape(StreamInput in) throws IOException { - shapeBuilder = ShapeParser.parse(in.readString()); + try { + shape = parse(in.readString()); + } catch (ParseException ex) { + throw new ElasticsearchParseException("cannot load shape", ex); + } } @Override public void writeTo(StreamOutput out) throws IOException { - out.writeString(shapeBuilder.toWKT()); + out.writeString(WellKnownText.toWKT(shape)); } @Override public String toString() { - return shapeBuilder.toWKT(); + return WellKnownText.toWKT(shape); } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return builder.value(shapeBuilder.toWKT()); + return builder.value(WellKnownText.toWKT(shape)); } public Geometry toGeometry() { - return shapeBuilder.buildGeometry(); + return shape; } public Point firstPoint() { - return shapeBuilder.buildGeometry().visit(new GeometryVisitor() { + return shape.visit(new GeometryVisitor() { @Override public Point visit(Circle circle) { return new Point(circle.getLat(), circle.getLon(), circle.hasAlt() ? circle.getAlt() : Double.NaN); @@ -149,16 +164,16 @@ public String getGeometryType() { } public static double distance(GeoShape shape1, GeoShape shape2) { - if (shape1.shapeBuilder instanceof PointBuilder == false) { + if (shape1.shape instanceof Point == false) { throw new SqlIllegalArgumentException("distance calculation is only supported for points; received [{}]", shape1); } - if (shape2.shapeBuilder instanceof PointBuilder == false) { + if (shape2.shape instanceof Point == false) { throw new SqlIllegalArgumentException("distance calculation is only supported for points; received [{}]", shape2); } - double srcLat = ((PointBuilder) shape1.shapeBuilder).latitude(); - double srcLon = ((PointBuilder) shape1.shapeBuilder).longitude(); - double dstLat = ((PointBuilder) shape2.shapeBuilder).latitude(); - double dstLon = ((PointBuilder) shape2.shapeBuilder).longitude(); + double srcLat = ((Point) shape1.shape).getLat(); + double srcLon = ((Point) shape1.shape).getLon(); + double dstLat = ((Point) shape2.shape).getLat(); + double dstLon = ((Point) shape2.shape).getLon(); return GeoUtils.arcDistance(srcLat, srcLon, dstLat, dstLon); } @@ -171,12 +186,12 @@ public boolean equals(Object o) { return false; } GeoShape geoShape = (GeoShape) o; - return shapeBuilder.equals(geoShape.shapeBuilder); + return shape.equals(geoShape.shape); } @Override public int hashCode() { - return Objects.hash(shapeBuilder); + return Objects.hash(shape); } @Override @@ -184,4 +199,19 @@ public String getWriteableName() { return NAME; } + private static Geometry parse(Object value) throws IOException, ParseException { + XContentBuilder content = JsonXContent.contentBuilder(); + content.startObject(); + content.field("value", value); + content.endObject(); + + try (InputStream stream = BytesReference.bytes(content).streamInput(); + XContentParser parser = JsonXContent.jsonXContent.createParser( + NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, stream)) { + parser.nextToken(); // start object + parser.nextToken(); // field name + parser.nextToken(); // field value + return GeometryParser.parse(parser, true, true, true); + } + } } diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/GeoProcessorTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/GeoProcessorTests.java index 37a5cb7d461f2..85953329c9a02 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/GeoProcessorTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/GeoProcessorTests.java @@ -77,9 +77,6 @@ public void testApplyGetXY() throws Exception { new GeoShape("geometrycollection (point (20.0 10.0),point (1.0 2.0))"))); } - // That doesn't work correctly at the moment because shape builder changes the order or points in polygons, so the second point - // sometimes becomes the first - @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/40908") public void testApplyGetXYToPolygons() throws Exception { assertEquals(3.0, new GeoProcessor(GeoOperation.X).process(new GeoShape("polygon ((3.0 1.0, 4.0 2.0, 4.0 3.0, 3.0 1.0))"))); assertEquals(1.0, new GeoProcessor(GeoOperation.Y).process(new GeoShape("polygon ((3.0 1.0, 4.0 2.0, 4.0 3.0, 3.0 1.0))")));