Exposed the label collision detector outside the agg_render object

and via Python, allowing detectors to be re-used across renderings.
This commit is contained in:
Matt Amos 2011-10-12 01:05:35 +01:00
parent 8fba4b11da
commit b5c4bb77de
9 changed files with 92 additions and 18 deletions

View File

@ -66,6 +66,7 @@ void export_view_transform();
void export_raster_colorizer();
void export_glyph_symbolizer();
void export_inmem_metawriter();
void export_label_collision_detector();
#include <mapnik/version.hpp>
#include <mapnik/value_error.hpp>
@ -120,6 +121,28 @@ void render(const mapnik::Map& map,
Py_END_ALLOW_THREADS
}
void render_with_detector(
const mapnik::Map &map,
mapnik::image_32 &image,
boost::shared_ptr<mapnik::label_collision_detector4> detector,
double scale_factor = 1.0,
unsigned offset_x = 0u,
unsigned offset_y = 0u)
{
Py_BEGIN_ALLOW_THREADS
try
{
mapnik::agg_renderer<mapnik::image_32> ren(map,image,detector);
ren.apply();
}
catch (...)
{
Py_BLOCK_THREADS
throw;
}
Py_END_ALLOW_THREADS
}
void render_layer2(const mapnik::Map& map,
mapnik::image_32& image,
unsigned layer_idx)
@ -374,6 +397,7 @@ BOOST_PYTHON_FUNCTION_OVERLOADS(load_map_string_overloads, load_map_string, 2, 4
BOOST_PYTHON_FUNCTION_OVERLOADS(save_map_overloads, save_map, 2, 3)
BOOST_PYTHON_FUNCTION_OVERLOADS(save_map_to_string_overloads, save_map_to_string, 1, 2)
BOOST_PYTHON_FUNCTION_OVERLOADS(render_overloads, render, 2, 5)
BOOST_PYTHON_FUNCTION_OVERLOADS(render_with_detector_overloads, render_with_detector, 3, 6)
BOOST_PYTHON_MODULE(_mapnik2)
{
@ -427,6 +451,7 @@ BOOST_PYTHON_MODULE(_mapnik2)
export_raster_colorizer();
export_glyph_symbolizer();
export_inmem_metawriter();
export_label_collision_detector();
def("render_grid",&render_grid,
( arg("map"),
@ -503,6 +528,19 @@ BOOST_PYTHON_MODULE(_mapnik2)
"\n"
));
def("render_with_detector", &render_with_detector, render_with_detector_overloads(
"\n"
"Render Map to an AGG image_32 using a pre-constructed detector.\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, Image, LabelCollisionDetector, render_with_detector, load_map\n"
">>> m = Map(256,256)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> im = Image(m.width,m.height)\n"
">>> detector = LabelCollisionDetector(m)\n"
">>> render_with_detector(m, im, detector)\n"
));
def("render_layer", &render_layer2,
(arg("map"),arg("image"),args("layer"))
);

View File

@ -40,6 +40,7 @@
// boost
#include <boost/utility.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
// FIXME
// forward declare so that
@ -61,7 +62,11 @@ class MAPNIK_DECL agg_renderer : public feature_style_processor<agg_renderer<T>
{
public:
// create with default, empty placement detector
agg_renderer(Map const& m, T & pixmap, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0);
// create with external placement detector, possibly non-empty
agg_renderer(Map const &m, T & pixmap, boost::shared_ptr<label_collision_detector4> detector,
double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0);
~agg_renderer();
void start_map_processing(Map const& map);
void end_map_processing(Map const& map);
@ -122,8 +127,10 @@ private:
CoordTransform t_;
freetype_engine font_engine_;
face_manager<freetype_engine> font_manager_;
label_collision_detector4 detector_;
boost::shared_ptr<label_collision_detector4> detector_;
boost::scoped_ptr<rasterizer> ras_ptr;
void setup(Map const &m);
};
}

View File

@ -69,7 +69,7 @@ class label_collision_detector2 : boost::noncopyable
typedef quad_tree<box2d<double> > tree_t;
tree_t tree_;
public:
explicit label_collision_detector2(box2d<double> const& extent)
: tree_(extent) {}
@ -138,6 +138,7 @@ public:
//quad tree based label collission detector so labels dont appear within a given distance
class label_collision_detector4 : boost::noncopyable
{
public:
struct label
{
label(box2d<double> const& b) : box(b) {}
@ -146,11 +147,13 @@ class label_collision_detector4 : boost::noncopyable
box2d<double> box;
UnicodeString text;
};
private:
typedef quad_tree< label > tree_t;
tree_t tree_;
public:
typedef tree_t::query_iterator query_iterator;
explicit label_collision_detector4(box2d<double> const& extent)
: tree_(extent) {}
@ -224,6 +227,9 @@ public:
{
return tree_.extent();
}
query_iterator begin() { return tree_.query_in_box(extent()); }
query_iterator end() { return tree_.query_end(); }
};
}

View File

@ -121,8 +121,31 @@ agg_renderer<T>::agg_renderer(Map const& m, T & pixmap, double scale_factor, uns
t_(m.width(),m.height(),m.get_current_extent(),offset_x,offset_y),
font_engine_(),
font_manager_(font_engine_),
detector_(box2d<double>(-m.buffer_size(), -m.buffer_size(), m.width() + m.buffer_size() ,m.height() + m.buffer_size())),
detector_(new label_collision_detector4(box2d<double>(-m.buffer_size(), -m.buffer_size(), m.width() + m.buffer_size() ,m.height() + m.buffer_size()))),
ras_ptr(new rasterizer)
{
setup(m);
}
template <typename T>
agg_renderer<T>::agg_renderer(Map const& m, T & pixmap, boost::shared_ptr<label_collision_detector4> detector,
double scale_factor, unsigned offset_x, unsigned offset_y)
: feature_style_processor<agg_renderer>(m, scale_factor),
pixmap_(pixmap),
width_(pixmap_.width()),
height_(pixmap_.height()),
scale_factor_(scale_factor),
t_(m.width(),m.height(),m.get_current_extent(),offset_x,offset_y),
font_engine_(),
font_manager_(font_engine_),
detector_(detector),
ras_ptr(new rasterizer)
{
setup(m);
}
template <typename T>
void agg_renderer<T>::setup(Map const &m)
{
boost::optional<color> const& bg = m.background();
if (bg) pixmap_.set_background(*bg);
@ -189,7 +212,7 @@ void agg_renderer<T>::start_layer_processing(layer const& lay)
#endif
if (lay.clear_label_cache())
{
detector_.clear();
detector_->clear();
}
}

View File

@ -77,12 +77,12 @@ void agg_renderer<T>::process(glyph_symbolizer const& sym,
// final box so we can check for a valid placement
box2d<double> dim = ren.prepare_glyphs(path.get());
box2d<double> ext(x-dim.width()/2, y-dim.height()/2, x+dim.width()/2, y+dim.height()/2);
if ((sym.get_allow_overlap() || detector_.has_placement(ext)) &&
(!sym.get_avoid_edges() || detector_.extent().contains(ext)))
if ((sym.get_allow_overlap() || detector_->has_placement(ext)) &&
(!sym.get_avoid_edges() || detector_->extent().contains(ext)))
{
// Placement is valid, render glyph and update detector.
ren.render(x, y);
detector_.insert(ext);
detector_->insert(ext);
metawriter_with_properties writer = sym.get_metawriter();
if (writer.first) writer.first->add_box(ext, feature, t_, writer.second);
}

View File

@ -109,7 +109,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
}
path_type path(t_,geom,prj_trans);
markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_,
markers_placement<path_type, label_collision_detector4> placement(path, extent, *detector_,
sym.get_spacing() * scale_factor_,
sym.get_max_error(),
sym.get_allow_overlap());
@ -194,7 +194,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
box2d<double> label_ext (px, py, px + dx +1, py + dy +1);
if (sym.get_allow_overlap() ||
detector_.has_placement(label_ext))
detector_->has_placement(label_ext))
{
agg::ellipse c(x, y, w, h);
marker.concat_path(c);
@ -215,7 +215,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
ren.color(agg::rgba8(s_r, s_g, s_b, int(s_a*stroke_.get_opacity())));
agg::render_scanlines(*ras_ptr, sl_line, ren);
}
detector_.insert(label_ext);
detector_->insert(label_ext);
if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second);
}
}
@ -226,7 +226,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
marker.concat_path(arrow_);
path_type path(t_,geom,prj_trans);
markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_,
markers_placement<path_type, label_collision_detector4> placement(path, extent, *detector_,
sym.get_spacing() * scale_factor_,
sym.get_max_error(),
sym.get_allow_overlap());

View File

@ -99,13 +99,13 @@ void agg_renderer<T>::process(point_symbolizer const& sym,
label_ext.re_center(x,y);
if (sym.get_allow_overlap() ||
detector_.has_placement(label_ext))
detector_->has_placement(label_ext))
{
render_marker(floor(x - 0.5 * w),floor(y - 0.5 * h) ,**marker,tr, sym.get_opacity());
if (!sym.get_ignore_placement())
detector_.insert(label_ext);
detector_->insert(label_ext);
metawriter_with_properties writer = sym.get_metawriter();
if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second);
}

View File

@ -135,7 +135,7 @@ void agg_renderer<T>::process(shield_symbolizer const& sym,
ren.set_halo_radius(sym.get_halo_radius() * scale_factor_);
ren.set_opacity(sym.get_text_opacity());
placement_finder<label_collision_detector4> finder(detector_);
placement_finder<label_collision_detector4> finder(*detector_);
string_info info(text);
@ -210,13 +210,13 @@ void agg_renderer<T>::process(shield_symbolizer const& sym,
label_ext.re_center(label_x,label_y);
}
if ( sym.get_allow_overlap() || detector_.has_placement(label_ext) )
if ( sym.get_allow_overlap() || detector_->has_placement(label_ext) )
{
render_marker(px,py,**marker,tr,sym.get_opacity());
box2d<double> dim = ren.prepare_glyphs(&text_placement.placements[0]);
ren.render(x,y);
detector_.insert(label_ext);
detector_->insert(label_ext);
finder.update_detector(text_placement);
if (writer.first) {
writer.first->add_box(label_ext, feature, t_, writer.second);

View File

@ -110,7 +110,7 @@ void agg_renderer<T>::process(text_symbolizer const& sym,
ren.set_opacity(sym.get_text_opacity());
box2d<double> dims(0,0,width_,height_);
placement_finder<label_collision_detector4> finder(detector_,dims);
placement_finder<label_collision_detector4> finder(*detector_,dims);
string_info info(text);