diff --git a/bindings/python/mapnik_line_symbolizer.cpp b/bindings/python/mapnik_line_symbolizer.cpp index f1ac4c419..e7c9a58be 100644 --- a/bindings/python/mapnik_line_symbolizer.cpp +++ b/bindings/python/mapnik_line_symbolizer.cpp @@ -42,12 +42,19 @@ struct line_symbolizer_pickle_suite : boost::python::pickle_suite void export_line_symbolizer() { using namespace boost::python; - + enumeration_("line_rasterizer") + .value("FULL",RASTERIZER_FULL) + .value("FAST",RASTERIZER_FAST) + ; class_("LineSymbolizer", init<>("Default LineSymbolizer - 1px solid black")) .def(init("TODO")) .def(init()) .def_pickle(line_symbolizer_pickle_suite()) + .add_property("rasterizer", + &line_symbolizer::get_rasterizer, + &line_symbolizer::set_rasterizer, + "Set/get the rasterization method of the line of the point") .add_property("stroke",make_function (&line_symbolizer::get_stroke, return_value_policy()), diff --git a/include/mapnik/agg_helpers.hpp b/include/mapnik/agg_helpers.hpp index f02eea19a..938e219bb 100644 --- a/include/mapnik/agg_helpers.hpp +++ b/include/mapnik/agg_helpers.hpp @@ -32,6 +32,7 @@ #include "agg_scanline_p.h" #include "agg_renderer_outline_aa.h" #include "agg_renderer_scanline.h" +#include "agg_rasterizer_outline_aa.h" namespace mapnik { @@ -94,6 +95,40 @@ void set_join_caps(Stroke const& stroke_, PathType & stroke) } +template +void set_join_caps_aa(Stroke const& stroke_, Rasterizer & ras) +{ + + line_join_e join=stroke_.get_line_join(); + switch (join) + { + case MITER_JOIN: + ras.line_join(agg::outline_miter_accurate_join); + break; + case MITER_REVERT_JOIN: + ras.line_join(agg::outline_no_join); + break; + case ROUND_JOIN: + ras.line_join(agg::outline_round_join); + break; + default: + ras.line_join(agg::outline_no_join); + } + + line_cap_e cap=stroke_.get_line_cap(); + switch (cap) + { + case BUTT_CAP: + ras.round_cap(false); + break; + case SQUARE_CAP: + ras.round_cap(false); + break; + default: + ras.round_cap(true); + } +} + template struct renderer_scanline_solid : private boost::noncopyable { diff --git a/include/mapnik/line_symbolizer.hpp b/include/mapnik/line_symbolizer.hpp index 0c089c937..f0cd81d36 100644 --- a/include/mapnik/line_symbolizer.hpp +++ b/include/mapnik/line_symbolizer.hpp @@ -31,24 +31,36 @@ namespace mapnik { +enum line_rasterizer_enum { + RASTERIZER_FULL, // agg::renderer_scanline_aa_solid + RASTERIZER_FAST, // agg::rasterizer_outline_aa, twice as fast but only good for thin lines + line_rasterizer_enum_MAX +}; + +DEFINE_ENUM( line_rasterizer_e, line_rasterizer_enum ); + + struct MAPNIK_DECL line_symbolizer : public symbolizer_base { explicit line_symbolizer() : symbolizer_base(), stroke_(), - offset_(0.0) + offset_(0.0), + rasterizer_p_(RASTERIZER_FULL) {} line_symbolizer(stroke const& stroke) : symbolizer_base(), stroke_(stroke), - offset_(0.0) + offset_(0.0), + rasterizer_p_(RASTERIZER_FULL) {} line_symbolizer(color const& pen,float width=1.0) : symbolizer_base(), stroke_(pen,width), - offset_(0.0) + offset_(0.0), + rasterizer_p_(RASTERIZER_FULL) {} stroke const& get_stroke() const @@ -70,10 +82,21 @@ struct MAPNIK_DECL line_symbolizer : public symbolizer_base { return offset_; } - + + void set_rasterizer(line_rasterizer_e rasterizer_p) + { + rasterizer_p_ = rasterizer_p; + } + + line_rasterizer_e get_rasterizer() const + { + return rasterizer_p_; + } + private: stroke stroke_; double offset_; + line_rasterizer_e rasterizer_p_; }; } diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index 59b0d9ba4..32924a998 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -63,45 +63,81 @@ void agg_renderer::process(line_symbolizer const& sym, ras_ptr->reset(); set_gamma_method(stroke_, ras_ptr); - - typedef boost::mpl::vector conv_types; - vertex_converter,rasterizer,line_symbolizer, proj_transform, CoordTransform,conv_types> - converter(query_extent_,*ras_ptr,sym,t_,prj_trans,scale_factor_); - - if (sym.clip()) converter.set(); // optional clip (default: true) - converter.set(); // always transform - - if (fabs(sym.offset()) > 0.0) converter.set(); // parallel offset - converter.set(); // optional affine transform - if (sym.smooth() > 0.0) converter.set(); // optional smooth converter - if (stroke_.has_dash()) converter.set(); - converter.set(); //always stroke - - BOOST_FOREACH( geometry_type & geom, feature->paths()) - { - if (geom.num_points() > 1) - { - converter.apply(geom); - } - } agg::rendering_buffer buf(current_buffer_->raw_data(),width_,height_, width_ * 4); - typedef agg::rgba8 color_type; typedef agg::order_rgba order_type; typedef agg::pixel32_type pixel_type; typedef agg::comp_op_adaptor_rgba blender_type; // comp blender typedef agg::pixfmt_custom_blend_rgba pixfmt_comp_type; typedef agg::renderer_base renderer_base; - typedef agg::renderer_scanline_aa_solid renderer_type; + pixfmt_comp_type pixf(buf); - pixf.comp_op(static_cast(sym.comp_op())); renderer_base renb(pixf); - renderer_type ren(renb); - ren.color(agg::rgba8(r, g, b, int(a * stroke_.get_opacity()))); - agg::scanline_u8 sl; - agg::render_scanlines(*ras_ptr, sl, ren); + + if (sym.get_rasterizer() == RASTERIZER_FAST) + { + typedef agg::renderer_outline_aa renderer_type; + typedef agg::rasterizer_outline_aa rasterizer_type; + // need to reduce width by half to match standard rasterizer look + double scaled = scale_factor_ * .5; + agg::line_profile_aa profile(stroke_.get_width() * scaled, agg::gamma_power(stroke_.get_gamma())); + renderer_type ren(renb, profile); + ren.color(agg::rgba8(r, g, b, int(a*stroke_.get_opacity()))); + rasterizer_type ras(ren); + set_join_caps_aa(stroke_,ras); + + typedef boost::mpl::vector conv_types; + vertex_converter,rasterizer_type,line_symbolizer, proj_transform, CoordTransform,conv_types> + converter(query_extent_,ras,sym,t_,prj_trans,scaled); + + if (sym.clip()) converter.set(); // optional clip (default: true) + converter.set(); // always transform + if (fabs(sym.offset()) > 0.0) converter.set(); // parallel offset + converter.set(); // optional affine transform + if (sym.smooth() > 0.0) converter.set(); // optional smooth converter + if (stroke_.has_dash()) converter.set(); + converter.set(); //always stroke + + BOOST_FOREACH( geometry_type & geom, feature->paths()) + { + if (geom.num_points() > 1) + { + converter.apply(geom); + } + } + } + else + { + typedef boost::mpl::vector conv_types; + vertex_converter,rasterizer,line_symbolizer, proj_transform, CoordTransform,conv_types> + converter(query_extent_,*ras_ptr,sym,t_,prj_trans,scale_factor_); + + if (sym.clip()) converter.set(); // optional clip (default: true) + converter.set(); // always transform + if (fabs(sym.offset()) > 0.0) converter.set(); // parallel offset + converter.set(); // optional affine transform + if (sym.smooth() > 0.0) converter.set(); // optional smooth converter + if (stroke_.has_dash()) converter.set(); + converter.set(); //always stroke + + BOOST_FOREACH( geometry_type & geom, feature->paths()) + { + if (geom.num_points() > 1) + { + converter.apply(geom); + } + } + + typedef agg::renderer_scanline_aa_solid renderer_type; + pixf.comp_op(static_cast(sym.comp_op())); + renderer_base renb(pixf); + renderer_type ren(renb); + ren.color(agg::rgba8(r, g, b, int(a * stroke_.get_opacity()))); + agg::scanline_u8 sl; + agg::render_scanlines(*ras_ptr, sl, ren); + } } diff --git a/src/line_symbolizer.cpp b/src/line_symbolizer.cpp index 97cc2cc1a..6f71f8b7a 100644 --- a/src/line_symbolizer.cpp +++ b/src/line_symbolizer.cpp @@ -26,6 +26,13 @@ namespace mapnik { -// + +static const char * line_rasterizer_strings[] = { + "full", + "fast", + "" +}; +IMPLEMENT_ENUM( line_rasterizer_e, line_rasterizer_strings ) + } diff --git a/src/load_map.cpp b/src/load_map.cpp index 6d03e7f17..9b7ef148f 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -1430,7 +1430,10 @@ void map_parser::parse_line_symbolizer(rule & rule, xml_node const & sym) // offset value optional offset = sym.get_opt_attr("offset"); if (offset) symbol.set_offset(*offset); - + + line_rasterizer_e rasterizer = sym.get_attr("rasterizer", RASTERIZER_FULL); + symbol.set_rasterizer(rasterizer); + // meta-writer parse_symbolizer_base(symbol, sym); rule.append(symbol); diff --git a/src/save_map.cpp b/src/save_map.cpp index 1f328a53c..6b30aa03d 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -84,6 +84,12 @@ public: const stroke & strk = sym.get_stroke(); add_stroke_attributes(sym_node, strk); add_metawriter_attributes(sym_node, sym); + + line_symbolizer dfl; + if ( sym.get_rasterizer() != dfl.get_rasterizer() || explicit_defaults_ ) + { + set_attr( sym_node, "rasterizer", sym.get_rasterizer() ); + } } void operator () ( line_pattern_symbolizer const& sym ) diff --git a/src/xml_tree.cpp b/src/xml_tree.cpp index 8769dc941..4d4593681 100644 --- a/src/xml_tree.cpp +++ b/src/xml_tree.cpp @@ -475,6 +475,7 @@ compile_get_attr(point_placement_e); compile_get_attr(marker_placement_e); compile_get_attr(marker_type_e); compile_get_attr(pattern_alignment_e); +compile_get_attr(line_rasterizer_e); compile_get_attr(colorizer_mode); compile_get_attr(double); compile_get_value(int);