Factored out markers symbolizer logic.

It's not ideal - there's still a bunch of "dispatch" objects from
which the common elements could be factored for greater
readability.
This commit is contained in:
Matt Amos 2013-12-09 18:50:00 +00:00
parent f01953e8f7
commit dd9584bdd6
7 changed files with 380 additions and 491 deletions

View file

@ -73,6 +73,14 @@ struct raster_markers_rasterizer_dispatch_grid
//pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op())); //pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op()));
} }
raster_markers_rasterizer_dispatch_grid(raster_markers_rasterizer_dispatch_grid &&d)
: buf_(d.buf_), pixf_(d.pixf_), renb_(d.renb_), ras_(d.ras_), src_(d.src_),
marker_trans_(d.marker_trans_), sym_(d.sym_), detector_(d.detector_),
scale_factor_(d.scale_factor_), feature_(d.feature_), pixmap_(d.pixmap_),
placed_(d.placed_)
{
}
template <typename T> template <typename T>
void add_path(T & path) void add_path(T & path)
{ {
@ -185,23 +193,26 @@ private:
template <typename BufferType, typename SvgRenderer, typename Rasterizer, typename Detector, typename PixMapType> template <typename BufferType, typename SvgRenderer, typename Rasterizer, typename Detector, typename PixMapType>
struct vector_markers_rasterizer_dispatch_grid struct vector_markers_rasterizer_dispatch_grid
{ {
typedef typename SvgRenderer::renderer_base renderer_base; typedef typename SvgRenderer::renderer_base renderer_base;
typedef typename renderer_base::pixfmt_type pixfmt_type; typedef typename SvgRenderer::vertex_source_type vertex_source_type;
typedef typename SvgRenderer::attribute_source_type attribute_source_type;
typedef typename renderer_base::pixfmt_type pixfmt_type;
vector_markers_rasterizer_dispatch_grid(BufferType & render_buffer, vector_markers_rasterizer_dispatch_grid(BufferType & render_buffer,
SvgRenderer & svg_renderer, vertex_source_type &path,
Rasterizer & ras, const attribute_source_type &attrs,
box2d<double> const& bbox, Rasterizer & ras,
agg::trans_affine const& marker_trans, box2d<double> const& bbox,
markers_symbolizer const& sym, agg::trans_affine const& marker_trans,
Detector & detector, markers_symbolizer const& sym,
double scale_factor, Detector & detector,
mapnik::feature_impl & feature, double scale_factor,
PixMapType & pixmap) mapnik::feature_impl & feature,
PixMapType & pixmap)
: buf_(render_buffer), : buf_(render_buffer),
pixf_(buf_), pixf_(buf_),
renb_(pixf_), renb_(pixf_),
svg_renderer_(svg_renderer), svg_renderer_(path, attrs),
ras_(ras), ras_(ras),
bbox_(bbox), bbox_(bbox),
marker_trans_(marker_trans), marker_trans_(marker_trans),
@ -216,6 +227,14 @@ struct vector_markers_rasterizer_dispatch_grid
//pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op())); //pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op()));
} }
vector_markers_rasterizer_dispatch_grid(vector_markers_rasterizer_dispatch_grid &&d)
: buf_(d.buf_), pixf_(d.pixf_), svg_renderer_(std::move(d.svg_renderer_)), ras_(d.ras_),
bbox_(d.bbox_), marker_trans_(d.marker_trans_), sym_(d.sym_), detector_(d.detector_),
scale_factor_(d.scale_factor_), feature_(d.feature_), pixmap_(d.pixmap_),
placed_(d.placed_)
{
}
template <typename T> template <typename T>
void add_path(T & path) void add_path(T & path)
{ {
@ -290,7 +309,7 @@ private:
BufferType & buf_; BufferType & buf_;
pixfmt_type pixf_; pixfmt_type pixf_;
renderer_base renb_; renderer_base renb_;
SvgRenderer & svg_renderer_; SvgRenderer svg_renderer_;
Rasterizer & ras_; Rasterizer & ras_;
box2d<double> const& bbox_; box2d<double> const& bbox_;
agg::trans_affine const& marker_trans_; agg::trans_affine const& marker_trans_;

View file

@ -61,11 +61,14 @@ namespace mapnik {
template <typename BufferType, typename SvgRenderer, typename Rasterizer, typename Detector> template <typename BufferType, typename SvgRenderer, typename Rasterizer, typename Detector>
struct vector_markers_rasterizer_dispatch struct vector_markers_rasterizer_dispatch
{ {
typedef typename SvgRenderer::renderer_base renderer_base; typedef typename SvgRenderer::renderer_base renderer_base;
typedef typename renderer_base::pixfmt_type pixfmt_type; typedef typename SvgRenderer::vertex_source_type vertex_source_type;
typedef typename SvgRenderer::attribute_source_type attribute_source_type;
typedef typename renderer_base::pixfmt_type pixfmt_type;
vector_markers_rasterizer_dispatch(BufferType & render_buffer, vector_markers_rasterizer_dispatch(BufferType & render_buffer,
SvgRenderer & svg_renderer, vertex_source_type &path,
attribute_source_type const &attrs,
Rasterizer & ras, Rasterizer & ras,
box2d<double> const& bbox, box2d<double> const& bbox,
agg::trans_affine const& marker_trans, agg::trans_affine const& marker_trans,
@ -76,7 +79,7 @@ struct vector_markers_rasterizer_dispatch
: buf_(render_buffer), : buf_(render_buffer),
pixf_(buf_), pixf_(buf_),
renb_(pixf_), renb_(pixf_),
svg_renderer_(svg_renderer), svg_renderer_(path, attrs),
ras_(ras), ras_(ras),
bbox_(bbox), bbox_(bbox),
marker_trans_(marker_trans), marker_trans_(marker_trans),
@ -88,6 +91,13 @@ struct vector_markers_rasterizer_dispatch
pixf_.comp_op(get<agg::comp_op_e>(sym_, keys::comp_op, agg::comp_op_src_over)); pixf_.comp_op(get<agg::comp_op_e>(sym_, keys::comp_op, agg::comp_op_src_over));
} }
vector_markers_rasterizer_dispatch(vector_markers_rasterizer_dispatch &&d)
: buf_(d.buf_), pixf_(d.pixf_), svg_renderer_(std::move(d.svg_renderer_)), ras_(d.ras_),
bbox_(d.bbox_), marker_trans_(d.marker_trans_), sym_(d.sym_), detector_(d.detector_),
scale_factor_(d.scale_factor_), snap_to_pixels_(d.snap_to_pixels_)
{
}
template <typename T> template <typename T>
void add_path(T & path) void add_path(T & path)
{ {
@ -162,7 +172,7 @@ private:
BufferType & buf_; BufferType & buf_;
pixfmt_type pixf_; pixfmt_type pixf_;
renderer_base renb_; renderer_base renb_;
SvgRenderer & svg_renderer_; SvgRenderer svg_renderer_;
Rasterizer & ras_; Rasterizer & ras_;
box2d<double> const& bbox_; box2d<double> const& bbox_;
agg::trans_affine const& marker_trans_; agg::trans_affine const& marker_trans_;
@ -204,6 +214,13 @@ struct raster_markers_rasterizer_dispatch
pixf_.comp_op(get<agg::comp_op_e>(sym_, keys::comp_op, agg::comp_op_src_over)); pixf_.comp_op(get<agg::comp_op_e>(sym_, keys::comp_op, agg::comp_op_src_over));
} }
raster_markers_rasterizer_dispatch(raster_markers_rasterizer_dispatch &&d)
: buf_(d.buf_), pixf_(d.pixf_), renb_(d.renb_), ras_(d.ras_), src_(d.src_),
marker_trans_(d.marker_trans_), sym_(d.sym_), detector_(d.detector_),
scale_factor_(d.scale_factor_), snap_to_pixels_(d.snap_to_pixels_)
{
}
template <typename T> template <typename T>
void add_path(T & path) void add_path(T & path)
{ {

View file

@ -0,0 +1,176 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2013 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_RENDERER_COMMON_PROCESS_MARKERS_SYMBOLIZER_HPP
#define MAPNIK_RENDERER_COMMON_PROCESS_MARKERS_SYMBOLIZER_HPP
#include <mapnik/svg/svg_storage.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
namespace mapnik {
namespace {
} // anonymous namespace
template <typename F1, typename F2>
void render_markers_symbolizer(markers_symbolizer const &sym,
mapnik::feature_impl &feature,
proj_transform const &prj_trans,
renderer_common &common,
box2d<double> const &clip_box,
F1 make_vector_dispatch,
F2 make_raster_dispatch)
{
using namespace mapnik::svg;
typedef boost::mpl::vector<clip_poly_tag,transform_tag,smooth_tag> conv_types;
typedef agg::pod_bvector<path_attributes> svg_attribute_type;
std::string filename = get<std::string>(sym, keys::file, feature, "shape://ellipse");
bool clip = get<value_bool>(sym, keys::clip, feature, false);
double smooth = get<value_double>(sym, keys::smooth, feature, false);
// https://github.com/mapnik/mapnik/issues/1316
bool snap_pixels = !mapnik::marker_cache::instance().is_uri(filename);
if (!filename.empty())
{
boost::optional<marker_ptr> mark = mapnik::marker_cache::instance().find(filename, true);
if (mark && *mark)
{
agg::trans_affine tr = agg::trans_affine_scaling(common.scale_factor_);
if ((*mark)->is_vector())
{
boost::optional<svg_path_ptr> const& stock_vector_marker = (*mark)->get_vector_data();
auto width_expr = get_optional<expression_ptr>(sym, keys::width);
auto height_expr = get_optional<expression_ptr>(sym, keys::height);
// special case for simple ellipse markers
// to allow for full control over rx/ry dimensions
if (filename == "shape://ellipse"
&& (width_expr || height_expr))
{
svg_storage_type marker_ellipse;
vertex_stl_adapter<svg_path_storage> stl_storage(marker_ellipse.source());
svg_path_adapter svg_path(stl_storage);
build_ellipse(sym, feature, marker_ellipse, svg_path);
svg_attribute_type attributes;
bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym);
auto image_transform = get_optional<transform_type>(sym, keys::image_transform);
if (image_transform) evaluate_transform(tr, feature, *image_transform);
box2d<double> bbox = marker_ellipse.bounding_box();
auto rasterizer_dispatch = make_vector_dispatch(
svg_path, result ? attributes : (*stock_vector_marker)->attributes(),
marker_ellipse, bbox, tr, snap_pixels);
typedef decltype(rasterizer_dispatch) dispatch_type;
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,tr,common.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon)
converter.template set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform
if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, converter, sym);
}
else
{
box2d<double> const& bbox = (*mark)->bounding_box();
setup_transform_scaling(tr, bbox.width(), bbox.height(), feature, sym);
auto image_transform = get_optional<transform_type>(sym, keys::image_transform);
if (image_transform) evaluate_transform(tr, feature, *image_transform);
vertex_stl_adapter<svg_path_storage> stl_storage((*stock_vector_marker)->source());
svg_path_adapter svg_path(stl_storage);
svg_attribute_type attributes;
bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym);
auto rasterizer_dispatch = make_vector_dispatch(
svg_path, result ? attributes : (*stock_vector_marker)->attributes(),
**stock_vector_marker, bbox, tr, snap_pixels);
typedef decltype(rasterizer_dispatch) dispatch_type;
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,tr,common.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon)
converter.template set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform
if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, converter, sym);
}
}
else // raster markers
{
setup_transform_scaling(tr, (*mark)->width(), (*mark)->height(), feature, sym);
auto image_transform = get_optional<transform_type>(sym, keys::image_transform);
if (image_transform) evaluate_transform(tr, feature, *image_transform);
box2d<double> const& bbox = (*mark)->bounding_box();
boost::optional<mapnik::image_ptr> marker = (*mark)->get_bitmap_data();
auto rasterizer_dispatch = make_raster_dispatch(**marker, tr, bbox);
typedef decltype(rasterizer_dispatch) dispatch_type;
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,tr,common.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon)
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)
// converter.template set<clip_line_tag>();
// don't clip if type==geometry_type::types::Point
}
converter.template set<transform_tag>(); //always transform
if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, converter, sym);
}
}
}
}
} // namespace mapnik
#endif /* MAPNIK_RENDERER_COMMON_PROCESS_MARKERS_SYMBOLIZER_HPP */

View file

@ -107,6 +107,8 @@ public:
typedef agg::conv_transform<curved_type> curved_trans_type; typedef agg::conv_transform<curved_type> curved_trans_type;
typedef agg::conv_contour<curved_trans_type> curved_trans_contour_type; typedef agg::conv_contour<curved_trans_type> curved_trans_contour_type;
typedef agg::renderer_base<PixelFormat> renderer_base; typedef agg::renderer_base<PixelFormat> renderer_base;
typedef VertexSource vertex_source_type;
typedef AttributeSource attribute_source_type;
svg_renderer_agg(VertexSource & source, AttributeSource const& attributes) svg_renderer_agg(VertexSource & source, AttributeSource const& attributes)
: source_(source), : source_(source),
@ -114,6 +116,10 @@ public:
curved_stroked_(curved_), curved_stroked_(curved_),
attributes_(attributes) {} attributes_(attributes) {}
svg_renderer_agg(svg_renderer_agg &&r)
: source_(r.source_), curved_(source_), curved_stroked_(curved_),
attributes_(r.attributes_) {}
template <typename Rasterizer, typename Scanline, typename Renderer> template <typename Rasterizer, typename Scanline, typename Renderer>
void render_gradient(Rasterizer& ras, void render_gradient(Rasterizer& ras,
Scanline& sl, Scanline& sl,

View file

@ -38,6 +38,7 @@
#include <mapnik/svg/svg_path_attributes.hpp> #include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/symbolizer.hpp> #include <mapnik/symbolizer.hpp>
#include <mapnik/parse_path.hpp> #include <mapnik/parse_path.hpp>
#include <mapnik/renderer_common/process_markers_symbolizer.hpp>
// agg // agg
#include "agg_basics.h" #include "agg_basics.h"
@ -63,183 +64,71 @@ void agg_renderer<T0,T1>::process(markers_symbolizer const& sym,
feature_impl & feature, feature_impl & feature,
proj_transform const& prj_trans) proj_transform const& prj_trans)
{ {
using namespace mapnik::svg;
typedef agg::rgba8 color_type; typedef agg::rgba8 color_type;
typedef agg::order_rgba order_type; typedef agg::order_rgba order_type;
typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender
typedef agg::rendering_buffer buf_type; typedef agg::rendering_buffer buf_type;
typedef agg::pixfmt_custom_blend_rgba<blender_type, buf_type> pixfmt_comp_type; typedef agg::pixfmt_custom_blend_rgba<blender_type, buf_type> pixfmt_comp_type;
typedef agg::renderer_base<pixfmt_comp_type> renderer_base; typedef agg::renderer_base<pixfmt_comp_type> renderer_base;
typedef label_collision_detector4 detector_type; typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_type;
typedef boost::mpl::vector<clip_poly_tag,transform_tag,smooth_tag> conv_types; typedef agg::pod_bvector<path_attributes> svg_attribute_type;
typedef svg_renderer_agg<svg_path_adapter,
svg_attribute_type,
renderer_type,
pixfmt_comp_type > svg_renderer_type;
typedef vector_markers_rasterizer_dispatch<buf_type,
svg_renderer_type,
rasterizer,
detector_type > vector_dispatch_type;
typedef raster_markers_rasterizer_dispatch<buf_type,rasterizer, detector_type> raster_dispatch_type;
std::string filename = get<std::string>(sym, keys::file, feature, "shape://ellipse"); double gamma = get<value_double>(sym, keys::gamma, feature, 1.0);
bool clip = get<value_bool>(sym, keys::clip, feature, false); gamma_method_enum gamma_method = get<gamma_method_enum>(sym, keys::gamma_method, feature, GAMMA_POWER);
double smooth = get<value_double>(sym, keys::smooth, feature, false); if (gamma != gamma_ || gamma_method != gamma_method_)
// https://github.com/mapnik/mapnik/issues/1316
bool snap_pixels = !mapnik::marker_cache::instance().is_uri(filename);
if (!filename.empty())
{ {
boost::optional<marker_ptr> mark = mapnik::marker_cache::instance().find(filename, true); set_gamma_method(ras_ptr, gamma, gamma_method);
if (mark && *mark) gamma_method_ = gamma_method;
{ gamma_ = gamma;
ras_ptr->reset();
double gamma = get<value_double>(sym, keys::gamma, feature, 1.0);
gamma_method_enum gamma_method = get<gamma_method_enum>(sym, keys::gamma_method, feature, GAMMA_POWER);
if (gamma != gamma_ || gamma_method != gamma_method_)
{
set_gamma_method(ras_ptr, gamma, gamma_method);
gamma_method_ = gamma_method;
gamma_ = gamma;
}
agg::trans_affine tr = agg::trans_affine_scaling(common_.scale_factor_);
box2d<double> clip_box = clipping_extent();
if ((*mark)->is_vector())
{
using namespace mapnik::svg;
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_type;
typedef agg::pod_bvector<path_attributes> svg_attribute_type;
typedef svg_renderer_agg<svg_path_adapter,
svg_attribute_type,
renderer_type,
pixfmt_comp_type > svg_renderer_type;
typedef vector_markers_rasterizer_dispatch<buf_type,
svg_renderer_type,
rasterizer,
detector_type > dispatch_type;
boost::optional<svg_path_ptr> const& stock_vector_marker = (*mark)->get_vector_data();
auto width_expr = get_optional<expression_ptr>(sym, keys::width);
auto height_expr = get_optional<expression_ptr>(sym, keys::height);
// special case for simple ellipse markers
// to allow for full control over rx/ry dimensions
if (filename == "shape://ellipse"
&& (width_expr || height_expr))
{
svg_storage_type marker_ellipse;
vertex_stl_adapter<svg_path_storage> stl_storage(marker_ellipse.source());
svg_path_adapter svg_path(stl_storage);
build_ellipse(sym, feature, marker_ellipse, svg_path);
svg_attribute_type attributes;
bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym);
svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes());
auto image_transform = get_optional<transform_type>(sym, keys::image_transform);
if (image_transform) evaluate_transform(tr, feature, *image_transform);
box2d<double> bbox = marker_ellipse.bounding_box();
coord2d center = bbox.center();
agg::trans_affine_translation recenter(-center.x, -center.y);
agg::trans_affine marker_trans = recenter * tr;
buf_type render_buffer(current_buffer_->raw_data(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4);
dispatch_type rasterizer_dispatch(render_buffer,
svg_renderer,
*ras_ptr,
bbox,
marker_trans,
sym,
*common_.detector_,
common_.scale_factor_,
snap_pixels);
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(clip_box, rasterizer_dispatch, sym,common_.t_,prj_trans,tr,common_.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon)
converter.template set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform
if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, converter, sym);
}
else
{
box2d<double> const& bbox = (*mark)->bounding_box();
setup_transform_scaling(tr, bbox.width(), bbox.height(), feature, sym);
auto image_transform = get_optional<transform_type>(sym, keys::image_transform);
if (image_transform) evaluate_transform(tr, feature, *image_transform);
coord2d center = bbox.center();
agg::trans_affine_translation recenter(-center.x, -center.y);
agg::trans_affine marker_trans = recenter * tr;
vertex_stl_adapter<svg_path_storage> stl_storage((*stock_vector_marker)->source());
svg_path_adapter svg_path(stl_storage);
svg_attribute_type attributes;
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(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4);
dispatch_type rasterizer_dispatch(render_buffer,
svg_renderer,
*ras_ptr,
bbox,
marker_trans,
sym,
*common_.detector_,
common_.scale_factor_,
snap_pixels);
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(clip_box, rasterizer_dispatch, sym,common_.t_,prj_trans,tr,common_.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon)
converter.template set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform
if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, converter, sym);
}
}
else // raster markers
{
setup_transform_scaling(tr, (*mark)->width(), (*mark)->height(), feature, sym);
auto image_transform = get_optional<transform_type>(sym, keys::image_transform);
if (image_transform) evaluate_transform(tr, feature, *image_transform);
box2d<double> const& bbox = (*mark)->bounding_box();
coord2d center = bbox.center();
agg::trans_affine_translation recenter(-center.x, -center.y);
agg::trans_affine marker_trans = recenter * tr;
boost::optional<mapnik::image_ptr> marker = (*mark)->get_bitmap_data();
typedef raster_markers_rasterizer_dispatch<buf_type,rasterizer, detector_type> dispatch_type;
buf_type render_buffer(current_buffer_->raw_data(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4);
dispatch_type rasterizer_dispatch(render_buffer,
*ras_ptr,
**marker,
marker_trans,
sym,
*common_.detector_,
common_.scale_factor_,
true /*snap rasters no matter what*/);
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(clip_box, rasterizer_dispatch, sym,common_.t_,prj_trans,tr,common_.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon)
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)
// converter.template set<clip_line_tag>();
// don't clip if type==geometry_type::types::Point
}
converter.template set<transform_tag>(); //always transform
if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, converter, sym);
}
}
} }
buf_type render_buffer(current_buffer_->raw_data(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4);
ras_ptr->reset();
box2d<double> clip_box = clipping_extent();
render_markers_symbolizer(
sym, feature, prj_trans, common_, clip_box,
[&](svg_path_adapter &path, svg_attribute_type const &attr, svg_storage_type &,
box2d<double> const &bbox, agg::trans_affine const &tr,
bool snap_pixels) -> vector_dispatch_type {
coord2d center = bbox.center();
agg::trans_affine_translation recenter(-center.x, -center.y);
agg::trans_affine marker_trans = recenter * tr;
return vector_dispatch_type(render_buffer,
path, attr,
*ras_ptr,
bbox,
marker_trans,
sym,
*common_.detector_,
common_.scale_factor_,
snap_pixels);
},
[&](image_data_32 const &marker, agg::trans_affine const &tr,
box2d<double> const &bbox) -> raster_dispatch_type {
coord2d center = bbox.center();
agg::trans_affine_translation recenter(-center.x, -center.y);
agg::trans_affine marker_trans = recenter * tr;
return raster_dispatch_type(render_buffer,
*ras_ptr,
marker,
marker_trans,
sym,
*common_.detector_,
common_.scale_factor_,
true /*snap rasters no matter what*/);
});
} }
template void agg_renderer<image_32>::process(markers_symbolizer const&, template void agg_renderer<image_32>::process(markers_symbolizer const&,

View file

@ -58,6 +58,7 @@
#include <mapnik/renderer_common/process_building_symbolizer.hpp> #include <mapnik/renderer_common/process_building_symbolizer.hpp>
#include <mapnik/renderer_common/process_point_symbolizer.hpp> #include <mapnik/renderer_common/process_point_symbolizer.hpp>
#include <mapnik/renderer_common/process_raster_symbolizer.hpp> #include <mapnik/renderer_common/process_raster_symbolizer.hpp>
#include <mapnik/renderer_common/process_markers_symbolizer.hpp>
// cairo // cairo
#include <cairo.h> #include <cairo.h>
@ -880,12 +881,12 @@ template <typename Context, typename ImageMarker, typename Detector>
struct markers_dispatch_2 struct markers_dispatch_2
{ {
markers_dispatch_2(Context & ctx, markers_dispatch_2(Context & ctx,
ImageMarker & marker, ImageMarker & marker,
Detector & detector, Detector & detector,
markers_symbolizer const& sym, markers_symbolizer const& sym,
box2d<double> const& bbox, box2d<double> const& bbox,
agg::trans_affine const& marker_trans, agg::trans_affine const& marker_trans,
double scale_factor) double scale_factor)
:ctx_(ctx), :ctx_(ctx),
marker_(marker), marker_(marker),
detector_(detector), detector_(detector),
@ -935,7 +936,7 @@ struct markers_dispatch_2
if (allow_overlap || if (allow_overlap ||
detector_.has_placement(transformed_bbox)) detector_.has_placement(transformed_bbox))
{ {
ctx_.add_image(matrix, *marker_, opacity); ctx_.add_image(matrix, marker_, opacity);
if (!ignore_placement) if (!ignore_placement)
{ {
detector_.insert(transformed_bbox); detector_.insert(transformed_bbox);
@ -956,7 +957,7 @@ struct markers_dispatch_2
matrix *= marker_trans_; matrix *= marker_trans_;
matrix *= agg::trans_affine_rotation(angle); matrix *= agg::trans_affine_rotation(angle);
matrix *= agg::trans_affine_translation(x, y); matrix *= agg::trans_affine_translation(x, y);
ctx_.add_image(matrix, *marker_, opacity); ctx_.add_image(matrix, marker_, opacity);
} }
} }
} }
@ -975,135 +976,30 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
mapnik::feature_impl & feature, mapnik::feature_impl & feature,
proj_transform const& prj_trans) proj_transform const& prj_trans)
{ {
typedef boost::mpl::vector<clip_poly_tag,transform_tag,smooth_tag> conv_types; typedef agg::pod_bvector<svg::path_attributes> svg_attribute_type;
typedef detail::markers_dispatch_2<cairo_context, mapnik::image_data_32,
label_collision_detector4> raster_dispatch_type;
typedef detail::markers_dispatch<cairo_context, mapnik::svg_storage_type, svg_attribute_type,
label_collision_detector4> vector_dispatch_type;
cairo_save_restore guard(context_); cairo_save_restore guard(context_);
composite_mode_e comp_op = get<composite_mode_e>(sym, keys::comp_op, feature, src_over); composite_mode_e comp_op = get<composite_mode_e>(sym, keys::comp_op, feature, src_over);
std::string filename = get<std::string>(sym, keys::file, feature, "shape://ellipse");
auto geom_transform = get_optional<transform_type>(sym, keys::geometry_transform);
auto img_transform = get_optional<transform_type>(sym, keys::image_transform);
auto width = get_optional<unsigned>(sym, keys::width);
auto height = get_optional<unsigned>(sym, keys::height);
bool clip = get<bool>(sym, keys::clip, feature, false);
double smooth = get<double>(sym, keys::smooth, feature, 0.0);
context_.set_operator(comp_op); context_.set_operator(comp_op);
box2d<double> clip_box = common_.query_extent_;
agg::trans_affine tr = agg::trans_affine_scaling(common_.scale_factor_); render_markers_symbolizer(
sym, feature, prj_trans, common_, clip_box,
if (!filename.empty()) [&](svg::svg_path_adapter &, svg_attribute_type const &attr, svg_storage_type &marker,
{ box2d<double> const &bbox, agg::trans_affine const &marker_trans,
boost::optional<marker_ptr> mark = mapnik::marker_cache::instance().find(filename, true); bool) -> vector_dispatch_type {
if (mark && *mark) return vector_dispatch_type(context_, marker, attr, *common_.detector_, sym, bbox,
{ marker_trans, common_.scale_factor_);
agg::trans_affine geom_tr; },
if (geom_transform) { evaluate_transform(geom_tr, feature, *geom_transform); } [&](image_data_32 &marker, agg::trans_affine const &marker_trans,
box2d<double> const& bbox = (*mark)->bounding_box(); box2d<double> const &bbox) -> raster_dispatch_type {
setup_transform_scaling(tr, bbox.width(), bbox.height(), feature, sym); return raster_dispatch_type(context_, marker, *common_.detector_, sym, bbox,
if (img_transform) { evaluate_transform(tr, feature, *img_transform); } marker_trans, common_.scale_factor_);
});
if ((*mark)->is_vector())
{
using namespace mapnik::svg;
typedef agg::pod_bvector<path_attributes> svg_attributes_type;
typedef detail::markers_dispatch<cairo_context, mapnik::svg_storage_type,
svg_attributes_type,label_collision_detector4> dispatch_type;
boost::optional<svg_path_ptr> const& stock_vector_marker = (*mark)->get_vector_data();
// special case for simple ellipse markers
// to allow for full control over rx/ry dimensions
if (filename == "shape://ellipse"
&& (width || height))
{
svg_storage_type marker_ellipse;
vertex_stl_adapter<svg_path_storage> stl_storage(marker_ellipse.source());
svg_path_adapter svg_path(stl_storage);
build_ellipse(sym, feature, marker_ellipse, svg_path);
svg_attributes_type attributes;
bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym);
agg::trans_affine marker_tr = agg::trans_affine_scaling(common_.scale_factor_);
if (img_transform) { evaluate_transform(marker_tr, feature, *img_transform); }
box2d<double> new_bbox = marker_ellipse.bounding_box();
dispatch_type dispatch(context_, marker_ellipse, result?attributes:(*stock_vector_marker)->attributes(),
*common_.detector_, sym, new_bbox, marker_tr, common_.scale_factor_);
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(common_.query_extent_, dispatch, sym, common_.t_, prj_trans, marker_tr, common_.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon)
converter.set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == geometry_type::types::LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==geometry_type::types::Point
}
converter.set<transform_tag>(); //always transform
if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, converter, sym);
}
else
{
svg_attributes_type attributes;
bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym);
dispatch_type dispatch(context_, **stock_vector_marker, result?attributes:(*stock_vector_marker)->attributes(),
*common_.detector_, sym, bbox, tr, common_.scale_factor_);
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(common_.query_extent_, dispatch, sym, common_.t_, prj_trans, tr, common_.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon)
converter.set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == geometry_type::types::LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==geometry_type::types::Point
}
converter.set<transform_tag>(); //always transform
if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, converter, sym);
}
}
else // raster markers
{
typedef detail::markers_dispatch_2<cairo_context,
mapnik::image_ptr,
label_collision_detector4> dispatch_type;
boost::optional<mapnik::image_ptr> marker = (*mark)->get_bitmap_data();
if ( marker )
{
dispatch_type dispatch(context_, *marker,
*common_.detector_, sym, bbox, tr, common_.scale_factor_);
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(common_.query_extent_, dispatch, sym, common_.t_, prj_trans, tr, common_.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon)
converter.set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == geometry_type::types::LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==geometry_type::types::Point
}
converter.set<transform_tag>(); //always transform
if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, converter, sym);
}
}
}
}
} }
void cairo_renderer_base::process(text_symbolizer const& sym, void cairo_renderer_base::process(text_symbolizer const& sym,

View file

@ -60,6 +60,7 @@ porting notes -->
#include <mapnik/svg/svg_path_adapter.hpp> #include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_path_attributes.hpp> #include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/parse_path.hpp> #include <mapnik/parse_path.hpp>
#include <mapnik/renderer_common/process_markers_symbolizer.hpp>
// agg // agg
#include "agg_basics.h" #include "agg_basics.h"
@ -84,181 +85,66 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
typedef typename grid_renderer_base_type::pixfmt_type pixfmt_type; typedef typename grid_renderer_base_type::pixfmt_type pixfmt_type;
typedef agg::renderer_scanline_bin_solid<grid_renderer_base_type> renderer_type; typedef agg::renderer_scanline_bin_solid<grid_renderer_base_type> renderer_type;
typedef label_collision_detector4 detector_type; typedef label_collision_detector4 detector_type;
typedef boost::mpl::vector<clip_poly_tag,transform_tag,smooth_tag> conv_types;
std::string filename = get<std::string>(sym, keys::file, feature, "shape://ellipse"); using namespace mapnik::svg;
bool clip = get<value_bool>(sym, keys::clip, feature, false); typedef agg::pod_bvector<path_attributes> svg_attribute_type;
double smooth = get<value_double>(sym, keys::smooth, feature, false); typedef svg_renderer_agg<svg_path_adapter,
svg_attribute_type,
renderer_type,
pixfmt_type > svg_renderer_type;
typedef vector_markers_rasterizer_dispatch_grid<buf_type,
svg_renderer_type,
grid_rasterizer,
detector_type,
mapnik::grid > vector_dispatch_type;
typedef raster_markers_rasterizer_dispatch_grid<buf_type,
grid_rasterizer,
pixfmt_type,
grid_renderer_base_type,
renderer_type,
detector_type,
mapnik::grid > raster_dispatch_type;
if (!filename.empty()) buf_type render_buf(pixmap_.raw_data(), common_.width_, common_.height_, common_.width_);
{ ras_ptr->reset();
boost::optional<marker_ptr> mark = mapnik::marker_cache::instance().find(filename, true); box2d<double> clip_box = common_.query_extent_;
if (mark && *mark)
{
ras_ptr->reset();
agg::trans_affine geom_tr;
auto geom_transform = get_optional<transform_type>(sym, keys::geometry_transform);
if (geom_transform) { evaluate_transform(geom_tr, feature, *geom_transform); }
agg::trans_affine tr = agg::trans_affine_scaling(common_.scale_factor_*(1.0/pixmap_.get_resolution())); render_markers_symbolizer(
auto img_transform = get_optional<transform_type>(sym, keys::image_transform); sym, feature, prj_trans, common_, clip_box,
[&](svg_path_adapter &path, svg_attribute_type const &attr, svg_storage_type &,
if ((*mark)->is_vector()) box2d<double> const &bbox, agg::trans_affine const &tr,
{ bool) -> vector_dispatch_type {
using namespace mapnik::svg; // TODO - clamping to >= 4 pixels
typedef agg::pod_bvector<path_attributes> svg_attribute_type; coord2d center = bbox.center();
typedef svg_renderer_agg<svg_path_adapter, agg::trans_affine_translation recenter(-center.x, -center.y);
svg_attribute_type, agg::trans_affine marker_trans = recenter * tr;
renderer_type, return vector_dispatch_type(render_buf,
pixfmt_type > svg_renderer_type; path, attr,
typedef vector_markers_rasterizer_dispatch_grid<buf_type, *ras_ptr,
svg_renderer_type, bbox,
grid_rasterizer, marker_trans,
detector_type, sym,
mapnik::grid > dispatch_type; *common_.detector_,
boost::optional<svg_path_ptr> const& stock_vector_marker = (*mark)->get_vector_data(); common_.scale_factor_,
feature,
auto width_expr = get_optional<expression_ptr>(sym, keys::width); pixmap_);
auto height_expr = get_optional<expression_ptr>(sym, keys::height); },
[&](image_data_32 const &marker, agg::trans_affine const &tr,
// special case for simple ellipse markers box2d<double> const &bbox) -> raster_dispatch_type {
// to allow for full control over rx/ry dimensions // - clamp sizes to > 4 pixels of interactivity
if (filename == "shape://ellipse" coord2d center = bbox.center();
&& (width_expr || height_expr)) agg::trans_affine_translation recenter(-center.x, -center.y);
{ agg::trans_affine marker_trans = recenter * tr;
svg_storage_type marker_ellipse; return raster_dispatch_type(render_buf,
vertex_stl_adapter<svg_path_storage> stl_storage(marker_ellipse.source()); *ras_ptr,
svg_path_adapter svg_path(stl_storage); marker,
// TODO - clamping to >= 4 pixels marker_trans,
build_ellipse(sym, feature, marker_ellipse, svg_path); sym,
svg_attribute_type attributes; *common_.detector_,
bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); common_.scale_factor_,
svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes()); feature,
if (img_transform) { evaluate_transform(tr, feature, *img_transform); } pixmap_);
});
box2d<double> bbox = marker_ellipse.bounding_box();
coord2d center = bbox.center();
agg::trans_affine_translation recenter(-center.x, -center.y);
agg::trans_affine marker_trans = recenter * tr;
buf_type render_buf(pixmap_.raw_data(), common_.width_, common_.height_, common_.width_);
dispatch_type rasterizer_dispatch(render_buf,
svg_renderer,
*ras_ptr,
bbox,
marker_trans,
sym,
*common_.detector_,
common_.scale_factor_,
feature,
pixmap_);
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(common_.query_extent_, rasterizer_dispatch, sym,common_.t_,prj_trans,tr,common_.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon)
converter.template set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform
if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, converter, sym);
}
else
{
box2d<double> const& bbox = (*mark)->bounding_box();
setup_transform_scaling(tr, bbox.width(), bbox.height(), feature, sym);
if (img_transform) { evaluate_transform(tr, feature, *img_transform); }
// TODO - clamping to >= 4 pixels
coord2d center = bbox.center();
agg::trans_affine_translation recenter(-center.x, -center.y);
agg::trans_affine marker_trans = recenter * tr;
vertex_stl_adapter<svg_path_storage> stl_storage((*stock_vector_marker)->source());
svg_path_adapter svg_path(stl_storage);
svg_attribute_type attributes;
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_buf(pixmap_.raw_data(), common_.width_, common_.height_, common_.width_);
dispatch_type rasterizer_dispatch(render_buf,
svg_renderer,
*ras_ptr,
bbox,
marker_trans,
sym,
*common_.detector_,
common_.scale_factor_,
feature,
pixmap_);
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(common_.query_extent_, rasterizer_dispatch, sym,common_.t_,prj_trans,tr,common_.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon)
converter.template set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform
if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, converter, sym);
}
}
else // raster markers
{
setup_transform_scaling(tr, (*mark)->width(), (*mark)->height(), feature, sym);
if (img_transform) { evaluate_transform(tr, feature, *img_transform); }
box2d<double> const& bbox = (*mark)->bounding_box();
// - clamp sizes to > 4 pixels of interactivity
coord2d center = bbox.center();
agg::trans_affine_translation recenter(-center.x, -center.y);
agg::trans_affine marker_trans = recenter * tr;
boost::optional<mapnik::image_ptr> marker = (*mark)->get_bitmap_data();
typedef raster_markers_rasterizer_dispatch_grid<buf_type,
grid_rasterizer,
pixfmt_type,
grid_renderer_base_type,
renderer_type,
detector_type,
mapnik::grid > dispatch_type;
buf_type render_buf(pixmap_.raw_data(), common_.width_, common_.height_, common_.width_);
dispatch_type rasterizer_dispatch(render_buf,
*ras_ptr,
**marker,
marker_trans,
sym,
*common_.detector_,
common_.scale_factor_,
feature,
pixmap_);
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(common_.query_extent_, rasterizer_dispatch, sym,common_.t_,prj_trans,tr,common_.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
if (type == geometry_type::types::Polygon)
converter.template set<clip_poly_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform
if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
apply_markers_multi(feature, converter, sym);
}
}
}
} }
template void grid_renderer<grid>::process(markers_symbolizer const&, template void grid_renderer<grid>::process(markers_symbolizer const&,