From a1f0af112ed5c575867b968143595d211291dad7 Mon Sep 17 00:00:00 2001 From: Hermann Kraus Date: Fri, 17 Aug 2012 18:31:55 +0200 Subject: [PATCH] Support ShieldSymbolizer. --- include/mapnik/symbolizer_helpers.hpp | 4 -- include/mapnik/text/placement_finder_ng.hpp | 15 +++++ include/mapnik/text/placements_list.hpp | 21 ++++++- src/agg/process_shield_symbolizer.cpp | 51 ++++----------- src/grid/process_shield_symbolizer.cpp | 62 +++++-------------- src/symbolizer_helpers.cpp | 53 +++++++--------- src/text/placement_finder_ng.cpp | 42 ++++++++++++- .../styles/shieldsymbolizer-3.xml | 2 +- .../styles/shieldsymbolizer-4.xml | 5 +- 9 files changed, 126 insertions(+), 129 deletions(-) diff --git a/include/mapnik/symbolizer_helpers.hpp b/include/mapnik/symbolizer_helpers.hpp index 209346be6..8cecdb3cb 100644 --- a/include/mapnik/symbolizer_helpers.hpp +++ b/include/mapnik/symbolizer_helpers.hpp @@ -70,8 +70,6 @@ public: /** Return all placements.*/ placements_list const& get(); - marker_ptr get_marker() const; - agg::trans_affine const& get_image_transform() const; protected: bool next_point_placement(); bool next_line_placement(); @@ -104,8 +102,6 @@ protected: placement_finder_ng finder_; //ShieldSymbolizer only - marker_ptr marker_; - agg::trans_affine marker_transform_; void init_marker(); }; diff --git a/include/mapnik/text/placement_finder_ng.hpp b/include/mapnik/text/placement_finder_ng.hpp index d6e751a0e..728b02d97 100644 --- a/include/mapnik/text/placement_finder_ng.hpp +++ b/include/mapnik/text/placement_finder_ng.hpp @@ -68,16 +68,24 @@ public: bool next_position(); placements_list const& placements() const; + + void set_marker(marker_info_ptr m, box2d box, bool marker_unlocked, pixel_position const& marker_displacement); private: void init_alignment(); pixel_position alignment_offset() const; double jalign_offset(double line_width) const; bool single_line_placement(vertex_cache &pp, text_upright_e orientation); + /** Moves dx pixels but makes sure not to fall of the end. */ void path_move_dx(vertex_cache &pp); + /** Normalize angle in range [-pi, +pi]. */ static double normalize_angle(double angle); + /** Adjusts user defined spacing to place an integer number of labels. */ double get_spacing(double path_length, double layout_width) const; + /** Checks for collision. */ bool collision(box2d const& box) const; + /** Adds marker to glyph_positions and to collision detector. Returns false if there is a collision. */ + bool add_marker(glyph_positions_ptr glyphs, pixel_position const& pos) const; box2d get_bbox(glyph_info const& glyph, pixel_position const& pos, rotation const& rot); Feature const& feature_; DetectorType &detector_; @@ -94,6 +102,13 @@ private: double scale_factor_; placements_list placements_; + + //ShieldSymbolizer + bool has_marker_; + marker_info_ptr marker_; + box2d marker_box_; + bool marker_unlocked_; + pixel_position marker_displacement_; }; typedef boost::shared_ptr placement_finder_ng_ptr; diff --git a/include/mapnik/text/placements_list.hpp b/include/mapnik/text/placements_list.hpp index 08ae9726f..a2f3ba7cc 100644 --- a/include/mapnik/text/placements_list.hpp +++ b/include/mapnik/text/placements_list.hpp @@ -26,6 +26,10 @@ #include #include #include +#include + +// agg +#include "agg_trans_affine.h" //stl #include @@ -45,9 +49,19 @@ struct glyph_position rotation rot; }; +struct marker_info +{ + marker_info() : marker(), transform() {} + marker_info(marker_ptr marker, agg::trans_affine const& transform) : + marker(marker), transform(transform) {} + marker_ptr marker; + agg::trans_affine transform; +}; +typedef boost::shared_ptr marker_info_ptr; + /** Stores positions of glphys. * - * The actual glyphs and their format is stored in text_layout. + * The actual glyphs and their format are stored in text_layout. */ class glyph_positions { @@ -62,9 +76,14 @@ public: pixel_position const& get_base_point() const; void set_base_point(pixel_position base_point); + void set_marker(marker_info_ptr marker, pixel_position const& marker_pos); + marker_info_ptr marker() const; + pixel_position const& marker_pos() const; private: std::vector data_; pixel_position base_point_; + marker_info_ptr marker_; + pixel_position marker_pos_; }; typedef boost::shared_ptr glyph_positions_ptr; diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index b77a8b85b..411ea30ee 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -22,15 +22,8 @@ // mapnik #include -#include -#include -#include -#include -#include #include - -// boost -#include +#include namespace mapnik { @@ -39,47 +32,25 @@ void agg_renderer::process(shield_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { -#if 0 - shield_symbolizer_helper, - label_collision_detector4> helper( + text_symbolizer_helper helper( sym, feature, prj_trans, width_, height_, scale_factor_, t_, font_manager_, *detector_, query_extent_); - text_renderer ren(*current_buffer_, - font_manager_, - *(font_manager_.get_stroker()), - sym.comp_op(), - scale_factor_); + agg_text_renderer ren(*current_buffer_, *(font_manager_.get_stroker()), sym.comp_op(), scale_factor_); - while (helper.next()) + placements_list const& placements = helper.get(); + BOOST_FOREACH(glyph_positions_ptr glyphs, placements) { - placements_type const& placements = helper.placements(); - for (unsigned int ii = 0; ii < placements.size(); ++ii) - { - // get_marker_position returns (minx,miny) corner position, - // while (currently only) agg_renderer::render_marker newly - // expects center position; - // until all renderers and shield_symbolizer_helper are - // modified accordingly, we must adjust the position here - pixel_position pos = helper.get_marker_position(placements[ii]); - pos.x += 0.5 * helper.get_marker_width(); - pos.y += 0.5 * helper.get_marker_height(); - render_marker(pos, - helper.get_marker(), - helper.get_image_transform(), - sym.get_opacity(), - sym.comp_op()); - - ren.prepare_glyphs(placements[ii]); - ren.render(placements[ii].center); - } + if (glyphs->marker()) + render_marker(glyphs->marker_pos(), + *(glyphs->marker()->marker), + glyphs->marker()->transform, + sym.get_opacity(), sym.comp_op()); + ren.render(glyphs); } -#else -#warning AGG: ShieldSymbolizer disabled! -#endif } diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp index 4792c2a46..a09b9c62e 100644 --- a/src/grid/process_shield_symbolizer.cpp +++ b/src/grid/process_shield_symbolizer.cpp @@ -21,15 +21,9 @@ *****************************************************************************/ // mapnik -#include #include -#include -#include -#include #include -#include -#include -#include +#include // agg #include "agg_trans_affine.h" @@ -41,54 +35,28 @@ void grid_renderer::process(shield_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { -#if 0 - shield_symbolizer_helper, - label_collision_detector4> helper( + text_symbolizer_helper helper( sym, feature, prj_trans, width_, height_, - scale_factor_, + scale_factor_ * (1.0/pixmap_.get_resolution()), t_, font_manager_, *detector_, query_extent_); - bool placement_found = false; - text_renderer ren(pixmap_, - font_manager_, - *(font_manager_.get_stroker()), - sym.comp_op(), - scale_factor_); + grid_text_renderer ren(pixmap_, *(font_manager_.get_stroker()), sym.comp_op(), scale_factor_); - text_placement_info_ptr placement; - while (helper.next()) + placements_list const& placements = helper.get(); + if (!placements.size()) return; + BOOST_FOREACH(glyph_positions_ptr glyphs, placements) { - placement_found = true; - placements_type const& placements = helper.placements(); - for (unsigned int ii = 0; ii < placements.size(); ++ii) - { - // get_marker_position returns (minx,miny) corner position, - // while (currently only) agg_renderer::render_marker newly - // expects center position; - // until all renderers and shield_symbolizer_helper are - // modified accordingly, we must adjust the position here - pixel_position pos = helper.get_marker_position(placements[ii]); - pos.x += 0.5 * helper.get_marker_width(); - pos.y += 0.5 * helper.get_marker_height(); - render_marker(feature, - pixmap_.get_resolution(), - pos, - helper.get_marker(), - helper.get_image_transform(), - sym.get_opacity(), - sym.comp_op()); - - ren.prepare_glyphs(placements[ii]); - ren.render_id(feature.id(), placements[ii].center, 2); - } + if (glyphs->marker()->marker) + render_marker(feature, pixmap_.get_resolution(), + glyphs->marker_pos(), + *(glyphs->marker()->marker), + glyphs->marker()->transform, + sym.get_opacity(), sym.comp_op()); + ren.render(glyphs, feature.id(), 2); } - if (placement_found) - pixmap_.add_feature(feature); -#else -#warning GRID: TextSymbolizer disabled! -#endif + pixmap_.add_feature(feature); } template void grid_renderer::process(shield_symbolizer const&, diff --git a/src/symbolizer_helpers.cpp b/src/symbolizer_helpers.cpp index c26543d41..3a6527c7f 100644 --- a/src/symbolizer_helpers.cpp +++ b/src/symbolizer_helpers.cpp @@ -267,45 +267,34 @@ void text_symbolizer_helper::init_marker() { shield_symbolizer const& sym = static_cast(sym_); std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature_); - evaluate_transform(marker_transform_, feature_, sym.get_image_transform()); -#if 0 - marker_.reset(); + agg::trans_affine trans; + evaluate_transform(trans, feature_, sym.get_image_transform()); + boost::optional opt_marker; //TODO: Why boost::optional? if (!filename.empty()) { - marker_ = marker_cache::instance()->find(filename, true); + opt_marker = marker_cache::instance()->find(filename, true); } - if (!marker_) { - marker_size_.clear(); - marker_ext_.init(0, 0, 0, 0); - return; - } - marker_size_.set((*marker_)->width(), (*marker_)->height()); - double px0 = - 0.5 * marker_size_.x; - double py0 = - 0.5 * marker_size_.y; - double px1 = 0.5 * marker_size_.x; - double py1 = 0.5 * marker_size_.y; + marker_ptr m; + if (opt_marker) m = *opt_marker; + if (!m) return; + double width = m->width(); + double height = m->height(); + double px0 = - 0.5 * width; + double py0 = - 0.5 * height; + double px1 = 0.5 * width; + double py1 = 0.5 * height; double px2 = px1; double py2 = py0; double px3 = px0; double py3 = py1; - marker_transform_.transform(&px0,&py0); - marker_transform_.transform(&px1,&py1); - marker_transform_.transform(&px2,&py2); - marker_transform_.transform(&px3,&py3); - marker_ext_.init(px0, py0, px1, py1); - marker_ext_.expand_to_include(px2, py2); - marker_ext_.expand_to_include(px3, py3); -#endif -} - -marker_ptr text_symbolizer_helper::get_marker() const -{ - return marker_; -} - -agg::trans_affine const& text_symbolizer_helper::get_image_transform() const -{ - return marker_transform_; + trans.transform(&px0, &py0); + trans.transform(&px1, &py1); + trans.transform(&px2, &py2); + trans.transform(&px3, &py3); + box2d bbox(px0, py0, px1, py1); + bbox.expand_to_include(px2, py2); + bbox.expand_to_include(px3, py3); + finder_.set_marker(boost::make_shared(m, trans), bbox, sym.get_unlock_image(), sym.get_shield_displacement()); } template text_symbolizer_helper::text_symbolizer_helper(const text_symbolizer &sym, const Feature &feature, diff --git a/src/text/placement_finder_ng.cpp b/src/text/placement_finder_ng.cpp index ad0cc930c..964225575 100644 --- a/src/text/placement_finder_ng.cpp +++ b/src/text/placement_finder_ng.cpp @@ -43,7 +43,7 @@ namespace mapnik { placement_finder_ng::placement_finder_ng(Feature const& feature, DetectorType &detector, box2d const& extent, text_placement_info_ptr placement_info, face_manager_freetype &font_manager, double scale_factor) - : feature_(feature), detector_(detector), extent_(extent), layout_(font_manager), info_(placement_info), valid_(true), scale_factor_(scale_factor), placements_() + : feature_(feature), detector_(detector), extent_(extent), layout_(font_manager), info_(placement_info), valid_(true), scale_factor_(scale_factor), placements_(), has_marker_(false), marker_(), marker_box_() { } @@ -83,7 +83,6 @@ const placements_list &placement_finder_ng::placements() const return placements_; } - void placement_finder_ng::init_alignment() { text_symbolizer_properties const& p = info_->properties; @@ -191,7 +190,7 @@ bool placement_finder_ng::find_point_placement(pixel_position pos) rotated_box2d(bbox, orientation_, layout_.width(), layout_.height()); bbox.re_center(glyphs->get_base_point().x, glyphs->get_base_point().y); if (collision(bbox)) return false; - + if (has_marker_ && !add_marker(glyphs, pos)) return false; detector_.insert(bbox, layout_.get_text()); /* IMPORTANT NOTE: @@ -438,6 +437,27 @@ bool placement_finder_ng::collision(const box2d &box) const return false; } +void placement_finder_ng::set_marker(marker_info_ptr m, box2d box, bool marker_unlocked, const pixel_position &marker_displacement) +{ + marker_ = m; + marker_box_ = box; + marker_unlocked_ = marker_unlocked; + marker_displacement_ = marker_displacement; + has_marker_ = true; +} + + +bool placement_finder_ng::add_marker(glyph_positions_ptr glyphs, const pixel_position &pos) const +{ + pixel_position real_pos = (marker_unlocked_ ? pos : glyphs->get_base_point()) + marker_displacement_; + box2d bbox = marker_box_; + bbox.move(real_pos.x, real_pos.y); + glyphs->set_marker(marker_, real_pos); + if (collision(bbox)) return false; + detector_.insert(bbox); + return true; +} + box2d placement_finder_ng::get_bbox(glyph_info const& glyph, pixel_position const& pos, rotation const& rot) { /* @@ -507,6 +527,22 @@ void glyph_positions::set_base_point(pixel_position base_point) base_point_ = base_point; } +void glyph_positions::set_marker(marker_info_ptr marker, const pixel_position &marker_pos) +{ + marker_ = marker; + marker_pos_ = marker_pos; +} + +marker_info_ptr glyph_positions::marker() const +{ + return marker_; +} + +const pixel_position &glyph_positions::marker_pos() const +{ + return marker_pos_; +} + /*************************************************************************************/ typedef agg::conv_clip_polyline clipped_geometry_type; diff --git a/tests/visual_tests/styles/shieldsymbolizer-3.xml b/tests/visual_tests/styles/shieldsymbolizer-3.xml index 3714c7924..055504e85 100644 --- a/tests/visual_tests/styles/shieldsymbolizer-3.xml +++ b/tests/visual_tests/styles/shieldsymbolizer-3.xml @@ -50,7 +50,7 @@ [nr] = '10' - 'X' + 'X' diff --git a/tests/visual_tests/styles/shieldsymbolizer-4.xml b/tests/visual_tests/styles/shieldsymbolizer-4.xml index 3f078e2a2..f7311e88d 100644 --- a/tests/visual_tests/styles/shieldsymbolizer-4.xml +++ b/tests/visual_tests/styles/shieldsymbolizer-4.xml @@ -50,11 +50,14 @@ [nr] = '10' - 'X' + 'X' + + +