diff --git a/server/src/main/java/org/elasticsearch/common/geo/GeometryIO.java b/server/src/main/java/org/elasticsearch/common/geo/GeometryIO.java index cfe225641d4b9..9b666bfa876da 100644 --- a/server/src/main/java/org/elasticsearch/common/geo/GeometryIO.java +++ b/server/src/main/java/org/elasticsearch/common/geo/GeometryIO.java @@ -21,6 +21,7 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.geometry.Circle; import org.elasticsearch.geometry.Geometry; import org.elasticsearch.geometry.GeometryCollection; @@ -49,7 +50,10 @@ public static void writeGeometry(StreamOutput out, Geometry geometry) throws IOE geometry.visit(new GeometryVisitor() { @Override public Void visit(Circle circle) throws IOException { - throw new UnsupportedOperationException("circle is not supported"); + writeCoordinate(circle.getLat(), circle.getLon(), circle.getAlt()); + out.writeDouble(circle.getRadiusMeters()); + DistanceUnit.METERS.writeTo(out); + return null; } @Override @@ -161,6 +165,8 @@ public static Geometry readGeometry(StreamInput in) throws IOException { return readMultiPolygon(in); case "envelope": return readRectangle(in); + case "circle": + return readCircle(in); default: throw new UnsupportedOperationException("unsupported shape type " + type); } @@ -304,4 +310,13 @@ private static double readAlt(StreamInput in) throws IOException { return alt; } } + + private static Circle readCircle(StreamInput in) throws IOException { + double lon = in.readDouble(); + double lat = in.readDouble(); + double alt = readAlt(in); + double radius = in.readDouble(); + DistanceUnit distanceUnit = DistanceUnit.readFromStream(in); + return new Circle(lon, lat, alt, distanceUnit.toMeters(radius)); + } } diff --git a/server/src/main/java/org/elasticsearch/common/geo/builders/CircleBuilder.java b/server/src/main/java/org/elasticsearch/common/geo/builders/CircleBuilder.java index 2b4c13f5c6dea..b3ac8e5dc06b3 100644 --- a/server/src/main/java/org/elasticsearch/common/geo/builders/CircleBuilder.java +++ b/server/src/main/java/org/elasticsearch/common/geo/builders/CircleBuilder.java @@ -165,7 +165,7 @@ public Circle buildS4J() { @Override public org.elasticsearch.geometry.Circle buildGeometry() { - throw new UnsupportedOperationException("CIRCLE geometry is not supported"); + return new org.elasticsearch.geometry.Circle(center.x, center.y, unit.toMeters(radius)); } @Override diff --git a/server/src/main/java/org/elasticsearch/index/query/LegacyGeoShapeQueryProcessor.java b/server/src/main/java/org/elasticsearch/index/query/LegacyGeoShapeQueryProcessor.java index edef83950f97d..14307d846b67e 100644 --- a/server/src/main/java/org/elasticsearch/index/query/LegacyGeoShapeQueryProcessor.java +++ b/server/src/main/java/org/elasticsearch/index/query/LegacyGeoShapeQueryProcessor.java @@ -28,6 +28,7 @@ import org.apache.lucene.spatial.query.SpatialOperation; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.geo.SpatialStrategy; +import org.elasticsearch.common.geo.builders.CircleBuilder; import org.elasticsearch.common.geo.builders.EnvelopeBuilder; import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder; import org.elasticsearch.common.geo.builders.LineStringBuilder; @@ -37,6 +38,7 @@ import org.elasticsearch.common.geo.builders.PointBuilder; import org.elasticsearch.common.geo.builders.PolygonBuilder; import org.elasticsearch.common.geo.builders.ShapeBuilder; +import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.geometry.Circle; import org.elasticsearch.geometry.Geometry; import org.elasticsearch.geometry.GeometryCollection; @@ -123,7 +125,7 @@ private static Shape buildS4J(Geometry geometry) { ShapeBuilder shapeBuilder = geometry.visit(new GeometryVisitor<>() { @Override public ShapeBuilder visit(Circle circle) { - throw new UnsupportedOperationException("circle is not supported"); + return new CircleBuilder().center(circle.getLon(), circle.getLat()).radius(circle.getRadiusMeters(), DistanceUnit.METERS); } @Override diff --git a/server/src/test/java/org/elasticsearch/common/geo/GeometryIOTests.java b/server/src/test/java/org/elasticsearch/common/geo/GeometryIOTests.java index e78938290de1b..4d3bf05163603 100644 --- a/server/src/test/java/org/elasticsearch/common/geo/GeometryIOTests.java +++ b/server/src/test/java/org/elasticsearch/common/geo/GeometryIOTests.java @@ -88,10 +88,6 @@ private boolean shapeSupported(Geometry geometry) { return false; } - if (geometry.type() == ShapeType.CIRCLE) { - return false; - } - if (geometry.type() == ShapeType.GEOMETRYCOLLECTION) { GeometryCollection collection = (GeometryCollection) geometry; for (Geometry g : collection) { diff --git a/server/src/test/java/org/elasticsearch/search/geo/LegacyGeoShapeIntegrationIT.java b/server/src/test/java/org/elasticsearch/search/geo/LegacyGeoShapeIntegrationIT.java index 5688e38e74d28..1a919015bb401 100644 --- a/server/src/test/java/org/elasticsearch/search/geo/LegacyGeoShapeIntegrationIT.java +++ b/server/src/test/java/org/elasticsearch/search/geo/LegacyGeoShapeIntegrationIT.java @@ -23,8 +23,10 @@ import org.elasticsearch.cluster.routing.IndexShardRoutingTable; import org.elasticsearch.common.Strings; import org.elasticsearch.common.geo.builders.ShapeBuilder; +import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.geometry.Circle; import org.elasticsearch.index.IndexService; import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper; import org.elasticsearch.index.mapper.MappedFieldType; @@ -161,6 +163,29 @@ public void testIndexShapeRouting() throws Exception { assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L)); } + /** + * Test that the circle is still supported for the legacy shapes + */ + public void testLegacyCircle() throws Exception { + // create index + assertAcked(client().admin().indices().prepareCreate("test") + .addMapping("geometry", "shape", "type=geo_shape,strategy=recursive,tree=geohash").get()); + ensureGreen(); + + indexRandom(true, client().prepareIndex("test").setId("0").setSource("shape", (ToXContent) (builder, params) -> { + builder.startObject().field("type", "circle") + .startArray("coordinates").value(30).value(50).endArray() + .field("radius","77km") + .endObject(); + return builder; + })); + + // test self crossing of circles + SearchResponse searchResponse = client().prepareSearch("test").setQuery(geoShapeQuery("shape", + new Circle(30, 50, 77000))).get(); + assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L)); + } + private String findNodeName(String index) { ClusterState state = client().admin().cluster().prepareState().get().getState(); IndexShardRoutingTable shard = state.getRoutingTable().index(index).shard(0);