diff --git a/src/HotChocolate/Spatial/src/Types/GeoJsonMultiPolygonType.cs b/src/HotChocolate/Spatial/src/Types/GeoJsonMultiPolygonType.cs index c3efd264643..09e53abaf75 100644 --- a/src/HotChocolate/Spatial/src/Types/GeoJsonMultiPolygonType.cs +++ b/src/HotChocolate/Spatial/src/Types/GeoJsonMultiPolygonType.cs @@ -17,7 +17,7 @@ protected override void Configure(IObjectTypeDescriptor descriptor .BindFieldsExplicitly(); descriptor - .Field(x => x.GetGeometryCollectionCoordinates(null!)) + .Field(x => x.GetMultiPolygonCoordinates(null!)) .Name(CoordinatesFieldName) .Description(GeoJson_Field_Coordinates_Description_MultiPolygon) .Type(); diff --git a/src/HotChocolate/Spatial/src/Types/GeoJsonResolvers.cs b/src/HotChocolate/Spatial/src/Types/GeoJsonResolvers.cs index cb33196ede8..2c324843e43 100644 --- a/src/HotChocolate/Spatial/src/Types/GeoJsonResolvers.cs +++ b/src/HotChocolate/Spatial/src/Types/GeoJsonResolvers.cs @@ -17,6 +17,18 @@ public Coordinate[][] GetGeometryCollectionCoordinates( return coordinates; } + public Coordinate[][][] GetMultiPolygonCoordinates([Parent] MultiPolygon multiPolygon) + { + var coordinates = new Coordinate[multiPolygon.NumGeometries][][]; + + for (var i = 0; i < multiPolygon.NumGeometries; i++) + { + coordinates[i] = GetPolygonRings((Polygon)multiPolygon.GetGeometryN(i)); + } + + return coordinates; + } + public GeoJsonGeometryType GetType([Parent] Geometry geometry) => geometry.OgcGeometryType switch { @@ -39,4 +51,17 @@ public IReadOnlyCollection GetBbox([Parent] Geometry geometry) public int GetCrs([Parent] Geometry geometry) => geometry.SRID is 0 or -1 ? 4326 : geometry.SRID; + + private static Coordinate[][] GetPolygonRings(Polygon polygon) + { + var rings = new Coordinate[polygon.NumInteriorRings + 1][]; + rings[0] = polygon.ExteriorRing.Coordinates; + + for (var i = 0; i < polygon.NumInteriorRings; i++) + { + rings[i + 1] = polygon.GetInteriorRingN(i).Coordinates; + } + + return rings; + } } diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPolygonTypeTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPolygonTypeTests.cs index 3fc91a675c8..86c2bf5bce3 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPolygonTypeTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPolygonTypeTests.cs @@ -25,6 +25,64 @@ public class GeoJsonMultiPolygonTypeTests ])) ]); + [Fact] + public async Task GetMultiPolygonCoordinates_Should_ReturnRingsPerPolygon_When_PolygonHasHoles() + { + // arrange + var multiPolygon = new MultiPolygon( + [ + new Polygon( + new LinearRing( + [ + new Coordinate(0, 0), + new Coordinate(40, 0), + new Coordinate(40, 40), + new Coordinate(0, 40), + new Coordinate(0, 0) + ]), + [ + new LinearRing( + [ + new Coordinate(10, 10), + new Coordinate(20, 10), + new Coordinate(20, 20), + new Coordinate(10, 20), + new Coordinate(10, 10) + ]) + ]), + new Polygon( + new LinearRing( + [ + new Coordinate(50, 50), + new Coordinate(60, 50), + new Coordinate(60, 60), + new Coordinate(50, 60), + new Coordinate(50, 50) + ])) + ]); + + var schema = SchemaBuilder.New() + .AddConvention() + .BindRuntimeType() + .AddType() + .AddQueryType( + d => d + .Name("Query") + .Field("test") + .Resolve(multiPolygon)) + .Create(); + + var executor = schema.MakeExecutable(); + + // act + var result = await executor.ExecuteAsync( + "{ test { type coordinates bbox crs }}", + TestContext.Current.CancellationToken); + + // assert + result.MatchSnapshot(); + } + [Fact] public async Task MultiPolygon_Execution_Output() { diff --git a/src/HotChocolate/Spatial/test/Types.Tests/__snapshots__/GeoJsonMultiPolygonTypeTests.GetMultiPolygonCoordinates_Should_ReturnRingsPerPolygon_When_PolygonHasHoles.snap b/src/HotChocolate/Spatial/test/Types.Tests/__snapshots__/GeoJsonMultiPolygonTypeTests.GetMultiPolygonCoordinates_Should_ReturnRingsPerPolygon_When_PolygonHasHoles.snap new file mode 100644 index 00000000000..08f2c2c10cd --- /dev/null +++ b/src/HotChocolate/Spatial/test/Types.Tests/__snapshots__/GeoJsonMultiPolygonTypeTests.GetMultiPolygonCoordinates_Should_ReturnRingsPerPolygon_When_PolygonHasHoles.snap @@ -0,0 +1,86 @@ +{ + "data": { + "test": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + 0, + 0 + ], + [ + 40, + 0 + ], + [ + 40, + 40 + ], + [ + 0, + 40 + ], + [ + 0, + 0 + ] + ], + [ + [ + 10, + 10 + ], + [ + 20, + 10 + ], + [ + 20, + 20 + ], + [ + 10, + 20 + ], + [ + 10, + 10 + ] + ] + ], + [ + [ + [ + 50, + 50 + ], + [ + 60, + 50 + ], + [ + 60, + 60 + ], + [ + 50, + 60 + ], + [ + 50, + 50 + ] + ] + ] + ], + "bbox": [ + 0, + 0, + 60, + 60 + ], + "crs": 4326 + } + } +} diff --git a/src/HotChocolate/Spatial/test/Types.Tests/__snapshots__/GeoJsonMultiPolygonTypeTests.MultiPolygon_Execution_Output.snap b/src/HotChocolate/Spatial/test/Types.Tests/__snapshots__/GeoJsonMultiPolygonTypeTests.MultiPolygon_Execution_Output.snap index 006f17ac489..00e6b869f85 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/__snapshots__/GeoJsonMultiPolygonTypeTests.MultiPolygon_Execution_Output.snap +++ b/src/HotChocolate/Spatial/test/Types.Tests/__snapshots__/GeoJsonMultiPolygonTypeTests.MultiPolygon_Execution_Output.snap @@ -5,42 +5,46 @@ "coordinates": [ [ [ - 30, - 20 - ], - [ - 45, - 40 - ], - [ - 10, - 40 - ], - [ - 30, - 20 + [ + 30, + 20 + ], + [ + 45, + 40 + ], + [ + 10, + 40 + ], + [ + 30, + 20 + ] ] ], [ [ - 15, - 5 - ], - [ - 40, - 10 - ], - [ - 10, - 20 - ], - [ - 5, - 15 - ], - [ - 15, - 5 + [ + 15, + 5 + ], + [ + 40, + 10 + ], + [ + 10, + 20 + ], + [ + 5, + 15 + ], + [ + 15, + 5 + ] ] ] ],