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());