Merge pull request #4005 from mapycz/v3.0.x-fix-pattern-alignment

v3.0.x: True global pattern alignment, fixed local alignment
This commit is contained in:
talaj 2018-11-06 18:05:30 +01:00 committed by GitHub
commit 38fa2a9792
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 147 additions and 124 deletions

View file

@ -29,6 +29,7 @@
#include <mapnik/renderer_common/apply_vertex_converter.hpp>
#include <mapnik/renderer_common/clipping_extent.hpp>
#include <mapnik/vertex_converters.hpp>
#include <mapnik/safe_cast.hpp>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore_agg.hpp>
@ -107,29 +108,14 @@ struct agg_polygon_pattern : agg_pattern_base
void render(renderer_base & ren_base, rasterizer & ras)
{
pattern_alignment_enum alignment = get<pattern_alignment_enum, keys::alignment>(
sym_, feature_, common_.vars_);
unsigned offset_x=0;
unsigned offset_y=0;
if (alignment == LOCAL_ALIGNMENT)
{
double x0 = 0;
double y0 = 0;
using apply_local_alignment = detail::apply_local_alignment;
apply_local_alignment apply(common_.t_, prj_trans_, clip_box_, x0, y0);
util::apply_visitor(geometry::vertex_processor<apply_local_alignment>(apply), feature_.get_geometry());
offset_x = unsigned(ren_base.width() - x0);
offset_y = unsigned(ren_base.height() - y0);
}
coord<double, 2> offset(pattern_offset(sym_, feature_, prj_trans_, common_,
pattern_img_.width(), pattern_img_.height()));
agg::rendering_buffer pattern_rbuf((agg::int8u*)pattern_img_.bytes(),
pattern_img_.width(), pattern_img_.height(),
pattern_img_.width() * 4);
agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf);
img_source_type img_src(pixf_pattern);
span_gen_type sg(img_src, offset_x, offset_y);
span_gen_type sg(img_src, safe_cast<unsigned>(offset.x), safe_cast<unsigned>(offset.y));
agg::span_allocator<agg::rgba8> sa;
value_double opacity = get<double, keys::opacity>(sym_, feature_, common_.vars_);

View file

@ -37,45 +37,30 @@ namespace mapnik {
struct cairo_renderer_process_visitor_p
{
cairo_renderer_process_visitor_p(cairo_context & context,
agg::trans_affine & image_tr,
unsigned offset_x,
unsigned offset_y,
float opacity)
: context_(context),
image_tr_(image_tr),
offset_x_(offset_x),
offset_y_(offset_y),
opacity_(opacity) {}
cairo_renderer_process_visitor_p(agg::trans_affine & image_tr)
: image_tr_(image_tr)
{}
void operator() (marker_null const&) {}
void operator() (marker_svg const& marker)
image_rgba8 operator() (marker_null const&)
{
mapnik::rasterizer ras;
mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr_;
mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height());
render_pattern<image_rgba8>(ras, marker, image_tr_, 1.0, image);
cairo_pattern pattern(image, opacity_);
pattern.set_extend(CAIRO_EXTEND_REPEAT);
pattern.set_origin(offset_x_, offset_y_);
context_.set_pattern(pattern);
return image_rgba8();
}
void operator() (marker_rgba8 const& marker)
image_rgba8 operator() (marker_svg const& marker)
{
cairo_pattern pattern(marker.get_data(), opacity_);
pattern.set_extend(CAIRO_EXTEND_REPEAT);
pattern.set_origin(offset_x_, offset_y_);
context_.set_pattern(pattern);
mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr_;
mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height());
render_pattern<image_rgba8>(marker, image_tr_, 1.0, image);
return image;
}
image_rgba8 operator() (marker_rgba8 const& marker)
{
return marker.get_data();
}
private:
cairo_context & context_;
agg::trans_affine & image_tr_;
unsigned offset_x_;
unsigned offset_y_;
float opacity_;
};
struct cairo_pattern_base
@ -123,20 +108,6 @@ struct cairo_polygon_pattern : cairo_pattern_base
void render(cairo_fill_rule_t fill_rule, cairo_context & context)
{
unsigned offset_x=0;
unsigned offset_y=0;
pattern_alignment_enum alignment = get<pattern_alignment_enum, keys::alignment>(sym_, feature_, common_.vars_);
if (alignment == LOCAL_ALIGNMENT)
{
double x0 = 0.0;
double y0 = 0.0;
using apply_local_alignment = detail::apply_local_alignment;
apply_local_alignment apply(common_.t_, prj_trans_, clip_box_, x0, y0);
util::apply_visitor(geometry::vertex_processor<apply_local_alignment>(apply), feature_.get_geometry());
offset_x = std::abs(clip_box_.width() - x0);
offset_y = std::abs(clip_box_.height() - y0);
}
value_double opacity = get<value_double, keys::opacity>(sym_, feature_, common_.vars_);
agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_);
auto image_transform = get_optional<transform_type>(sym_, keys::image_transform);
@ -150,8 +121,13 @@ struct cairo_polygon_pattern : cairo_pattern_base
cairo_save_restore guard(context);
context.set_operator(comp_op);
util::apply_visitor(cairo_renderer_process_visitor_p(
context, image_tr, offset_x, offset_y, opacity), marker_);
image_rgba8 pattern_img(util::apply_visitor(cairo_renderer_process_visitor_p(image_tr), marker_));
coord<double, 2> offset(pattern_offset(sym_, feature_, prj_trans_, common_,
pattern_img.width(), pattern_img.height()));
cairo_pattern pattern(pattern_img, opacity);
pattern.set_extend(CAIRO_EXTEND_REPEAT);
pattern.set_origin(-offset.x, -offset.y);
context.set_pattern(pattern);
using apply_vertex_converter_type = detail::apply_vertex_converter<VertexConverter, cairo_context>;
using vertex_processor_type = geometry::vertex_processor<apply_vertex_converter_type>;

View file

@ -20,56 +20,26 @@
*
*****************************************************************************/
#ifndef MAPNIK_PATTERN_ALIGNMENT_HPP
#define MAPNIK_PATTERN_ALIGNMENT_HPP
#include <mapnik/geometry.hpp>
#include <mapnik/vertex_adapters.hpp>
#include <mapnik/transform_path_adapter.hpp>
#include <mapnik/coord.hpp>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore_agg.hpp>
#include "agg_conv_clip_polygon.h"
#pragma GCC diagnostic pop
namespace mapnik {
namespace mapnik { namespace detail {
class symbolizer_base;
class feature_impl;
class proj_transform;
class renderer_common;
struct apply_local_alignment
{
apply_local_alignment(view_transform const& t,
proj_transform const& prj_trans,
box2d<double> const& clip_box,
double & x, double & y)
: t_(t),
prj_trans_(prj_trans),
clip_box_(clip_box),
x_(x),
y_(y) {}
coord<double, 2> pattern_offset(
symbolizer_base const & sym,
feature_impl const & feature,
proj_transform const & prj_trans,
renderer_common const & common,
unsigned pattern_width,
unsigned pattern_height);
void operator() (geometry::polygon_vertex_adapter<double> & va)
{
using clipped_geometry_type = agg::conv_clip_polygon<geometry::polygon_vertex_adapter<double> >;
using path_type = transform_path_adapter<view_transform,clipped_geometry_type>;
clipped_geometry_type clipped(va);
clipped.clip_box(clip_box_.minx(),clip_box_.miny(),clip_box_.maxx(),clip_box_.maxy());
path_type path(t_, clipped, prj_trans_);
path.vertex(&x_,&y_);
}
template <typename Adapter>
void operator() (Adapter &)
{
// no-op
}
view_transform const& t_;
proj_transform const& prj_trans_;
box2d<double> const& clip_box_;
double & x_;
double & y_;
};
}}
}
#endif // MAPNIK_PATTERN_ALIGNMENT_HPP

View file

@ -38,8 +38,7 @@ struct rasterizer;
struct marker_svg;
template <typename T>
void render_pattern(rasterizer & ras,
marker_svg const& marker,
void render_pattern(marker_svg const& marker,
agg::trans_affine const& tr,
double opacity,
T & image);

View file

@ -199,7 +199,7 @@ struct agg_renderer_process_visitor_l
if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_);
mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr;
image_rgba8 image(bbox_image.width(), bbox_image.height());
render_pattern<buffer_type>(ras_, marker, image_tr, 1.0, image);
render_pattern<buffer_type>(marker, image_tr, 1.0, image);
render_by_pattern_type(image);
}

View file

@ -85,7 +85,7 @@ struct agg_renderer_process_visitor_p
if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_);
mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr;
mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height());
render_pattern<buffer_type>(*ras_ptr_, marker, image_tr, 1.0, image);
render_pattern<buffer_type>(marker, image_tr, 1.0, image);
render(image);
}

View file

@ -263,6 +263,7 @@ source = Split(
renderer_common/render_markers_symbolizer.cpp
renderer_common/render_pattern.cpp
renderer_common/render_thunk_extractor.cpp
renderer_common/pattern_alignment.cpp
math.cpp
value.cpp
"""

View file

@ -63,13 +63,12 @@ struct prepare_pattern_visitor
std::shared_ptr<cairo_pattern> operator() (mapnik::marker_svg const& marker)
{
double opacity = get<value_double, keys::opacity>(sym_, feature_, common_.vars_);
mapnik::rasterizer ras;
agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_);
auto image_transform = get_optional<transform_type>(sym_, keys::image_transform);
if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_);
mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr;
mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height());
render_pattern<image_rgba8>(ras, marker, image_tr, 1.0, image);
render_pattern<image_rgba8>(marker, image_tr, 1.0, image);
width_ = image.width();
height_ = image.height();
return std::make_shared<cairo_pattern>(image, opacity);

View file

@ -0,0 +1,93 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2015 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
*
*****************************************************************************/
#include <mapnik/geometry.hpp>
#include <mapnik/view_transform.hpp>
#include <mapnik/vertex_adapters.hpp>
#include <mapnik/vertex_processor.hpp>
#include <mapnik/transform_path_adapter.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/renderer_common.hpp>
namespace mapnik {
namespace {
struct apply_local_alignment
{
apply_local_alignment(view_transform const& t,
proj_transform const& prj_trans,
double & x, double & y)
: t_(t),
prj_trans_(prj_trans),
x_(x),
y_(y) {}
void operator() (geometry::polygon_vertex_adapter<double> & va)
{
using path_type = transform_path_adapter<view_transform, decltype(va)>;
path_type path(t_, va, prj_trans_);
path.rewind(0);
path.vertex(&x_, &y_);
}
template <typename Adapter>
void operator() (Adapter &)
{
// no-op
}
view_transform const& t_;
proj_transform const& prj_trans_;
double & x_;
double & y_;
};
}
coord<double, 2> pattern_offset(
symbolizer_base const & sym,
mapnik::feature_impl const & feature,
proj_transform const & prj_trans,
renderer_common const & common,
unsigned pattern_width,
unsigned pattern_height)
{
coord<double, 2> reference_position(0, 0);
pattern_alignment_enum alignment_type = get<pattern_alignment_enum, keys::alignment>(sym, feature, common.vars_);
if (alignment_type == LOCAL_ALIGNMENT)
{
apply_local_alignment apply(common.t_, prj_trans, reference_position.x, reference_position.y);
util::apply_visitor(geometry::vertex_processor<apply_local_alignment>(apply), feature.get_geometry());
}
else
{
common.t_.forward(&reference_position.x, &reference_position.y);
}
return coord<double, 2>(
std::fmod(-reference_position.x, pattern_width) + pattern_width,
std::fmod(-reference_position.y, pattern_height) + pattern_height);
}
}

View file

@ -41,8 +41,7 @@
namespace mapnik {
template <>
void render_pattern<image_rgba8>(rasterizer & ras,
marker_svg const& marker,
void render_pattern<image_rgba8>(marker_svg const& marker,
agg::trans_affine const& tr,
double opacity,
image_rgba8 & image)
@ -62,13 +61,13 @@ void render_pattern<image_rgba8>(rasterizer & ras,
pixfmt pixf(buf);
renderer_base renb(pixf);
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(marker.get_data()->source());
mapnik::svg::svg_path_adapter svg_path(stl_storage);
mapnik::svg::svg_renderer_agg<mapnik::svg::svg_path_adapter,
agg::pod_bvector<mapnik::svg::path_attributes>,
svg::vertex_stl_adapter<svg::svg_path_storage> stl_storage(marker.get_data()->source());
svg_path_adapter svg_path(stl_storage);
svg::svg_renderer_agg<svg_path_adapter,
svg_attribute_type,
renderer_solid,
pixfmt > svg_renderer(svg_path,
marker.get_data()->attributes());
pixfmt> svg_renderer(svg_path, marker.get_data()->attributes());
rasterizer ras;
svg_renderer.render(ras, sl, renb, mtx, opacity, bbox);
}

@ -1 +1 @@
Subproject commit bd8eab4b6a3c812832e332fff08fa9882f950233
Subproject commit 7309b0cea5b7add6e3e889ca51f730adaef70acc