From 995d3044a466bc9d862700d7949a6dbf93dae42b Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Mon, 26 Feb 2024 14:01:09 +0000 Subject: [PATCH] GeoJSON - allow empty arrays in "coordinates" element for Multi* geometries (ref #4431) --- include/mapnik/json/create_geometry.hpp | 36 +++++++++++++++++++ .../json/geometry_generator_grammar_impl.hpp | 6 ++-- test/unit/datasource/geojson.cpp | 14 +++++--- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/include/mapnik/json/create_geometry.hpp b/include/mapnik/json/create_geometry.hpp index 9df2d063e..707f5afa6 100644 --- a/include/mapnik/json/create_geometry.hpp +++ b/include/mapnik/json/create_geometry.hpp @@ -64,6 +64,10 @@ struct create_linestring { mapnik::geometry::line_string line; std::size_t size = points.size(); + //if (size < 2) + //{ + // throw std::runtime_error("RFC 7946: For type \"LineString\", the \"coordinates\" member is an array of two or more positions."); + //} line.reserve(size); for (auto&& pt : points) { @@ -108,6 +112,12 @@ struct create_polygon mapnik::geometry::correct(geom_); } + void operator()(ring const& points) const + { + //POLYGON EMPTY + geom_ = std::move(mapnik::geometry::polygon{}); + } + template void operator()(T const&) const { @@ -170,6 +180,12 @@ struct create_multilinestring geom_ = std::move(multi_line); } + void operator()(ring const& points) const + { + //MULTILINESTRING EMPTY + geom_ = std::move(mapnik::geometry::multi_line_string{}); + } + template void operator()(T const&) const { @@ -213,6 +229,26 @@ struct create_multipolygon mapnik::geometry::correct(geom_); } + void operator()(rings const& rngs) const + { + //MULTIPOLYGON + mapnik::geometry::multi_polygon multi_poly; + mapnik::geometry::polygon poly; + std::size_t num_rings = rngs.size(); + for (std::size_t i = 0; i < num_rings; ++i) + { + // POLYGON EMPTY + multi_poly.emplace_back(mapnik::geometry::polygon{}); + } + geom_ = std::move(multi_poly); + } + + void operator()(ring const& points) const + { + //MULTIPOLYGON EMPTY + geom_ = std::move(mapnik::geometry::multi_polygon{}); + } + template void operator()(T const&) const { diff --git a/include/mapnik/json/geometry_generator_grammar_impl.hpp b/include/mapnik/json/geometry_generator_grammar_impl.hpp index 5f003c2f1..2940f6ee9 100644 --- a/include/mapnik/json/geometry_generator_grammar_impl.hpp +++ b/include/mapnik/json/geometry_generator_grammar_impl.hpp @@ -83,16 +83,16 @@ geometry_generator_grammar::geometry_generator_grammar linear_ring_coord = lit('[') << -(point_coord % lit(',')) << lit(']')//linestring_coord.alias() ; - polygon_coord = lit('[') << linear_ring_coord % lit(',') << lit(']') + polygon_coord = lit('[') << -(linear_ring_coord % lit(',')) << lit(']') ; multi_point_coord = lit('[') << -(point_coord % lit(',')) << lit(']');//linestring_coord.alias() ; - multi_linestring_coord = lit('[') << linestring_coord % lit(',') << lit(']') + multi_linestring_coord = lit('[') << -(linestring_coord % lit(',')) << lit(']') ; - multi_polygon_coord = lit('[') << polygon_coord % lit(',') << lit("]") + multi_polygon_coord = lit('[') << -(polygon_coord % lit(',')) << lit("]") ; geometries = geometry % lit(',') diff --git a/test/unit/datasource/geojson.cpp b/test/unit/datasource/geojson.cpp index 308e51cff..afd8d84c6 100644 --- a/test/unit/datasource/geojson.cpp +++ b/test/unit/datasource/geojson.cpp @@ -125,11 +125,15 @@ TEST_CASE("geojson") SECTION("GeoJSON empty Geometries handling") { auto valid_empty_geometries = {"null", // Point can't be empty - "{ \"type\": \"LineString\", \"coordinates\": [] }", - "{ \"type\": \"Polygon\", \"coordinates\": [ [ ] ] } ", - "{ \"type\": \"MultiPoint\", \"coordinates\": [ ] }", - "{ \"type\": \"MultiLineString\", \"coordinates\": [ [] ] }", - "{ \"type\": \"MultiPolygon\", \"coordinates\": [[ []] ] }"}; + "{ \"type\": \"LineString\", \"coordinates\":[]}", + "{ \"type\": \"Polygon\", \"coordinates\":[]} ", + "{ \"type\": \"Polygon\", \"coordinates\":[[]]} ", + "{ \"type\": \"MultiPoint\", \"coordinates\":[]}", + "{ \"type\": \"MultiLineString\", \"coordinates\":[]}", + "{ \"type\": \"MultiLineString\", \"coordinates\":[[]]}", + "{ \"type\": \"MultiPolygon\", \"coordinates\":[]}", + "{ \"type\": \"MultiPolygon\", \"coordinates\":[[]]}", + "{ \"type\": \"MultiPolygon\", \"coordinates\": [[[]]] }"}; for (auto const& in : valid_empty_geometries) {