From e34dc99f3aa42f708943df32fe6d0b5cb90c43f5 Mon Sep 17 00:00:00 2001 From: Panagiotis Skintzos Date: Sat, 25 Aug 2012 11:43:31 +0200 Subject: [PATCH] Exposed the label collision detector outside of Cairo renderer and added Python bindings (issue #1107) --- bindings/python/mapnik_python.cpp | 109 ++++++++++++++++++++++++++++++ include/mapnik/cairo_renderer.hpp | 4 +- src/cairo_renderer.cpp | 50 +++++++++++--- 3 files changed, 153 insertions(+), 10 deletions(-) diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 705d4fdd6..ad651eacf 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -199,6 +199,56 @@ void render6(const mapnik::Map& map, PycairoContext* context) ren.apply(); } +void render_with_detector2( + const mapnik::Map& map, + PycairoContext* context, + boost::shared_ptr detector) +{ + python_unblock_auto_block b; + Cairo::RefPtr c(new Cairo::Context(context->ctx)); + mapnik::cairo_renderer ren(map,c,detector); + ren.apply(); +} + +void render_with_detector3( + const mapnik::Map& map, + PycairoContext* context, + boost::shared_ptr detector, + double scale_factor = 1.0, + unsigned offset_x = 0u, + unsigned offset_y = 0u) +{ + python_unblock_auto_block b; + Cairo::RefPtr c(new Cairo::Context(context->ctx)); + mapnik::cairo_renderer ren(map,c,detector,scale_factor,offset_x,offset_y); + ren.apply(); +} + +void render_with_detector4( + const mapnik::Map& map, + PycairoSurface* surface, + boost::shared_ptr detector) +{ + python_unblock_auto_block b; + Cairo::RefPtr s(new Cairo::Surface(surface->surface)); + mapnik::cairo_renderer ren(map,s,detector); + ren.apply(); +} + +void render_with_detector5( + const mapnik::Map& map, + PycairoSurface* surface, + boost::shared_ptr detector, + double scale_factor = 1.0, + unsigned offset_x = 0u, + unsigned offset_y = 0u) +{ + python_unblock_auto_block b; + Cairo::RefPtr s(new Cairo::Surface(surface->surface)); + mapnik::cairo_renderer ren(map,s,detector,scale_factor,offset_x,offset_y); + ren.apply(); +} + #endif @@ -572,6 +622,65 @@ BOOST_PYTHON_MODULE(_mapnik) ">>> render(m,context)\n" "\n" ); + + def("render_with_detector", &render_with_detector2, + "\n" + "Render Map to Cairo Context using a pre-constructed detector.\n" + "\n" + "Usage:\n" + ">>> from mapnik import Map, LabelCollisionDetector, render_with_detector, load_map\n" + ">>> from cairo import SVGSurface, Context\n" + ">>> surface = SVGSurface('image.svg', m.width, m.height)\n" + ">>> ctx = Context(surface)\n" + ">>> m = Map(256,256)\n" + ">>> load_map(m,'mapfile.xml')\n" + ">>> detector = LabelCollisionDetector(m)\n" + ">>> render_with_detector(m, ctx, detector)\n" + ); + + def("render_with_detector", &render_with_detector3, + "\n" + "Render Map to Cairo Context using a pre-constructed detector, scale and offsets.\n" + "\n" + "Usage:\n" + ">>> from mapnik import Map, LabelCollisionDetector, render_with_detector, load_map\n" + ">>> from cairo import SVGSurface, Context\n" + ">>> surface = SVGSurface('image.svg', m.width, m.height)\n" + ">>> ctx = Context(surface)\n" + ">>> m = Map(256,256)\n" + ">>> load_map(m,'mapfile.xml')\n" + ">>> detector = LabelCollisionDetector(m)\n" + ">>> render_with_detector(m, ctx, detector, 1, 1, 1)\n" + ); + + def("render_with_detector", &render_with_detector4, + "\n" + "Render Map to Cairo Surface using a pre-constructed detector.\n" + "\n" + "Usage:\n" + ">>> from mapnik import Map, LabelCollisionDetector, render_with_detector, load_map\n" + ">>> from cairo import SVGSurface, Context\n" + ">>> surface = SVGSurface('image.svg', m.width, m.height)\n" + ">>> m = Map(256,256)\n" + ">>> load_map(m,'mapfile.xml')\n" + ">>> detector = LabelCollisionDetector(m)\n" + ">>> render_with_detector(m, surface, detector)\n" + ); + + def("render_with_detector", &render_with_detector5, + "\n" + "Render Map to Cairo Surface using a pre-constructed detector, scale and offsets.\n" + "\n" + "Usage:\n" + ">>> from mapnik import Map, LabelCollisionDetector, render_with_detector, load_map\n" + ">>> from cairo import SVGSurface, Context\n" + ">>> surface = SVGSurface('image.svg', m.width, m.height)\n" + ">>> m = Map(256,256)\n" + ">>> load_map(m,'mapfile.xml')\n" + ">>> detector = LabelCollisionDetector(m)\n" + ">>> render_with_detector(m, surface, detector, 1, 1, 1)\n" + ); + #endif def("scale_denominator", &scale_denominator, diff --git a/include/mapnik/cairo_renderer.hpp b/include/mapnik/cairo_renderer.hpp index c8bfc88a7..5adba78da 100644 --- a/include/mapnik/cairo_renderer.hpp +++ b/include/mapnik/cairo_renderer.hpp @@ -73,6 +73,7 @@ class MAPNIK_DECL cairo_renderer_base : private boost::noncopyable { protected: cairo_renderer_base(Map const& m, Cairo::RefPtr const& context, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); + cairo_renderer_base(Map const& m, Cairo::RefPtr const& context, boost::shared_ptr detector, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); public: ~cairo_renderer_base(); void start_map_processing(Map const& map); @@ -136,7 +137,7 @@ protected: boost::shared_ptr font_engine_; face_manager font_manager_; cairo_face_manager face_manager_; - label_collision_detector4 detector_; + boost::shared_ptr detector_; box2d query_extent_; }; @@ -147,6 +148,7 @@ class MAPNIK_DECL cairo_renderer : public feature_style_processor const& surface, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); + cairo_renderer(Map const& m, Cairo::RefPtr const& surface, boost::shared_ptr detector, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); void end_map_processing(Map const& map); }; } diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index c44171da5..d90fa3d8e 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -774,7 +774,29 @@ cairo_renderer_base::cairo_renderer_base(Map const& m, font_engine_(boost::make_shared()), font_manager_(*font_engine_), face_manager_(font_engine_), - detector_(box2d(-m.buffer_size() ,-m.buffer_size() , m.width() + m.buffer_size() ,m.height() + m.buffer_size())) + detector_(boost::make_shared( + box2d(-m.buffer_size(), -m.buffer_size(), + m.width() + m.buffer_size(), m.height() + m.buffer_size()))) +{ + MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: Scale=" << m.scale(); +} + +cairo_renderer_base::cairo_renderer_base(Map const& m, + Cairo::RefPtr const& context, + boost::shared_ptr detector, + double scale_factor, + unsigned offset_x, + unsigned offset_y) + : m_(m), + context_(context), + width_(m.width()), + height_(m.height()), + scale_factor_(scale_factor), + t_(m.width(),m.height(),m.get_current_extent(),offset_x,offset_y), + font_engine_(boost::make_shared()), + font_manager_(*font_engine_), + face_manager_(font_engine_), + detector_(detector) { MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: Scale=" << m.scale(); } @@ -789,6 +811,16 @@ cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr(m,scale_factor), cairo_renderer_base(m,Cairo::Context::create(surface),scale_factor,offset_x,offset_y) {} +template <> +cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& context, boost::shared_ptr detector, double scale_factor, unsigned offset_x, unsigned offset_y) + : feature_style_processor(m,scale_factor), + cairo_renderer_base(m,context,detector,scale_factor,offset_x,offset_y) {} + +template <> +cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& surface, boost::shared_ptr detector, double scale_factor, unsigned offset_x, unsigned offset_y) + : feature_style_processor(m,scale_factor), + cairo_renderer_base(m,Cairo::Context::create(surface),detector,scale_factor,offset_x,offset_y) {} + cairo_renderer_base::~cairo_renderer_base() {} void cairo_renderer_base::start_map_processing(Map const& map) @@ -834,7 +866,7 @@ void cairo_renderer_base::start_layer_processing(layer const& lay, box2d if (lay.clear_label_cache()) { - detector_.clear(); + detector_->clear(); } query_extent_ = query_extent; } @@ -1224,12 +1256,12 @@ void cairo_renderer_base::process(point_symbolizer const& sym, label_ext *= tr; label_ext *= agg::trans_affine_translation(x,y); if (sym.get_allow_overlap() || - detector_.has_placement(label_ext)) + detector_->has_placement(label_ext)) { render_marker(pixel_position(x,y),**marker, tr, sym.get_opacity()); if (!sym.get_ignore_placement()) - detector_.insert(label_ext); + detector_->insert(label_ext); } } } @@ -1244,7 +1276,7 @@ void cairo_renderer_base::process(shield_symbolizer const& sym, sym, feature, prj_trans, width_, height_, scale_factor_, - t_, font_manager_, detector_, query_extent_); + t_, font_manager_, *detector_, query_extent_); cairo_context context(context_); context.set_operator(sym.comp_op()); @@ -1689,7 +1721,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, box2d bbox = marker_ellipse.bounding_box(); dispatch_type dispatch(context, marker_ellipse, result?attributes:(*stock_vector_marker)->attributes(), - detector_, sym, bbox, marker_tr, scale_factor_); + *detector_, sym, bbox, marker_tr, scale_factor_); vertex_converter, dispatch_type, markers_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> converter(query_extent_, dispatch, sym, t_, prj_trans, marker_tr, scale_factor_); @@ -1717,7 +1749,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); dispatch_type dispatch(context, **stock_vector_marker, result?attributes:(*stock_vector_marker)->attributes(), - detector_, sym, bbox, tr, scale_factor_); + *detector_, sym, bbox, tr, scale_factor_); vertex_converter, dispatch_type, markers_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> converter(query_extent_, dispatch, sym, t_, prj_trans, tr, scale_factor_); @@ -1749,7 +1781,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, if ( marker ) { dispatch_type dispatch(context, *marker, - detector_, sym, bbox, tr, scale_factor_); + *detector_, sym, bbox, tr, scale_factor_); vertex_converter, dispatch_type, markers_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> @@ -1786,7 +1818,7 @@ void cairo_renderer_base::process(text_symbolizer const& sym, sym, feature, prj_trans, width_, height_, scale_factor_, - t_, font_manager_, detector_, query_extent_); + t_, font_manager_, *detector_, query_extent_); cairo_context context(context_); context.set_operator(sym.comp_op());