diff --git a/include/mapnik/geometry/interior.hpp b/include/mapnik/geometry/interior.hpp index 50378d163..d4318dcef 100644 --- a/include/mapnik/geometry/interior.hpp +++ b/include/mapnik/geometry/interior.hpp @@ -24,11 +24,14 @@ #define MAPNIK_GEOMETRY_INTERIOR_HPP #include +#include // for MAPNIK_DECL namespace mapnik { namespace geometry { template -point interior(polygon const& polygon, double scale_factor); +MAPNIK_DECL bool interior(polygon const& polygon, + double scale_factor, + point & pt); } } diff --git a/include/mapnik/markers_placements/interior.hpp b/include/mapnik/markers_placements/interior.hpp index e0bbd69a1..12b1af494 100644 --- a/include/mapnik/markers_placements/interior.hpp +++ b/include/mapnik/markers_placements/interior.hpp @@ -62,8 +62,14 @@ public: { geometry::polygon_vertex_processor vertex_processor; vertex_processor.add_path(this->locator_); - geometry::point placement = geometry::interior(vertex_processor.polygon_, - this->params_.scale_factor); + geometry::point placement; + if (!geometry::interior(vertex_processor.polygon_, + this->params_.scale_factor, + placement)) + { + this->done_ = true; + return false; + } x = placement.x; y = placement.y; diff --git a/include/mapnik/renderer_common/process_point_symbolizer.hpp b/include/mapnik/renderer_common/process_point_symbolizer.hpp index fda6f8efc..1756135de 100644 --- a/include/mapnik/renderer_common/process_point_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_point_symbolizer.hpp @@ -80,7 +80,7 @@ void render_point_symbolizer(point_symbolizer const &sym, else if (type == mapnik::geometry::geometry_types::Polygon) { auto const& poly = mapnik::util::get >(geometry); - pt = geometry::interior(poly, common.scale_factor_); + if (!geometry::interior(poly, common.scale_factor_, pt)) return; } else { diff --git a/src/geometry/interior.cpp b/src/geometry/interior.cpp index ceab6ae1a..164d4c46e 100644 --- a/src/geometry/interior.cpp +++ b/src/geometry/interior.cpp @@ -30,6 +30,11 @@ #include #include +#pragma GCC diagnostic push +#include +#include +#pragma GCC diagnostic pop + namespace mapnik { namespace geometry { // Interior algorithm is realized as a modification of Polylabel algorithm @@ -148,8 +153,13 @@ struct cell }; template -point polylabel(const polygon& polygon, T precision = 1) +boost::optional> polylabel(polygon const& polygon, T precision = 1) { + if (polygon.exterior_ring.empty()) + { + return boost::none; + } + // find the bounding box of the outer ring const box2d bbox = envelope(polygon.exterior_ring); const point size { bbox.width(), bbox.height() }; @@ -167,14 +177,14 @@ point polylabel(const polygon& polygon, T precision = 1) if (cell_size == 0) { - return { bbox.minx(), bbox.miny() }; + return point{ bbox.minx(), bbox.miny() }; } point centroid; if (!mapnik::geometry::centroid(polygon, centroid)) { auto center = bbox.center(); - return { center.x, center.y }; + return point{ center.x, center.y }; } fitness_functor fitness_func(centroid, size); @@ -220,15 +230,21 @@ point polylabel(const polygon& polygon, T precision = 1) } // namespace detail template -point interior(polygon const& polygon, double scale_factor) +bool interior(polygon const& polygon, double scale_factor, point & pt) { // This precision has been chosen to work well in the map (viewport) coordinates. double precision = 10.0 * scale_factor; - return detail::polylabel(polygon, precision); + if (boost::optional> opt = detail::polylabel(polygon, precision)) + { + pt = *opt; + return true; + } + + return false; } template -point interior(polygon const& polygon, double scale_factor); +bool interior(polygon const& polygon, double scale_factor, point & pt); } } diff --git a/src/text/symbolizer_helpers.cpp b/src/text/symbolizer_helpers.cpp index f77707547..4bac8a4fe 100644 --- a/src/text/symbolizer_helpers.cpp +++ b/src/text/symbolizer_helpers.cpp @@ -300,8 +300,11 @@ void base_symbolizer_helper::initialize_points() const using transform_group_type = geometry::strategy_group; transform_group_type transform_group(ps, vs); geometry::polygon tranformed_poly(geometry::transform(poly, transform_group)); - geometry::point pt = geometry::interior(tranformed_poly, scale_factor_); - points_.emplace_back(pt.x, pt.y); + geometry::point pt; + if (geometry::interior(tranformed_poly, scale_factor_, pt)) + { + points_.emplace_back(pt.x, pt.y); + } continue; } else diff --git a/test/unit/geometry/interior.cpp b/test/unit/geometry/interior.cpp new file mode 100644 index 000000000..646bb0d3d --- /dev/null +++ b/test/unit/geometry/interior.cpp @@ -0,0 +1,31 @@ +#include "catch.hpp" + +#include + +TEST_CASE("polygon interior") { + +SECTION("empty polygon") { + + mapnik::geometry::polygon poly; + mapnik::geometry::point pt; + + CHECK(!mapnik::geometry::interior(poly, 1.0, pt)); +} + +SECTION("interior of a square") { + + mapnik::geometry::polygon poly; + poly.exterior_ring.emplace_back(-1, -1); + poly.exterior_ring.emplace_back( 1, -1); + poly.exterior_ring.emplace_back( 1, 1); + poly.exterior_ring.emplace_back(-1, 1); + poly.exterior_ring.emplace_back(-1, -1); + + mapnik::geometry::point pt{ -3, -3 }; + + CHECK(mapnik::geometry::interior(poly, 1.0, pt)); + CHECK(pt.x == Approx(0)); + CHECK(pt.y == Approx(0)); +} + +}