Permalink
Browse files

Exposed the label collision detector outside the agg_render object

and via Python, allowing detectors to be re-used across renderings.
  • Loading branch information...
1 parent 8fba4b1 commit b5c4bb77de1f48312d64387d5118711ac0b2eea2 @zerebubuth zerebubuth committed Oct 12, 2011
@@ -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"))
);
@@ -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 @@ class MAPNIK_DECL agg_renderer : public feature_style_processor<agg_renderer<T>
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);
};
}
@@ -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 @@ class label_collision_detector3 : boost::noncopyable
//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 @@ class label_collision_detector4 : boost::noncopyable
{
return tree_.extent();
}
+
+ query_iterator begin() { return tree_.query_in_box(extent()); }
+ query_iterator end() { return tree_.query_end(); }
};
}
View
@@ -121,9 +121,32 @@ 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();
}
}
@@ -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);
}
@@ -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());
@@ -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);
}
@@ -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);
@@ -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);

0 comments on commit b5c4bb7

Please sign in to comment.