From 7a5f06656c68f283cd2f39d073e4a3819060e6be Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 14 Aug 2012 17:11:08 -0700 Subject: [PATCH] allow setting marker width/height together with transform --- include/mapnik/grid/grid_marker_helpers.hpp | 279 ++++++++++++++++++++ include/mapnik/marker_helpers.hpp | 6 +- src/agg/process_markers_symbolizer.cpp | 9 +- src/cairo_renderer.cpp | 3 +- src/grid/process_markers_symbolizer.cpp | 3 +- 5 files changed, 289 insertions(+), 11 deletions(-) create mode 100644 include/mapnik/grid/grid_marker_helpers.hpp diff --git a/include/mapnik/grid/grid_marker_helpers.hpp b/include/mapnik/grid/grid_marker_helpers.hpp new file mode 100644 index 000000000..4316f2777 --- /dev/null +++ b/include/mapnik/grid/grid_marker_helpers.hpp @@ -0,0 +1,279 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_GRID_MARKER_HELPERS_HPP +#define MAPNIK_GRID_MARKER_HELPERS_HPP + +// mapnik +#include +#include + +// agg +#include "agg_renderer_scanline.h" +#include "agg_scanline_bin.h" +#include "agg_image_filters.h" +#include "agg_trans_bilinear.h" +#include "agg_span_allocator.h" +#include "agg_image_accessors.h" +#include "agg_span_image_filter_gray.h" + + +namespace mapnik { + +template +struct raster_markers_rasterizer_dispatch_grid +{ + typedef mapnik::gray32 color_type; + typedef typename RendererBase::pixfmt_type pixfmt_type; + + raster_markers_rasterizer_dispatch_grid(BufferType & render_buffer, + Rasterizer & ras, + image_data_32 const& src, + agg::trans_affine const& marker_trans, + markers_symbolizer const& sym, + Detector & detector, + double scale_factor, + mapnik::feature_impl & feature, + PixMapType & pixmap) + : buf_(render_buffer), + pixf_(buf_), + renb_(pixf_), + ras_(ras), + src_(src), + marker_trans_(marker_trans), + sym_(sym), + detector_(detector), + scale_factor_(scale_factor), + feature_(feature), + pixmap_(pixmap), + placed_(false) + { + // TODO - support basic binary operators + //pixf_.comp_op(static_cast(sym_.comp_op())); + } + + template + void add_path(T & path) + { + marker_placement_e placement_method = sym_.get_marker_placement(); + box2d bbox_(0,0, src_.width(),src_.height()); + if (placement_method != MARKER_LINE_PLACEMENT) + { + double x,y; + path.rewind(0); + if (placement_method == MARKER_INTERIOR_PLACEMENT) + { + label::interior_position(path, x, y); + } + else + { + label::centroid(path, x, y); + } + agg::trans_affine matrix = marker_trans_; + matrix.translate(x,y); + box2d transformed_bbox = bbox_ * matrix; + if (sym_.get_allow_overlap() || + detector_.has_placement(transformed_bbox)) + { + render_raster_marker(matrix); + if (!sym_.get_ignore_placement()) + { + detector_.insert(transformed_bbox); + } + if (!placed_) + { + pixmap_.add_feature(feature_); + placed_ = true; + } + } + } + else + { + markers_placement placement(path, bbox_, marker_trans_, detector_, + sym_.get_spacing() * scale_factor_, + sym_.get_max_error(), + sym_.get_allow_overlap()); + double x, y, angle; + while (placement.get_point(x, y, angle)) + { + agg::trans_affine matrix = marker_trans_; + matrix.rotate(angle); + matrix.translate(x, y); + render_raster_marker(matrix); + if (!placed_) + { + pixmap_.add_feature(feature_); + placed_ = true; + } + } + } + } + + void render_raster_marker(agg::trans_affine const& marker_tr) + { + 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]); + RendererType ren(renb_); + ren.color(mapnik::gray32(feature_.id())); + agg::render_scanlines(ras_, sl_, ren); + } + +private: + agg::scanline_bin sl_; + BufferType & buf_; + PixFmt pixf_; + RendererBase renb_; + Rasterizer & ras_; + image_data_32 const& src_; + agg::trans_affine const& marker_trans_; + markers_symbolizer const& sym_; + Detector & detector_; + double scale_factor_; + mapnik::feature_impl & feature_; + PixMapType & pixmap_; + bool placed_; +}; + + +template +struct vector_markers_rasterizer_dispatch_grid +{ + typedef typename SvgRenderer::renderer_base renderer_base; + typedef typename renderer_base::pixfmt_type pixfmt_type; + + vector_markers_rasterizer_dispatch_grid(BufferType & render_buffer, + SvgRenderer & svg_renderer, + Rasterizer & ras, + box2d const& bbox, + agg::trans_affine const& marker_trans, + markers_symbolizer const& sym, + Detector & detector, + double scale_factor, + mapnik::feature_impl & feature, + PixMapType & pixmap) + : buf_(render_buffer), + pixf_(buf_), + renb_(pixf_), + svg_renderer_(svg_renderer), + ras_(ras), + bbox_(bbox), + marker_trans_(marker_trans), + sym_(sym), + detector_(detector), + scale_factor_(scale_factor), + feature_(feature), + pixmap_(pixmap), + placed_(false) + { + // TODO + //pixf_.comp_op(static_cast(sym_.comp_op())); + } + + template + void add_path(T & path) + { + marker_placement_e placement_method = sym_.get_marker_placement(); + if (placement_method != MARKER_LINE_PLACEMENT) + { + double x,y; + path.rewind(0); + if (placement_method == MARKER_INTERIOR_PLACEMENT) + { + label::interior_position(path, x, y); + } + else + { + label::centroid(path, x, y); + } + agg::trans_affine matrix = marker_trans_; + matrix.translate(x,y); + box2d transformed_bbox = bbox_ * matrix; + if (sym_.get_allow_overlap() || + detector_.has_placement(transformed_bbox)) + { + svg_renderer_.render_id(ras_, sl_, renb_, feature_.id(), matrix, sym_.get_opacity(), bbox_); + if (!sym_.get_ignore_placement()) + { + detector_.insert(transformed_bbox); + } + if (!placed_) + { + pixmap_.add_feature(feature_); + placed_ = true; + } + } + } + else + { + markers_placement placement(path, bbox_, marker_trans_, detector_, + sym_.get_spacing() * scale_factor_, + sym_.get_max_error(), + sym_.get_allow_overlap()); + double x, y, angle; + while (placement.get_point(x, y, angle)) + { + agg::trans_affine matrix = marker_trans_; + matrix.rotate(angle); + matrix.translate(x, y); + svg_renderer_.render_id(ras_, sl_, renb_, feature_.id(), matrix, sym_.get_opacity(), bbox_); + if (!placed_) + { + pixmap_.add_feature(feature_); + placed_ = true; + } + } + } + } +private: + agg::scanline_bin sl_; + BufferType & buf_; + pixfmt_type pixf_; + renderer_base renb_; + SvgRenderer & svg_renderer_; + Rasterizer & ras_; + box2d const& bbox_; + agg::trans_affine const& marker_trans_; + markers_symbolizer const& sym_; + Detector & detector_; + double scale_factor_; + mapnik::feature_impl & feature_; + PixMapType & pixmap_; + bool placed_; +}; + + +} +#endif + diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index 439bd8c43..2b90d3579 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -359,7 +359,7 @@ bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& } template -void setup_label_transform(agg::trans_affine & tr, box2d const& bbox, mapnik::feature_impl const& feature, T const& sym) +void setup_transform_scaling(agg::trans_affine & tr, box2d const& bbox, mapnik::feature_impl const& feature, T const& sym) { double width = 0; double height = 0; @@ -388,10 +388,6 @@ void setup_label_transform(agg::trans_affine & tr, box2d const& bbox, ma double sy = height/bbox.height(); tr *= agg::trans_affine_scaling(sy); } - else - { - evaluate_transform(tr, feature, sym.get_image_transform()); - } } } diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 263e2566b..570161ef9 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -82,8 +82,7 @@ void agg_renderer::process(markers_symbolizer const& sym, ras_ptr->gamma(agg::gamma_power()); agg::trans_affine geom_tr; evaluate_transform(geom_tr, feature, sym.get_transform()); - agg::trans_affine tr; - tr *= agg::trans_affine_scaling(scale_factor_); + agg::trans_affine tr = agg::trans_affine_scaling(scale_factor_); if ((*mark)->is_vector()) { @@ -144,7 +143,8 @@ void agg_renderer::process(markers_symbolizer const& sym, else { box2d const& bbox = (*mark)->bounding_box(); - setup_label_transform(tr, bbox, feature, sym); + setup_transform_scaling(tr, bbox, feature, sym); + evaluate_transform(tr, feature, sym.get_image_transform()); coord2d center = bbox.center(); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine marker_trans = recenter * tr; @@ -179,7 +179,8 @@ void agg_renderer::process(markers_symbolizer const& sym, else // raster markers { box2d const& bbox = (*mark)->bounding_box(); - setup_label_transform(tr, bbox, feature, sym); + setup_transform_scaling(tr, bbox, feature, sym); + evaluate_transform(tr, feature, sym.get_image_transform()); coord2d center = bbox.center(); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine marker_trans = recenter * tr; diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index ba34355f8..bdc01b0a0 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -1628,7 +1628,8 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, agg::trans_affine geom_tr; evaluate_transform(geom_tr, feature, sym.get_transform()); box2d const& bbox = (*mark)->bounding_box(); - setup_label_transform(tr, bbox, feature, sym); + setup_transform_scaling(tr, bbox, feature, sym); + evaluate_transform(tr, feature, sym.get_image_transform()); if ((*mark)->is_vector()) { diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index cef9cb478..823bad284 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -129,7 +129,8 @@ void grid_renderer::process(markers_symbolizer const& sym, box2d const& bbox = (*marker)->bounding_box(); agg::trans_affine tr; - setup_label_transform(tr, bbox, feature, sym); + setup_transform_scaling(tr, bbox, feature, sym); + evaluate_transform(tr, feature, sym.get_image_transform()); // - clamp sizes to > 4 pixels of interactivity if (tr.scale() < 0.5) {