diff --git a/include/mapnik/geometry/polylabel.hpp b/include/mapnik/geometry/polylabel.hpp index 3eb4b9ad2..dedebf577 100644 --- a/include/mapnik/geometry/polylabel.hpp +++ b/include/mapnik/geometry/polylabel.hpp @@ -23,16 +23,20 @@ #ifndef MAPNIK_GEOMETRY_POLYLABEL_HPP #define MAPNIK_GEOMETRY_POLYLABEL_HPP +#include // for MAPNIK_DECL #include #include namespace mapnik { namespace geometry { template -point polylabel(polygon const& polygon, T precision); +MAPNIK_DECL bool polylabel(polygon const& polygon, + T precision, + point & pt); template -T polylabel_precision(polygon const& polygon, double scale_factor); +MAPNIK_DECL T polylabel_precision(polygon const& polygon, + double scale_factor); } } diff --git a/include/mapnik/markers_placements/polylabel.hpp b/include/mapnik/markers_placements/polylabel.hpp index ac07a8cfe..1fbc16045 100644 --- a/include/mapnik/markers_placements/polylabel.hpp +++ b/include/mapnik/markers_placements/polylabel.hpp @@ -56,7 +56,12 @@ public: vertex_processor.add_path(this->locator_); double precision = geometry::polylabel_precision(vertex_processor.polygon_, this->params_.scale_factor); - geometry::point placement = geometry::polylabel(vertex_processor.polygon_, precision); + geometry::point placement; + if (!geometry::polylabel(vertex_processor.polygon_, precision, placement)) + { + this->done_ = true; + return false; + } x = placement.x; y = placement.y; diff --git a/src/geometry/polylabel.cpp b/src/geometry/polylabel.cpp index 1ace5949c..740eccbfe 100644 --- a/src/geometry/polylabel.cpp +++ b/src/geometry/polylabel.cpp @@ -34,16 +34,25 @@ T polylabel_precision(polygon const& polygon, double scale_factor) } template -point polylabel(polygon const& polygon, T precision) +bool polylabel(polygon const& polygon, T precision, point & pt) { - return mapbox::polylabel(polygon, precision); + if (polygon.empty() || polygon.front().empty()) + { + return false; + } + + pt = mapbox::polylabel(polygon, precision); + return true; } template -point polylabel(polygon const& polygon, double precision); +bool polylabel(polygon const& polygon, + double precision, + point & pt); template -double polylabel_precision(polygon const& polygon, double scale_factor); +double polylabel_precision(polygon const& polygon, + double scale_factor); } } diff --git a/src/text/symbolizer_helpers.cpp b/src/text/symbolizer_helpers.cpp index 493e9fe73..1d0f6e9e9 100644 --- a/src/text/symbolizer_helpers.cpp +++ b/src/text/symbolizer_helpers.cpp @@ -312,8 +312,11 @@ void base_symbolizer_helper::initialize_points() const else if (how_placed == POLYLABEL_PLACEMENT) { double precision = geometry::polylabel_precision(tranformed_poly, scale_factor_); - geometry::point pt = geometry::polylabel(tranformed_poly, precision); - points_.emplace_back(pt.x, pt.y); + geometry::point pt; + if (geometry::polylabel(tranformed_poly, precision, pt)) + { + points_.emplace_back(pt.x, pt.y); + } } continue; } diff --git a/test/unit/geometry/polylabel.cpp b/test/unit/geometry/polylabel.cpp new file mode 100644 index 000000000..094332e95 --- /dev/null +++ b/test/unit/geometry/polylabel.cpp @@ -0,0 +1,43 @@ +#include "catch.hpp" + +#include + +TEST_CASE("polylabel") { + +SECTION("empty polygon") { + + mapnik::geometry::polygon poly; + mapnik::geometry::point pt; + + CHECK(!mapnik::geometry::polylabel(poly, 1.0, pt)); +} + +SECTION("empty exterior ring") { + + mapnik::geometry::polygon poly; + poly.emplace_back(); + + mapnik::geometry::point pt; + + CHECK(!mapnik::geometry::polylabel(poly, 1.0, pt)); +} + +SECTION("polylabel with a square") { + + mapnik::geometry::polygon poly; + poly.emplace_back(); + auto & exterior_ring = poly.front(); + exterior_ring.emplace_back(-1, -1); + exterior_ring.emplace_back( 1, -1); + exterior_ring.emplace_back( 1, 1); + exterior_ring.emplace_back(-1, 1); + exterior_ring.emplace_back(-1, -1); + + mapnik::geometry::point pt{ -3, -3 }; + + CHECK(mapnik::geometry::polylabel(poly, 1.0, pt)); + CHECK(pt.x == Approx(0)); + CHECK(pt.y == Approx(0)); +} + +}