EXPERIMENTAL: use boost r-tree as a spatial container in label_collision_detector
This commit is contained in:
parent
5423f4c5bf
commit
8d9cecd6ad
5 changed files with 73 additions and 44 deletions
|
@ -27,13 +27,39 @@
|
|||
#include <mapnik/quad_tree.hpp>
|
||||
#include <mapnik/util/noncopyable.hpp>
|
||||
#include <mapnik/value_types.hpp>
|
||||
|
||||
#include <mapnik/geometry_adapters.hpp>
|
||||
// boost
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/geometry/index/rtree.hpp>
|
||||
// icu
|
||||
#include <unicode/unistr.h>
|
||||
|
||||
// stl
|
||||
#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
|
||||
{
|
||||
//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<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:
|
||||
using query_iterator = tree_t::query_iterator;
|
||||
using query_iterator = tree_t::const_query_iterator;
|
||||
|
||||
explicit label_collision_detector4(box2d<double> const& extent)
|
||||
: tree_(extent) {}
|
||||
: tree_(), extent_(extent) {}
|
||||
|
||||
bool has_placement(box2d<double> 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<double> const& box, double margin)
|
||||
{
|
||||
box2d<double> const& margin_box = (margin > 0
|
||||
? box2d<double>(box.minx() - margin, box.miny() - margin,
|
||||
box.maxx() + margin, box.maxy() + margin)
|
||||
: box);
|
||||
? box2d<double>(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<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
|
||||
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<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)
|
||||
{
|
||||
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<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 end() { return tree_.query_end(); }
|
||||
query_iterator begin() const { return tree_.qbegin(boost::geometry::index::intersects(extent_)); }
|
||||
query_iterator end() const { return tree_.qend(); }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -232,7 +232,7 @@ void agg_renderer<T0,T1>::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)
|
||||
|
|
|
@ -106,9 +106,9 @@ void cairo_renderer<T>::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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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_;
|
||||
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)))
|
||||
|
|
Loading…
Reference in a new issue