EXPERIMENTAL: use boost r-tree as a spatial container in label_collision_detector

This commit is contained in:
artemp 2015-07-17 13:50:22 +02:00
parent 5423f4c5bf
commit 8d9cecd6ad
5 changed files with 73 additions and 44 deletions

View file

@ -27,13 +27,39 @@
#include <mapnik/quad_tree.hpp> #include <mapnik/quad_tree.hpp>
#include <mapnik/util/noncopyable.hpp> #include <mapnik/util/noncopyable.hpp>
#include <mapnik/value_types.hpp> #include <mapnik/value_types.hpp>
#include <mapnik/geometry_adapters.hpp>
// boost
#include <boost/version.hpp>
#include <boost/geometry/index/rtree.hpp>
// icu // icu
#include <unicode/unistr.h> #include <unicode/unistr.h>
// stl // stl
#include <vector> #include <vector>
template <std::size_t Max, std::size_t Min>
struct detector_linear : boost::geometry::index::linear<Max,Min> {};
namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree {
template <std::size_t Max, std::size_t Min>
struct options_type<detector_linear<Max,Min> >
{
using type = options<detector_linear<Max, Min>,
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 namespace mapnik
{ {
//this needs to be tree structure //this needs to be tree structure
@ -139,52 +165,42 @@ public:
}; };
private: private:
using tree_t = quad_tree< label >;
tree_t tree_;
using box_type = mapnik::box2d<double>;
using item_type = std::pair<box_type, label>;
using tree_t = boost::geometry::index::rtree<item_type,detector_linear<16,4> >;
tree_t tree_;
box2d<double> extent_;
public: public:
using query_iterator = tree_t::query_iterator; using query_iterator = tree_t::const_query_iterator;
explicit label_collision_detector4(box2d<double> const& extent) explicit label_collision_detector4(box2d<double> const& extent)
: tree_(extent) {} : tree_(), extent_(extent) {}
bool has_placement(box2d<double> const& box) bool has_placement(box2d<double> const& box)
{ {
tree_t::query_iterator itr = tree_.query_in_box(box); auto itr = tree_.qbegin(boost::geometry::index::intersects(box));
tree_t::query_iterator end = tree_.query_end(); auto end = tree_.qend();
return (itr != end);
for ( ;itr != end; ++itr)
{
if (itr->get().box.intersects(box)) return false;
}
return true;
} }
bool has_placement(box2d<double> const& box, double margin) bool has_placement(box2d<double> const& box, double margin)
{ {
box2d<double> const& margin_box = (margin > 0 box2d<double> const& margin_box = (margin > 0
? box2d<double>(box.minx() - margin, box.miny() - margin, ? box2d<double>(box.minx() - margin, box.miny() - margin,
box.maxx() + margin, box.maxy() + margin) box.maxx() + margin, box.maxy() + margin)
: box); : box);
tree_t::query_iterator itr = tree_.query_in_box(margin_box); auto itr = tree_.qbegin(boost::geometry::index::intersects(margin_box));
tree_t::query_iterator end = tree_.query_end(); auto end = tree_.qend();
return (itr != end);
for (;itr != end; ++itr)
{
if (itr->get().box.intersects(margin_box))
{
return false;
}
}
return true;
} }
bool has_placement(box2d<double> const& box, double margin, mapnik::value_unicode_string const& text, double repeat_distance) bool has_placement(box2d<double> 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 // 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); return has_placement(box, margin);
} }
@ -196,12 +212,16 @@ public:
box.maxx() + margin, box.maxy() + margin) box.maxx() + margin, box.maxy() + margin)
: box); : box);
tree_t::query_iterator itr = tree_.query_in_box(repeat_box); auto itr = tree_.qbegin(boost::geometry::index::intersects(margin_box));
tree_t::query_iterator end = tree_.query_end(); auto end = tree_.qend();
for ( ;itr != end; ++itr) 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; return false;
} }
@ -212,12 +232,18 @@ public:
void insert(box2d<double> const& box) void insert(box2d<double> const& box)
{ {
tree_.insert(label(box), box); //if (tree_.extent().intersects(box))
//{
tree_.insert(std::make_pair(box, label(box)));
//}
} }
void insert(box2d<double> const& box, mapnik::value_unicode_string const& text) void insert(box2d<double> 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() void clear()
@ -227,11 +253,12 @@ public:
box2d<double> const& extent() const box2d<double> const& extent() const
{ {
return tree_.extent(); //auto const& b = tree_.bounds();
return extent_;
} }
query_iterator begin() { return tree_.query_in_box(extent()); } query_iterator begin() const { return tree_.qbegin(boost::geometry::index::intersects(extent_)); }
query_iterator end() { return tree_.query_end(); } query_iterator end() const { return tree_.qend(); }
}; };
} }

View file

@ -232,7 +232,7 @@ void agg_renderer<T0,T1>::process(debug_symbolizer const& sym,
{ {
for (auto const& n : *common_.detector_) 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) else if (mode == DEBUG_SYM_MODE_VERTEX)

View file

@ -106,9 +106,9 @@ void cairo_renderer<T>::process(debug_symbolizer const& sym,
if (mode == DEBUG_SYM_MODE_COLLISION) 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) else if (mode == DEBUG_SYM_MODE_VERTEX)

View file

@ -215,15 +215,15 @@ void render_thunk_extractor::update_box() const
{ {
label_collision_detector4 & detector = *common_.detector_; label_collision_detector4 & detector = *common_.detector_;
for (auto const& label : detector) for (auto const& node : detector)
{ {
if (box_.width() > 0 && box_.height() > 0) if (box_.width() > 0 && box_.height() > 0)
{ {
box_.expand_to_include(label.get().box); box_.expand_to_include(std::get<1>(node).box);
} }
else else
{ {
box_ = label.get().box; box_ = std::get<1>(node).box;
} }
} }

View file

@ -399,7 +399,9 @@ bool placement_finder::collision(const box2d<double> &box, const value_unicode_s
margin = (text_props_->margin != 0 ? text_props_->margin : text_props_->minimum_distance) * scale_factor_; margin = (text_props_->margin != 0 ? text_props_->margin : text_props_->minimum_distance) * scale_factor_;
repeat_distance = text_props_->repeat_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 && (text_props_->minimum_padding > 0 &&
!extent_.contains(box + (scale_factor_ * text_props_->minimum_padding))) !extent_.contains(box + (scale_factor_ * text_props_->minimum_padding)))