diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index 707fbf2ab..a7031621c 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -48,6 +48,7 @@ #include "agg_image_accessors.h" #include "agg_pixfmt_rgba.h" #include "agg_span_image_filter_rgba.h" +#include "agg_span_interpolator_linear.h" // boost #include @@ -69,7 +70,8 @@ struct vector_markers_rasterizer_dispatch agg::trans_affine const& marker_trans, markers_symbolizer const& sym, Detector & detector, - double scale_factor) + double scale_factor, + bool snap_to_pixels) : buf_(render_buffer), pixf_(buf_), renb_(pixf_), @@ -79,7 +81,8 @@ struct vector_markers_rasterizer_dispatch marker_trans_(marker_trans), sym_(sym), detector_(detector), - scale_factor_(scale_factor) + scale_factor_(scale_factor), + snap_to_pixels_(snap_to_pixels) { pixf_.comp_op(static_cast(sym_.comp_op())); } @@ -116,6 +119,12 @@ struct vector_markers_rasterizer_dispatch if (sym_.get_allow_overlap() || detector_.has_placement(transformed_bbox)) { + if (snap_to_pixels_) + { + // https://github.com/mapnik/mapnik/issues/1316 + matrix.tx = std::floor(matrix.tx+.5); + matrix.ty = std::floor(matrix.ty+.5); + } svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_); if (!sym_.get_ignore_placement()) { @@ -153,6 +162,7 @@ private: markers_symbolizer const& sym_; Detector & detector_; double scale_factor_; + bool snap_to_pixels_; }; template @@ -171,7 +181,8 @@ struct raster_markers_rasterizer_dispatch agg::trans_affine const& marker_trans, markers_symbolizer const& sym, Detector & detector, - double scale_factor) + double scale_factor, + bool snap_to_pixels) : buf_(render_buffer), pixf_(buf_), renb_(pixf_), @@ -180,7 +191,8 @@ struct raster_markers_rasterizer_dispatch marker_trans_(marker_trans), sym_(sym), detector_(detector), - scale_factor_(scale_factor) + scale_factor_(scale_factor), + snap_to_pixels_(snap_to_pixels) { pixf_.comp_op(static_cast(sym_.comp_op())); } @@ -245,41 +257,66 @@ struct raster_markers_rasterizer_dispatch void render_raster_marker(agg::trans_affine const& marker_tr, double opacity) { + typedef agg::pixfmt_rgba32_pre pixfmt_pre; double width = src_.width(); double height = src_.height(); - double p[8]; - p[0] = 0; p[1] = 0; - p[2] = width; p[3] = 0; - p[4] = width; p[5] = height; - p[6] = 0; p[7] = height; - marker_tr.transform(&p[0], &p[1]); - marker_tr.transform(&p[2], &p[3]); - marker_tr.transform(&p[4], &p[5]); - marker_tr.transform(&p[6], &p[7]); - ras_.move_to_d(p[0],p[1]); - ras_.line_to_d(p[2],p[3]); - ras_.line_to_d(p[4],p[5]); - ras_.line_to_d(p[6],p[7]); - agg::span_allocator sa; - agg::image_filter_bilinear filter_kernel; - agg::image_filter_lut filter(filter_kernel, false); - agg::rendering_buffer marker_buf((unsigned char *)src_.getBytes(), - src_.width(), - src_.height(), - src_.width()*4); - agg::pixfmt_rgba32_pre pixf(marker_buf); - typedef agg::image_accessor_clone img_accessor_type; - typedef agg::span_interpolator_linear interpolator_type; - typedef agg::span_image_filter_rgba_2x2 span_gen_type; - typedef agg::renderer_scanline_aa_alpha, - span_gen_type> renderer_type; - img_accessor_type ia(pixf); - interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) ); - span_gen_type sg(ia, interpolator, filter); - renderer_type rp(renb_,sa, sg, unsigned(opacity*255)); - agg::render_scanlines(ras_, sl_, rp); + if (std::fabs(1.0 - scale_factor_) < 0.001 + && (std::fabs(1.0 - marker_tr.sx) < agg::affine_epsilon) + && (std::fabs(0.0 - marker_tr.shy) < agg::affine_epsilon) + && (std::fabs(0.0 - marker_tr.shx) < agg::affine_epsilon) + && (std::fabs(1.0 - marker_tr.sy) < agg::affine_epsilon)) + { + agg::rendering_buffer src_buffer((unsigned char *)src_.getBytes(),src_.width(),src_.height(),src_.width() * 4); + pixfmt_pre pixf_mask(src_buffer); + renb_.blend_from(pixf_mask, + 0, + std::floor(marker_tr.tx + .5), + std::floor(marker_tr.ty + .5), + unsigned(255*sym_.get_opacity())); + } + else + { + typedef agg::image_accessor_clone img_accessor_type; + typedef agg::span_interpolator_linear<> interpolator_type; + //typedef agg::span_image_filter_rgba_2x2 span_gen_type; + typedef agg::span_image_resample_rgba_affine span_gen_type; + typedef agg::renderer_scanline_aa_alpha, + span_gen_type> renderer_type; + + double p[8]; + p[0] = 0; p[1] = 0; + p[2] = width; p[3] = 0; + p[4] = width; p[5] = height; + p[6] = 0; p[7] = height; + marker_tr.transform(&p[0], &p[1]); + marker_tr.transform(&p[2], &p[3]); + marker_tr.transform(&p[4], &p[5]); + marker_tr.transform(&p[6], &p[7]); + agg::span_allocator sa; + agg::image_filter_lut filter; + filter.calculate(agg::image_filter_bilinear(), true); + agg::rendering_buffer marker_buf((unsigned char *)src_.getBytes(), + src_.width(), + src_.height(), + src_.width()*4); + pixfmt_pre pixf(marker_buf); + img_accessor_type ia(pixf); + agg::trans_affine final_tr(p, 0, 0, width, height); + if (snap_to_pixels_) + { + final_tr.tx = std::floor(final_tr.tx+.5); + final_tr.ty = std::floor(final_tr.ty+.5); + } + interpolator_type interpolator(final_tr); + span_gen_type sg(ia, interpolator, filter); + renderer_type rp(renb_,sa, sg, unsigned(opacity*255)); + ras_.move_to_d(p[0],p[1]); + ras_.line_to_d(p[2],p[3]); + ras_.line_to_d(p[4],p[5]); + ras_.line_to_d(p[6],p[7]); + agg::render_scanlines(ras_, sl_, rp); + } } private: @@ -293,6 +330,7 @@ private: markers_symbolizer const& sym_; Detector & detector_; double scale_factor_; + bool snap_to_pixels_; }; diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index ed1a0ea92..8aa7311d4 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -74,6 +74,9 @@ void agg_renderer::process(markers_symbolizer const& sym, std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); + // https://github.com/mapnik/mapnik/issues/1316 + bool snap_pixels = !mapnik::marker_cache::instance().is_uri(filename); + if (!filename.empty()) { boost::optional mark = mapnik::marker_cache::instance().find(filename, true); @@ -120,8 +123,15 @@ void agg_renderer::process(markers_symbolizer const& sym, agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine marker_trans = recenter * tr; buf_type render_buffer(current_buffer_->raw_data(), width_, height_, width_ * 4); - dispatch_type rasterizer_dispatch(render_buffer,svg_renderer,*ras_ptr, - bbox, marker_trans, sym, *detector_, scale_factor_); + dispatch_type rasterizer_dispatch(render_buffer, + svg_renderer, + *ras_ptr, + bbox, + marker_trans, + sym, + *detector_, + scale_factor_, + snap_pixels); vertex_converter, dispatch_type, markers_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> converter(query_extent_, rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_); @@ -153,8 +163,15 @@ void agg_renderer::process(markers_symbolizer const& sym, bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes()); buf_type render_buffer(current_buffer_->raw_data(), width_, height_, width_ * 4); - dispatch_type rasterizer_dispatch(render_buffer,svg_renderer,*ras_ptr, - bbox, marker_trans, sym, *detector_, scale_factor_); + dispatch_type rasterizer_dispatch(render_buffer, + svg_renderer, + *ras_ptr, + bbox, + marker_trans, + sym, + *detector_, + scale_factor_, + snap_pixels); vertex_converter, dispatch_type, markers_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> converter(query_extent_, rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_); @@ -184,8 +201,14 @@ void agg_renderer::process(markers_symbolizer const& sym, boost::optional marker = (*mark)->get_bitmap_data(); typedef raster_markers_rasterizer_dispatch dispatch_type; buf_type render_buffer(current_buffer_->raw_data(), width_, height_, width_ * 4); - dispatch_type rasterizer_dispatch(render_buffer,*ras_ptr, **marker, - marker_trans, sym, *detector_, scale_factor_); + dispatch_type rasterizer_dispatch(render_buffer, + *ras_ptr, + **marker, + marker_trans, + sym, + *detector_, + scale_factor_, + true /*snap rasters no matter what*/); vertex_converter, dispatch_type, markers_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> converter(query_extent_, rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_);