markers: support offset, geometry-transform, and simplify - closes #2108

This commit is contained in:
Dane Springmeyer 2014-09-06 21:27:15 -07:00
parent bb0df1d6c6
commit 54b2880e53
11 changed files with 162 additions and 130 deletions

View file

@ -54,6 +54,8 @@ namespace agg
m_trans = &tr; m_trans = &tr;
} }
unsigned type() const { return m_source->type(); }
private: private:
conv_transform(const conv_transform<VertexSource>&); conv_transform(const conv_transform<VertexSource>&);
const conv_transform<VertexSource>& const conv_transform<VertexSource>&

View file

@ -64,6 +64,11 @@ struct MAPNIK_DECL offset_converter
process process
}; };
unsigned type() const
{
return static_cast<unsigned>(geom_.type());
}
double get_offset() const double get_offset() const
{ {
return offset_; return offset_;

View file

@ -49,11 +49,18 @@ void render_markers_symbolizer(markers_symbolizer const& sym,
using raster_dispatch_type = T1; using raster_dispatch_type = T1;
using renderer_context_type = T2; using renderer_context_type = T2;
using conv_types = boost::mpl::vector<clip_poly_tag,transform_tag,smooth_tag>;
using svg_attribute_type = agg::pod_bvector<path_attributes>; using svg_attribute_type = agg::pod_bvector<path_attributes>;
using conv_types = boost::mpl::vector<clip_line_tag,
clip_poly_tag,
transform_tag,
affine_transform_tag,
simplify_tag, smooth_tag,
offset_transform_tag>;
std::string filename = get<std::string>(sym, keys::file, feature, common.vars_, "shape://ellipse"); std::string filename = get<std::string>(sym, keys::file, feature, common.vars_, "shape://ellipse");
bool clip = get<value_bool>(sym, keys::clip, feature, common.vars_, false); bool clip = get<value_bool>(sym, keys::clip, feature, common.vars_, false);
double offset = get<value_double>(sym, keys::offset, feature, common.vars_, 0.0);
double simplify_tolerance = get<value_double>(sym, keys::simplify_tolerance, feature, common.vars_, 0.0);
double smooth = get<value_double>(sym, keys::smooth, feature, common.vars_, false); double smooth = get<value_double>(sym, keys::smooth, feature, common.vars_, false);
// https://github.com/mapnik/mapnik/issues/1316 // https://github.com/mapnik/mapnik/issues/1316
@ -63,7 +70,10 @@ void render_markers_symbolizer(markers_symbolizer const& sym,
boost::optional<marker_ptr> mark = mapnik::marker_cache::instance().find(filename, true); boost::optional<marker_ptr> mark = mapnik::marker_cache::instance().find(filename, true);
if (mark && *mark) if (mark && *mark)
{ {
agg::trans_affine tr = agg::trans_affine_scaling(common.scale_factor_); agg::trans_affine geom_tr;
auto transform = get_optional<transform_type>(sym, keys::geometry_transform);
if (transform) evaluate_transform(geom_tr, feature, common.vars_, *transform, common.scale_factor_);
agg::trans_affine image_tr = agg::trans_affine_scaling(common.scale_factor_);
if ((*mark)->is_vector()) if ((*mark)->is_vector())
{ {
@ -84,12 +94,12 @@ void render_markers_symbolizer(markers_symbolizer const& sym,
svg_attribute_type attributes; svg_attribute_type attributes;
bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym, feature, common.vars_); bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym, feature, common.vars_);
auto image_transform = get_optional<transform_type>(sym, keys::image_transform); auto image_transform = get_optional<transform_type>(sym, keys::image_transform);
if (image_transform) evaluate_transform(tr, feature, common.vars_, *image_transform); if (image_transform) evaluate_transform(image_tr, feature, common.vars_, *image_transform);
box2d<double> bbox = marker_ellipse.bounding_box(); box2d<double> bbox = marker_ellipse.bounding_box();
vector_dispatch_type rasterizer_dispatch(svg_path, vector_dispatch_type rasterizer_dispatch(svg_path,
result ? attributes : (*stock_vector_marker)->attributes(), result ? attributes : (*stock_vector_marker)->attributes(),
bbox, bbox,
tr, image_tr,
sym, sym,
*common.detector_, *common.detector_,
common.scale_factor_, common.scale_factor_,
@ -100,27 +110,28 @@ void render_markers_symbolizer(markers_symbolizer const& sym,
vertex_converter<box2d<double>, vector_dispatch_type, markers_symbolizer, vertex_converter<box2d<double>, vector_dispatch_type, markers_symbolizer,
view_transform, proj_transform, agg::trans_affine, conv_types, feature_impl> view_transform, proj_transform, agg::trans_affine, conv_types, feature_impl>
converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,tr,feature,common.vars_,common.scale_factor_); converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true) if (clip && feature.paths().size() > 0) // optional clip (default: true)
{ {
geometry_type::types type = feature.paths()[0].type(); geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon) if (type == geometry_type::types::Polygon)
converter.template set<clip_poly_tag>(); converter.template set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 else if (type == geometry_type::types::LineString)
//else if (type == LineString) converter.template set<clip_line_tag>();
// converter.template set<clip_line_tag>();
// don't clip if type==Point
} }
converter.template set<transform_tag>(); //always transform converter.template set<transform_tag>(); //always transform
if (std::fabs(offset) > 0.0) converter.template set<offset_transform_tag>(); // parallel offset
converter.template set<affine_transform_tag>(); // optional affine transform
if (simplify_tolerance > 0.0) converter.template set<simplify_tag>(); // optional simplify converter
if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, common.vars_, converter, sym); apply_markers_multi(feature, common.vars_, converter, sym);
} }
else else
{ {
box2d<double> const& bbox = (*mark)->bounding_box(); box2d<double> const& bbox = (*mark)->bounding_box();
setup_transform_scaling(tr, bbox.width(), bbox.height(), feature, common.vars_, sym); setup_transform_scaling(image_tr, bbox.width(), bbox.height(), feature, common.vars_, sym);
auto image_transform = get_optional<transform_type>(sym, keys::image_transform); auto image_transform = get_optional<transform_type>(sym, keys::image_transform);
if (image_transform) evaluate_transform(tr, feature, common.vars_, *image_transform); if (image_transform) evaluate_transform(image_tr, feature, common.vars_, *image_transform);
vertex_stl_adapter<svg_path_storage> stl_storage((*stock_vector_marker)->source()); vertex_stl_adapter<svg_path_storage> stl_storage((*stock_vector_marker)->source());
svg_path_adapter svg_path(stl_storage); svg_path_adapter svg_path(stl_storage);
svg_attribute_type attributes; svg_attribute_type attributes;
@ -128,7 +139,7 @@ void render_markers_symbolizer(markers_symbolizer const& sym,
vector_dispatch_type rasterizer_dispatch(svg_path, vector_dispatch_type rasterizer_dispatch(svg_path,
result ? attributes : (*stock_vector_marker)->attributes(), result ? attributes : (*stock_vector_marker)->attributes(),
bbox, bbox,
tr, image_tr,
sym, sym,
*common.detector_, *common.detector_,
common.scale_factor_, common.scale_factor_,
@ -139,33 +150,34 @@ void render_markers_symbolizer(markers_symbolizer const& sym,
vertex_converter<box2d<double>, vector_dispatch_type, markers_symbolizer, vertex_converter<box2d<double>, vector_dispatch_type, markers_symbolizer,
view_transform, proj_transform, agg::trans_affine, conv_types, feature_impl> view_transform, proj_transform, agg::trans_affine, conv_types, feature_impl>
converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,tr,feature,common.vars_,common.scale_factor_); converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true) if (clip && feature.paths().size() > 0) // optional clip (default: true)
{ {
geometry_type::types type = feature.paths()[0].type(); geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon) if (type == geometry_type::types::Polygon)
converter.template set<clip_poly_tag>(); converter.template set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 else if (type == geometry_type::types::LineString)
//else if (type == LineString) converter.template set<clip_line_tag>();
// converter.template set<clip_line_tag>();
// don't clip if type==Point
} }
converter.template set<transform_tag>(); //always transform converter.template set<transform_tag>(); //always transform
if (std::fabs(offset) > 0.0) converter.template set<offset_transform_tag>(); // parallel offset
converter.template set<affine_transform_tag>(); // optional affine transform
if (simplify_tolerance > 0.0) converter.template set<simplify_tag>(); // optional simplify converter
if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, common.vars_, converter, sym); apply_markers_multi(feature, common.vars_, converter, sym);
} }
} }
else // raster markers else // raster markers
{ {
setup_transform_scaling(tr, (*mark)->width(), (*mark)->height(), feature, common.vars_, sym); setup_transform_scaling(image_tr, (*mark)->width(), (*mark)->height(), feature, common.vars_, sym);
auto image_transform = get_optional<transform_type>(sym, keys::image_transform); auto image_transform = get_optional<transform_type>(sym, keys::image_transform);
if (image_transform) evaluate_transform(tr, feature, common.vars_, *image_transform); if (image_transform) evaluate_transform(image_tr, feature, common.vars_, *image_transform);
box2d<double> const& bbox = (*mark)->bounding_box(); box2d<double> const& bbox = (*mark)->bounding_box();
boost::optional<mapnik::image_ptr> marker = (*mark)->get_bitmap_data(); boost::optional<mapnik::image_ptr> marker = (*mark)->get_bitmap_data();
// - clamp sizes to > 4 pixels of interactivity // - clamp sizes to > 4 pixels of interactivity
coord2d center = bbox.center(); coord2d center = bbox.center();
agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine_translation recenter(-center.x, -center.y);
agg::trans_affine marker_trans = recenter * tr; agg::trans_affine marker_trans = recenter * image_tr;
raster_dispatch_type rasterizer_dispatch(**marker, raster_dispatch_type rasterizer_dispatch(**marker,
marker_trans, marker_trans,
sym, sym,
@ -177,19 +189,20 @@ void render_markers_symbolizer(markers_symbolizer const& sym,
vertex_converter<box2d<double>, raster_dispatch_type, markers_symbolizer, vertex_converter<box2d<double>, raster_dispatch_type, markers_symbolizer,
view_transform, proj_transform, agg::trans_affine, conv_types, feature_impl> view_transform, proj_transform, agg::trans_affine, conv_types, feature_impl>
converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,tr,feature,common.vars_,common.scale_factor_); converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true) if (clip && feature.paths().size() > 0) // optional clip (default: true)
{ {
geometry_type::types type = feature.paths()[0].type(); geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon) if (type == geometry_type::types::Polygon)
converter.template set<clip_poly_tag>(); converter.template set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 else if (type == geometry_type::types::LineString)
//else if (type == geometry_type::types::LineString) converter.template set<clip_line_tag>();
// converter.template set<clip_line_tag>();
// don't clip if type==geometry_type::types::Point
} }
converter.template set<transform_tag>(); //always transform converter.template set<transform_tag>(); //always transform
if (std::fabs(offset) > 0.0) converter.template set<offset_transform_tag>(); // parallel offset
converter.template set<affine_transform_tag>(); // optional affine transform
if (simplify_tolerance > 0.0) converter.template set<simplify_tag>(); // optional simplify converter
if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, common.vars_, converter, sym); apply_markers_multi(feature, common.vars_, converter, sym);
} }

View file

@ -109,6 +109,11 @@ public:
cache cache
}; };
unsigned type() const
{
return static_cast<unsigned>(geom_.type());
}
simplify_algorithm_e get_simplify_algorithm() simplify_algorithm_e get_simplify_algorithm()
{ {
return algorithm_; return algorithm_;

View file

@ -969,6 +969,8 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
set_symbolizer_property<markers_symbolizer,boolean_type>(sym, keys::avoid_edges, node); set_symbolizer_property<markers_symbolizer,boolean_type>(sym, keys::avoid_edges, node);
// ignore-placement // ignore-placement
set_symbolizer_property<markers_symbolizer,boolean_type>(sym, keys::ignore_placement, node); set_symbolizer_property<markers_symbolizer,boolean_type>(sym, keys::ignore_placement, node);
// offset
set_symbolizer_property<symbolizer_base,double>(sym, keys::offset, node);
// width // width
//set_symbolizer_property<markers_symbolizer,double>(sym, keys::width, node); //set_symbolizer_property<markers_symbolizer,double>(sym, keys::width, node);
// height // height
@ -1025,8 +1027,7 @@ void map_parser::parse_line_pattern_symbolizer(rule & rule, xml_node const & nod
set_symbolizer_property<line_pattern_symbolizer,double>(sym, keys::opacity, node); set_symbolizer_property<line_pattern_symbolizer,double>(sym, keys::opacity, node);
// offset value // offset value
optional<double> offset = node.get_opt_attr<double>("offset"); set_symbolizer_property<symbolizer_base,double>(sym, keys::offset, node);
if (offset) put(sym, keys::offset, *offset);
// image transform // image transform
set_symbolizer_property<line_pattern_symbolizer, transform_type>(sym, keys::image_transform, node); set_symbolizer_property<line_pattern_symbolizer, transform_type>(sym, keys::image_transform, node);
rule.append(std::move(sym)); rule.append(std::move(sym));

View file

@ -5,105 +5,105 @@
], ],
"data": {}, "data": {},
"grid": [ "grid": [
" !!! ", " !!!!!! ",
" !!! ", " ! !! !!!! !! ",
" !!!! ", " ! ! !!! ! ! ",
" ! ! ", " ! ! !! ! !!! ",
" ! ", " ! ! !!! ! !! ",
" ! ! ", " ! ! ! ! ! ",
" ! ", " ! ! ! ! !! ",
" ! ! ", " ! ! ! ! ! ! ",
" ! ", " ! ! ! ! ",
" ! ! ", " ! ! ! !!! ! !! ",
" ! ", " !! ! !!! !! ",
" ! ! ", " ! !! ! ! ! ",
" ! ", " ! ! ! !! ",
" ! ! ", " ! ! ! ! ! !!! ",
" ! ", " ! ! ! ! !!! ",
" ! ! ", " ! ! ! ! ! ! !! ! ",
" ! ", " ! ! ! ! !!! ",
" ! ! ", " !! ! ! ! ! ! !!! ",
" ! ", " !! ! ! ! !! ! ",
" ! ! ", " ! !! ! ! !!! ! ",
" ! ", " ! !!!!! ! !! ! ",
" !! ! ", " !! !! ! ! ! ",
" !! !!! ", " ! ! ! !! !! ! ",
" ! !!! ", " ! ! !!! ! ! ",
" ! !! ", " ! ! ! ! ",
" ! ! ", " ! ! ! ! ! ",
" ! ", " ! ! ! ! ! ! ",
" ! ! ", " ! ! ! ",
" ! ", " ! ! ! ! ! ",
" ! ! ", " ! ! ! ! ! ",
" ! ", " ! ! ! ! ! ",
" ! ! ", " ! ! !! ! ! ",
" ! ", " ! ! ! ! !!! ! ! ! ",
" ! ! ", " ! ! ! !! ! ! ",
" ! ", " ! ! ! ! ",
" ! ! ", " ! ! ! ! ! ! ",
" ! ", " ! ! !!! ",
" ! ! ", " ! ! ! ! !!!! ",
" ! ", " ! ! !!! ! ",
" ! ! ", " !! ! ! ! !!!! ",
" ! ", " !!! ! ! !!!!! ",
" ! ! ", " !! !!! ! ! !! ",
" ! ", " ! !!!!!! ! !!! ",
" !! ! ", " !!!!! !! !!!! ! ",
" !!! ! ", " ! ! ! !!! ! ! ",
" !! !!! ", " ! ! ! !! !!!! ",
" ! !!! ", " ! ! ! !!!!! ! ",
" ! ! ", " ! ! ! ! ! ",
" ! ", " ! ! ! ! ! ! ",
" ! ! ", " ! ! ! ! ",
" ! ", " ! ! ! ! ! ",
" ! ! ", " ! ! ! !! ! ",
" ! ", " ! ! ! ",
" ! ! ", " ! ! ! !! ",
" ! ", " ! ! !! ! ",
" ! ! ", " ! ! ! !!!! ",
" ! ", " ! ! ! ! ",
" ! ! ", " !! ! ! ! ",
" ! ", " ! ! ! !! ",
" ! ! ", " ! ! ! ! ",
" ! ", " !! ! !! ",
" ! ! ", " ! ! !!!! ",
" ! ", " ! !! ! !!! ",
" ! ! ", " !! !! ! !!!! ",
" ! ", " !! !!! ! !!!! ",
" !! ! ", " !! !!! !! !!! ",
" !!! ", " ! !!! !!! !! ",
" !!! !!! ", " !!! !!! !!!! ",
" ! !!! ", " ! ! ! !!! ",
" ! ! ", " ! ! ! ! ! ",
" ! ", " ! ! ! ! ",
" ! ! ", " ! ! !! ",
" ! ", " ! ! ! ! ",
" ! ! ", " ! ! !! ",
" ! ", " ! !! ",
" ! ! ! ", " ! ! ! ! !! !! ",
" ! ! ", " ! ! ! !!! !!! ",
" ! ! ! ", " ! ! ! !!! !!! ",
" ! ! ", " ! ! ! ! !!! ",
" ! ! ! ", " ! ! ! !! ! ! ! ",
" ! ! ", " !!! ! ! ! !! ",
" ! ! ! ", " ! !! ! ! !! ! ",
" ! ! ", " ! !!! ! ! ! !!! ",
" ! ! ! ", " ! !!! !! ! ! !!! ! ",
" ! ! ", " ! !!!! ! ! !! ",
" ! ! ! ", " ! ! ! !!! ! !! ! ! !!! ",
" ! ! ", " ! ! !!!! !!! ! ! !!! ",
" ! ! ! ", " !!! ! !!!! !!! ! ! ",
" !!! ! ", " !!!!! !! ! ! ",
" !!! !! !! ", " !!!!! !! !! !! ! ! ! ",
" !! !! !!! ", " !!!!! !!! !!! ! ! ! ",
" ! !! !!! ", " !!!! !!!! !!! ! ! ! ",
" ! ! ", " ! !! ! ! ! ! ",
" ! ! ! ", " !!! ! ! ! ! ",
" ! ! ", " !! ! ! ! !!! ! ",
" ! ! ! ", " !! ! !!! ! !! ! ! ",
" ! ! ", " ! ! ! !! ! ",
" ! ! ! ", " !! ! !! ! ! ! ! ",
" ! ! ", " ! ! !! ! ! ! ! ",
" ! !! " " ! ! !!! ! ! ! "
] ]
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -1,13 +1,19 @@
<Map> <Map>
<Style name="line" filter-mode="first" > <Style name="line" filter-mode="first" >
<Rule> <Rule>
<LineSymbolizer stroke="#000000" /> <LineSymbolizer stroke="red"/>
<LineSymbolizer stroke="blue" smooth=".5"/>
<LineSymbolizer stroke="orange" smooth="1"/>
<LineSymbolizer stroke="green" smooth="1" geometry-transform="translate(10,10)" />
</Rule> </Rule>
</Style> </Style>
<Style name="point-placement" filter-mode="first" > <Style name="point-placement" filter-mode="first" >
<Rule> <Rule>
<MarkersSymbolizer allow-overlap="false" ignore-placement="true" placement="line" marker-type="ellipse" fill="blue" /> <MarkersSymbolizer stroke-width="0" allow-overlap="true" placement="line" marker-type="ellipse" fill="red" />
<DebugSymbolizer /> <MarkersSymbolizer stroke-width="0" offset="-10" transform="translate(0,-10)" allow-overlap="true" placement="line" marker-type="ellipse" fill="darkred" />
<MarkersSymbolizer stroke-width="0" allow-overlap="true" smooth=".5" transform="translate(10,10) translate(-10,-10)" placement="line" marker-type="ellipse" fill="blue" />
<MarkersSymbolizer stroke-width="0" allow-overlap="true" smooth="1" placement="line" marker-type="ellipse" fill="orange" />
<MarkersSymbolizer stroke-width="0" allow-overlap="true" smooth="1" geometry-transform="translate(10,10)" placement="line" marker-type="ellipse" fill="darkgreen" />
</Rule> </Rule>
</Style> </Style>
<Layer name="carto_tests"> <Layer name="carto_tests">