mirror of
https://github.com/mapnik/mapnik.git
synced 2025-12-08 20:13:09 +00:00
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:
parent
8fba4b11da
commit
b5c4bb77de
@ -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 @@ 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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -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(); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user