From 8d9cecd6ad7e3afefb5f4bf7c779bb56ebf41d48 Mon Sep 17 00:00:00 2001 From: artemp Date: Fri, 17 Jul 2015 13:50:22 +0200 Subject: [PATCH] EXPERIMENTAL: use boost r-tree as a spatial container in label_collision_detector --- include/mapnik/label_collision_detector.hpp | 101 +++++++++++------- src/agg/process_debug_symbolizer.cpp | 2 +- src/cairo/process_debug_symbolizer.cpp | 4 +- .../process_group_symbolizer.cpp | 6 +- src/text/placement_finder.cpp | 4 +- 5 files changed, 73 insertions(+), 44 deletions(-) diff --git a/include/mapnik/label_collision_detector.hpp b/include/mapnik/label_collision_detector.hpp index 6dce9ff2c..f92a009c4 100644 --- a/include/mapnik/label_collision_detector.hpp +++ b/include/mapnik/label_collision_detector.hpp @@ -27,13 +27,39 @@ #include #include #include - +#include +// boost +#include +#include // icu #include // stl #include +template +struct detector_linear : boost::geometry::index::linear {}; + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { + +template +struct options_type > +{ + using type = options, + insert_default_tag, + choose_by_content_diff_tag, + split_default_tag, + linear_tag, +#if BOOST_VERSION >= 105700 + node_variant_static_tag>; +#else + node_s_mem_static_tag>; + +#endif +}; + +}}}}} + namespace mapnik { //this needs to be tree structure @@ -139,52 +165,42 @@ public: }; private: - using tree_t = quad_tree< label >; - tree_t tree_; + using box_type = mapnik::box2d; + using item_type = std::pair; + using tree_t = boost::geometry::index::rtree >; + tree_t tree_; + box2d extent_; public: - using query_iterator = tree_t::query_iterator; + using query_iterator = tree_t::const_query_iterator; explicit label_collision_detector4(box2d const& extent) - : tree_(extent) {} + : tree_(), extent_(extent) {} bool has_placement(box2d const& box) { - tree_t::query_iterator itr = tree_.query_in_box(box); - tree_t::query_iterator end = tree_.query_end(); - - for ( ;itr != end; ++itr) - { - if (itr->get().box.intersects(box)) return false; - } - - return true; + auto itr = tree_.qbegin(boost::geometry::index::intersects(box)); + auto end = tree_.qend(); + return (itr != end); } bool has_placement(box2d const& box, double margin) { box2d const& margin_box = (margin > 0 - ? box2d(box.minx() - margin, box.miny() - margin, - box.maxx() + margin, box.maxy() + margin) - : box); + ? box2d(box.minx() - margin, box.miny() - margin, + box.maxx() + margin, box.maxy() + margin) + : box); - tree_t::query_iterator itr = tree_.query_in_box(margin_box); - tree_t::query_iterator end = tree_.query_end(); - - for (;itr != end; ++itr) - { - if (itr->get().box.intersects(margin_box)) - { - return false; - } - } - return true; + auto itr = tree_.qbegin(boost::geometry::index::intersects(margin_box)); + auto end = tree_.qend(); + return (itr != end); } bool has_placement(box2d const& box, double margin, mapnik::value_unicode_string const& text, double repeat_distance) { // Don't bother with any of the repeat checking unless the repeat distance is greater than the margin - if (repeat_distance <= margin) { + if (repeat_distance <= margin) + { return has_placement(box, margin); } @@ -196,12 +212,16 @@ public: box.maxx() + margin, box.maxy() + margin) : box); - tree_t::query_iterator itr = tree_.query_in_box(repeat_box); - tree_t::query_iterator end = tree_.query_end(); + auto itr = tree_.qbegin(boost::geometry::index::intersects(margin_box)); + auto end = tree_.qend(); for ( ;itr != end; ++itr) { - if (itr->get().box.intersects(margin_box) || (text == itr->get().text && itr->get().box.intersects(repeat_box))) + auto const& node = *itr; + auto const& b = std::get<0>(node); + auto const& lab = std::get<1>(node); + + if (b.intersects(margin_box) || (text == lab.text && b.intersects(repeat_box))) { return false; } @@ -212,12 +232,18 @@ public: void insert(box2d const& box) { - tree_.insert(label(box), box); + //if (tree_.extent().intersects(box)) + //{ + tree_.insert(std::make_pair(box, label(box))); + //} } void insert(box2d const& box, mapnik::value_unicode_string const& text) { - tree_.insert(label(box, text), box); + //if (tree_.extent().intersects(box)) + // { + tree_.insert(std::make_pair(box, label(box, text))); + //} } void clear() @@ -227,11 +253,12 @@ public: box2d const& extent() const { - return tree_.extent(); + //auto const& b = tree_.bounds(); + return extent_; } - query_iterator begin() { return tree_.query_in_box(extent()); } - query_iterator end() { return tree_.query_end(); } + query_iterator begin() const { return tree_.qbegin(boost::geometry::index::intersects(extent_)); } + query_iterator end() const { return tree_.qend(); } }; } diff --git a/src/agg/process_debug_symbolizer.cpp b/src/agg/process_debug_symbolizer.cpp index c56add951..10719225b 100644 --- a/src/agg/process_debug_symbolizer.cpp +++ b/src/agg/process_debug_symbolizer.cpp @@ -232,7 +232,7 @@ void agg_renderer::process(debug_symbolizer const& sym, { for (auto const& n : *common_.detector_) { - draw_rect(pixmap_, n.get().box); + draw_rect(pixmap_, std::get<1>(n).box); } } else if (mode == DEBUG_SYM_MODE_VERTEX) diff --git a/src/cairo/process_debug_symbolizer.cpp b/src/cairo/process_debug_symbolizer.cpp index c60794b78..f4a591285 100644 --- a/src/cairo/process_debug_symbolizer.cpp +++ b/src/cairo/process_debug_symbolizer.cpp @@ -106,9 +106,9 @@ void cairo_renderer::process(debug_symbolizer const& sym, if (mode == DEBUG_SYM_MODE_COLLISION) { - for (auto & n : *common_.detector_) + for (auto const& n : *common_.detector_) { - render_debug_box(context_, n.get().box); + render_debug_box(context_, std::get<1>(n).box); } } else if (mode == DEBUG_SYM_MODE_VERTEX) diff --git a/src/renderer_common/process_group_symbolizer.cpp b/src/renderer_common/process_group_symbolizer.cpp index ebef9149f..0968a6e26 100644 --- a/src/renderer_common/process_group_symbolizer.cpp +++ b/src/renderer_common/process_group_symbolizer.cpp @@ -215,15 +215,15 @@ void render_thunk_extractor::update_box() const { label_collision_detector4 & detector = *common_.detector_; - for (auto const& label : detector) + for (auto const& node : detector) { if (box_.width() > 0 && box_.height() > 0) { - box_.expand_to_include(label.get().box); + box_.expand_to_include(std::get<1>(node).box); } else { - box_ = label.get().box; + box_ = std::get<1>(node).box; } } diff --git a/src/text/placement_finder.cpp b/src/text/placement_finder.cpp index 7c09e56f2..27ff92935 100644 --- a/src/text/placement_finder.cpp +++ b/src/text/placement_finder.cpp @@ -399,7 +399,9 @@ bool placement_finder::collision(const box2d &box, const value_unicode_s margin = (text_props_->margin != 0 ? text_props_->margin : text_props_->minimum_distance) * scale_factor_; repeat_distance = text_props_->repeat_distance * scale_factor_; } - return (text_props_->avoid_edges && !extent_.contains(box)) + return !detector_.extent().intersects(box) + || + (text_props_->avoid_edges && !extent_.contains(box)) || (text_props_->minimum_padding > 0 && !extent_.contains(box + (scale_factor_ * text_props_->minimum_padding)))