Support ShieldSymbolizer.

This commit is contained in:
Hermann Kraus 2012-08-17 18:31:55 +02:00
parent d8fad34aa3
commit a1f0af112e
9 changed files with 126 additions and 129 deletions

View file

@ -70,8 +70,6 @@ public:
/** Return all placements.*/ /** Return all placements.*/
placements_list const& get(); placements_list const& get();
marker_ptr get_marker() const;
agg::trans_affine const& get_image_transform() const;
protected: protected:
bool next_point_placement(); bool next_point_placement();
bool next_line_placement(); bool next_line_placement();
@ -104,8 +102,6 @@ protected:
placement_finder_ng finder_; placement_finder_ng finder_;
//ShieldSymbolizer only //ShieldSymbolizer only
marker_ptr marker_;
agg::trans_affine marker_transform_;
void init_marker(); void init_marker();
}; };

View file

@ -68,16 +68,24 @@ public:
bool next_position(); bool next_position();
placements_list const& placements() const; placements_list const& placements() const;
void set_marker(marker_info_ptr m, box2d<double> box, bool marker_unlocked, pixel_position const& marker_displacement);
private: private:
void init_alignment(); void init_alignment();
pixel_position alignment_offset() const; pixel_position alignment_offset() const;
double jalign_offset(double line_width) const; double jalign_offset(double line_width) const;
bool single_line_placement(vertex_cache &pp, text_upright_e orientation); 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); void path_move_dx(vertex_cache &pp);
/** Normalize angle in range [-pi, +pi]. */
static double normalize_angle(double angle); 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; double get_spacing(double path_length, double layout_width) const;
/** Checks for collision. */
bool collision(box2d<double> const& box) const; bool collision(box2d<double> 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<double> get_bbox(glyph_info const& glyph, pixel_position const& pos, rotation const& rot); box2d<double> get_bbox(glyph_info const& glyph, pixel_position const& pos, rotation const& rot);
Feature const& feature_; Feature const& feature_;
DetectorType &detector_; DetectorType &detector_;
@ -94,6 +102,13 @@ private:
double scale_factor_; double scale_factor_;
placements_list placements_; placements_list placements_;
//ShieldSymbolizer
bool has_marker_;
marker_info_ptr marker_;
box2d<double> marker_box_;
bool marker_unlocked_;
pixel_position marker_displacement_;
}; };
typedef boost::shared_ptr<placement_finder_ng> placement_finder_ng_ptr; typedef boost::shared_ptr<placement_finder_ng> placement_finder_ng_ptr;

View file

@ -26,6 +26,10 @@
#include <mapnik/pixel_position.hpp> #include <mapnik/pixel_position.hpp>
#include <mapnik/text/glyph_info.hpp> #include <mapnik/text/glyph_info.hpp>
#include <mapnik/text/rotation.hpp> #include <mapnik/text/rotation.hpp>
#include <mapnik/marker_cache.hpp>
// agg
#include "agg_trans_affine.h"
//stl //stl
#include <vector> #include <vector>
@ -45,9 +49,19 @@ struct glyph_position
rotation rot; 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> marker_info_ptr;
/** Stores positions of glphys. /** 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 class glyph_positions
{ {
@ -62,9 +76,14 @@ public:
pixel_position const& get_base_point() const; pixel_position const& get_base_point() const;
void set_base_point(pixel_position base_point); 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: private:
std::vector<glyph_position> data_; std::vector<glyph_position> data_;
pixel_position base_point_; pixel_position base_point_;
marker_info_ptr marker_;
pixel_position marker_pos_;
}; };
typedef boost::shared_ptr<glyph_positions> glyph_positions_ptr; typedef boost::shared_ptr<glyph_positions> glyph_positions_ptr;

View file

@ -22,15 +22,8 @@
// mapnik // mapnik
#include <mapnik/agg_renderer.hpp> #include <mapnik/agg_renderer.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/svg/svg_converter.hpp>
#include <mapnik/svg/svg_renderer.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/symbolizer_helpers.hpp> #include <mapnik/symbolizer_helpers.hpp>
#include <mapnik/text/renderer.hpp>
// boost
#include <boost/make_shared.hpp>
namespace mapnik { namespace mapnik {
@ -39,47 +32,25 @@ void agg_renderer<T>::process(shield_symbolizer const& sym,
mapnik::feature_impl & feature, mapnik::feature_impl & feature,
proj_transform const& prj_trans) proj_transform const& prj_trans)
{ {
#if 0 text_symbolizer_helper helper(
shield_symbolizer_helper<face_manager<freetype_engine>,
label_collision_detector4> helper(
sym, feature, prj_trans, sym, feature, prj_trans,
width_, height_, width_, height_,
scale_factor_, scale_factor_,
t_, font_manager_, *detector_, t_, font_manager_, *detector_,
query_extent_); query_extent_);
text_renderer<T> ren(*current_buffer_, agg_text_renderer<T> ren(*current_buffer_, *(font_manager_.get_stroker()), sym.comp_op(), scale_factor_);
font_manager_,
*(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(); if (glyphs->marker())
for (unsigned int ii = 0; ii < placements.size(); ++ii) render_marker(glyphs->marker_pos(),
{ *(glyphs->marker()->marker),
// get_marker_position returns (minx,miny) corner position, glyphs->marker()->transform,
// while (currently only) agg_renderer::render_marker newly sym.get_opacity(), sym.comp_op());
// expects center position; ren.render(glyphs);
// 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);
}
} }
#else
#warning AGG: ShieldSymbolizer disabled!
#endif
} }

View file

@ -21,15 +21,9 @@
*****************************************************************************/ *****************************************************************************/
// mapnik // mapnik
#include <mapnik/grid/grid_rasterizer.hpp>
#include <mapnik/grid/grid_renderer.hpp> #include <mapnik/grid/grid_renderer.hpp>
#include <mapnik/grid/grid_pixfmt.hpp>
#include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid.hpp>
#include <mapnik/symbolizer_helpers.hpp> #include <mapnik/symbolizer_helpers.hpp>
#include <mapnik/svg/svg_converter.hpp> #include <mapnik/text/renderer.hpp>
#include <mapnik/svg/svg_renderer.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
// agg // agg
#include "agg_trans_affine.h" #include "agg_trans_affine.h"
@ -41,54 +35,28 @@ void grid_renderer<T>::process(shield_symbolizer const& sym,
mapnik::feature_impl & feature, mapnik::feature_impl & feature,
proj_transform const& prj_trans) proj_transform const& prj_trans)
{ {
#if 0 text_symbolizer_helper helper(
shield_symbolizer_helper<face_manager<freetype_engine>,
label_collision_detector4> helper(
sym, feature, prj_trans, sym, feature, prj_trans,
width_, height_, width_, height_,
scale_factor_, scale_factor_ * (1.0/pixmap_.get_resolution()),
t_, font_manager_, *detector_, t_, font_manager_, *detector_,
query_extent_); query_extent_);
bool placement_found = false;
text_renderer<T> ren(pixmap_, grid_text_renderer<T> ren(pixmap_, *(font_manager_.get_stroker()), sym.comp_op(), scale_factor_);
font_manager_,
*(font_manager_.get_stroker()),
sym.comp_op(),
scale_factor_);
text_placement_info_ptr placement; placements_list const& placements = helper.get();
while (helper.next()) if (!placements.size()) return;
BOOST_FOREACH(glyph_positions_ptr glyphs, placements)
{ {
placement_found = true; if (glyphs->marker()->marker)
placements_type const& placements = helper.placements(); render_marker(feature, pixmap_.get_resolution(),
for (unsigned int ii = 0; ii < placements.size(); ++ii) glyphs->marker_pos(),
{ *(glyphs->marker()->marker),
// get_marker_position returns (minx,miny) corner position, glyphs->marker()->transform,
// while (currently only) agg_renderer::render_marker newly sym.get_opacity(), sym.comp_op());
// expects center position; ren.render(glyphs, feature.id(), 2);
// 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 (placement_found) pixmap_.add_feature(feature);
pixmap_.add_feature(feature);
#else
#warning GRID: TextSymbolizer disabled!
#endif
} }
template void grid_renderer<grid>::process(shield_symbolizer const&, template void grid_renderer<grid>::process(shield_symbolizer const&,

View file

@ -267,45 +267,34 @@ void text_symbolizer_helper::init_marker()
{ {
shield_symbolizer const& sym = static_cast<shield_symbolizer const&>(sym_); shield_symbolizer const& sym = static_cast<shield_symbolizer const&>(sym_);
std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature_); std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature_);
evaluate_transform(marker_transform_, feature_, sym.get_image_transform()); agg::trans_affine trans;
#if 0 evaluate_transform(trans, feature_, sym.get_image_transform());
marker_.reset(); boost::optional<marker_ptr> opt_marker; //TODO: Why boost::optional?
if (!filename.empty()) if (!filename.empty())
{ {
marker_ = marker_cache::instance()->find(filename, true); opt_marker = marker_cache::instance()->find(filename, true);
} }
if (!marker_) { marker_ptr m;
marker_size_.clear(); if (opt_marker) m = *opt_marker;
marker_ext_.init(0, 0, 0, 0); if (!m) return;
return; double width = m->width();
} double height = m->height();
marker_size_.set((*marker_)->width(), (*marker_)->height()); double px0 = - 0.5 * width;
double px0 = - 0.5 * marker_size_.x; double py0 = - 0.5 * height;
double py0 = - 0.5 * marker_size_.y; double px1 = 0.5 * width;
double px1 = 0.5 * marker_size_.x; double py1 = 0.5 * height;
double py1 = 0.5 * marker_size_.y;
double px2 = px1; double px2 = px1;
double py2 = py0; double py2 = py0;
double px3 = px0; double px3 = px0;
double py3 = py1; double py3 = py1;
marker_transform_.transform(&px0,&py0); trans.transform(&px0, &py0);
marker_transform_.transform(&px1,&py1); trans.transform(&px1, &py1);
marker_transform_.transform(&px2,&py2); trans.transform(&px2, &py2);
marker_transform_.transform(&px3,&py3); trans.transform(&px3, &py3);
marker_ext_.init(px0, py0, px1, py1); box2d<double> bbox(px0, py0, px1, py1);
marker_ext_.expand_to_include(px2, py2); bbox.expand_to_include(px2, py2);
marker_ext_.expand_to_include(px3, py3); bbox.expand_to_include(px3, py3);
#endif finder_.set_marker(boost::make_shared<marker_info>(m, trans), bbox, sym.get_unlock_image(), sym.get_shield_displacement());
}
marker_ptr text_symbolizer_helper::get_marker() const
{
return marker_;
}
agg::trans_affine const& text_symbolizer_helper::get_image_transform() const
{
return marker_transform_;
} }
template text_symbolizer_helper::text_symbolizer_helper(const text_symbolizer &sym, const Feature &feature, template text_symbolizer_helper::text_symbolizer_helper(const text_symbolizer &sym, const Feature &feature,

View file

@ -43,7 +43,7 @@ namespace mapnik
{ {
placement_finder_ng::placement_finder_ng(Feature const& feature, DetectorType &detector, box2d<double> const& extent, text_placement_info_ptr placement_info, face_manager_freetype &font_manager, double scale_factor) placement_finder_ng::placement_finder_ng(Feature const& feature, DetectorType &detector, box2d<double> 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_; return placements_;
} }
void placement_finder_ng::init_alignment() void placement_finder_ng::init_alignment()
{ {
text_symbolizer_properties const& p = info_->properties; 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()); rotated_box2d(bbox, orientation_, layout_.width(), layout_.height());
bbox.re_center(glyphs->get_base_point().x, glyphs->get_base_point().y); bbox.re_center(glyphs->get_base_point().x, glyphs->get_base_point().y);
if (collision(bbox)) return false; if (collision(bbox)) return false;
if (has_marker_ && !add_marker(glyphs, pos)) return false;
detector_.insert(bbox, layout_.get_text()); detector_.insert(bbox, layout_.get_text());
/* IMPORTANT NOTE: /* IMPORTANT NOTE:
@ -438,6 +437,27 @@ bool placement_finder_ng::collision(const box2d<double> &box) const
return false; return false;
} }
void placement_finder_ng::set_marker(marker_info_ptr m, box2d<double> 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<double> 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<double> placement_finder_ng::get_bbox(glyph_info const& glyph, pixel_position const& pos, rotation const& rot) box2d<double> 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; 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<geometry_type> clipped_geometry_type; typedef agg::conv_clip_polyline<geometry_type> clipped_geometry_type;

View file

@ -50,7 +50,7 @@
</Rule> </Rule>
<Rule> <Rule>
<Filter>[nr] = '10'</Filter> <Filter>[nr] = '10'</Filter>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../../data/images/crosshair16x16.png" unlock-image="false" shield-dx="15">'X'</ShieldSymbolizer> <ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../../data/images/crosshair16x16.png" unlock-image="false" shield-dx="15" dy="20">'X'</ShieldSymbolizer>
</Rule> </Rule>
<Rule> <Rule>
<PointSymbolizer allow-overlap="true" file="../../data/raster/white-alpha.png"/> <PointSymbolizer allow-overlap="true" file="../../data/raster/white-alpha.png"/>

View file

@ -50,11 +50,14 @@
</Rule> </Rule>
<Rule> <Rule>
<Filter>[nr] = '10'</Filter> <Filter>[nr] = '10'</Filter>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../../data/images/crosshair16x16.png" unlock-image="true" shield-dx="15">'X'</ShieldSymbolizer> <ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../../data/images/crosshair16x16.png" unlock-image="true" shield-dx="15" dy="20">'X'</ShieldSymbolizer>
</Rule> </Rule>
<Rule> <Rule>
<PointSymbolizer allow-overlap="true" file="../../data/raster/white-alpha.png"/> <PointSymbolizer allow-overlap="true" file="../../data/raster/white-alpha.png"/>
</Rule> </Rule>
<Rule>
<DebugSymbolizer />
</Rule>
</Style> </Style>
</Map> </Map>