Polylabel: cover the case of empty polygon or exterior ring

This commit is contained in:
Jiri Drbalek 2018-01-17 13:36:28 +00:00
parent a97eace434
commit 99038229f7
5 changed files with 73 additions and 9 deletions

View file

@ -23,16 +23,20 @@
#ifndef MAPNIK_GEOMETRY_POLYLABEL_HPP
#define MAPNIK_GEOMETRY_POLYLABEL_HPP
#include <mapnik/config.hpp> // for MAPNIK_DECL
#include <mapnik/geometry/polygon.hpp>
#include <mapnik/geometry/point.hpp>
namespace mapnik { namespace geometry {
template <class T>
point<T> polylabel(polygon<T> const& polygon, T precision);
MAPNIK_DECL bool polylabel(polygon<T> const& polygon,
T precision,
point<T> & pt);
template <class T>
T polylabel_precision(polygon<T> const& polygon, double scale_factor);
MAPNIK_DECL T polylabel_precision(polygon<T> const& polygon,
double scale_factor);
} }

View file

@ -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<double> placement = geometry::polylabel(vertex_processor.polygon_, precision);
geometry::point<double> placement;
if (!geometry::polylabel(vertex_processor.polygon_, precision, placement))
{
this->done_ = true;
return false;
}
x = placement.x;
y = placement.y;

View file

@ -34,16 +34,25 @@ T polylabel_precision(polygon<T> const& polygon, double scale_factor)
}
template <class T>
point<T> polylabel(polygon<T> const& polygon, T precision)
bool polylabel(polygon<T> const& polygon, T precision, point<T> & pt)
{
return mapbox::polylabel(polygon, precision);
if (polygon.empty() || polygon.front().empty())
{
return false;
}
pt = mapbox::polylabel(polygon, precision);
return true;
}
template
point<double> polylabel(polygon<double> const& polygon, double precision);
bool polylabel(polygon<double> const& polygon,
double precision,
point<double> & pt);
template
double polylabel_precision(polygon<double> const& polygon, double scale_factor);
double polylabel_precision(polygon<double> const& polygon,
double scale_factor);
} }

View file

@ -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<double> pt = geometry::polylabel(tranformed_poly, precision);
points_.emplace_back(pt.x, pt.y);
geometry::point<double> pt;
if (geometry::polylabel(tranformed_poly, precision, pt))
{
points_.emplace_back(pt.x, pt.y);
}
}
continue;
}

View file

@ -0,0 +1,43 @@
#include "catch.hpp"
#include <mapnik/geometry/polylabel.hpp>
TEST_CASE("polylabel") {
SECTION("empty polygon") {
mapnik::geometry::polygon<double> poly;
mapnik::geometry::point<double> pt;
CHECK(!mapnik::geometry::polylabel(poly, 1.0, pt));
}
SECTION("empty exterior ring") {
mapnik::geometry::polygon<double> poly;
poly.emplace_back();
mapnik::geometry::point<double> pt;
CHECK(!mapnik::geometry::polylabel(poly, 1.0, pt));
}
SECTION("polylabel with a square") {
mapnik::geometry::polygon<double> 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<double> pt{ -3, -3 };
CHECK(mapnik::geometry::polylabel(poly, 1.0, pt));
CHECK(pt.x == Approx(0));
CHECK(pt.y == Approx(0));
}
}