diff --git a/include/mapnik/box2d.hpp b/include/mapnik/box2d.hpp index b90644f91..f9f59ba28 100644 --- a/include/mapnik/box2d.hpp +++ b/include/mapnik/box2d.hpp @@ -116,6 +116,7 @@ public: bool valid() const; void move(T x, T y); std::string to_string() const; + T area() const; // define some operators box2d_type& operator+=(box2d_type const& other); diff --git a/include/mapnik/box2d_impl.hpp b/include/mapnik/box2d_impl.hpp index b1c462d16..232a25d58 100644 --- a/include/mapnik/box2d_impl.hpp +++ b/include/mapnik/box2d_impl.hpp @@ -407,6 +407,11 @@ std::string box2d::to_string() const return s.str(); } +template +T box2d::area() const +{ + return width() * height(); +} template box2d& box2d::operator+=(box2d const& other) diff --git a/src/text/symbolizer_helpers.cpp b/src/text/symbolizer_helpers.cpp index caa29da0f..b8857f933 100644 --- a/src/text/symbolizer_helpers.cpp +++ b/src/text/symbolizer_helpers.cpp @@ -187,23 +187,26 @@ base_symbolizer_helper::base_symbolizer_helper( initialize_points(); } -struct largest_bbox_first +template +static It largest_bbox(It begin, It end) { - bool operator() (geometry::geometry const* g0, geometry::geometry const* g1) const + if (begin == end) { - box2d b0 = geometry::envelope(*g0); - box2d b1 = geometry::envelope(*g1); - return b0.width() * b0.height() > b1.width() * b1.height(); + return end; } - bool operator() (base_symbolizer_helper::geometry_cref const& g0, - base_symbolizer_helper::geometry_cref const& g1) const + It largest_geom = begin; + double largest_bbox = geometry::envelope(*largest_geom).area(); + for (++begin; begin != end; ++begin) { - // TODO - this has got to be expensive! Can we cache bbox's if there are repeated calls to same geom? - box2d b0 = geometry::envelope(g0); - box2d b1 = geometry::envelope(g1); - return b0.width() * b0.height() > b1.width() * b1.height(); + double bbox = geometry::envelope(*begin).area(); + if (bbox > largest_bbox) + { + largest_bbox = bbox; + largest_geom = begin; + } } -}; + return largest_geom; +} void base_symbolizer_helper::initialize_geometries() const { @@ -216,10 +219,16 @@ void base_symbolizer_helper::initialize_geometries() const type == geometry::geometry_types::MultiPolygon) { bool largest_box_only = text_props_->largest_bbox_only; - if (largest_box_only) + if (largest_box_only && geometries_to_process_.size() > 1) { - geometries_to_process_.sort(largest_bbox_first()); + auto largest_geom = largest_bbox( + geometries_to_process_.begin(), + geometries_to_process_.end()); geo_itr_ = geometries_to_process_.begin(); + if (geo_itr_ != largest_geom) + { + std::swap(*geo_itr_, *largest_geom); + } geometries_to_process_.erase(++geo_itr_, geometries_to_process_.end()); } }