Merge pull request #3989 from mapycz/fix-pattern-alignment

True global pattern alignment, fixed local alignment
This commit is contained in:
talaj 2018-11-02 14:31:31 +01:00 committed by GitHub
commit 7dcf5ee082
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 141 additions and 117 deletions

View file

@ -29,6 +29,7 @@
#include <mapnik/renderer_common/apply_vertex_converter.hpp> #include <mapnik/renderer_common/apply_vertex_converter.hpp>
#include <mapnik/renderer_common/clipping_extent.hpp> #include <mapnik/renderer_common/clipping_extent.hpp>
#include <mapnik/vertex_converters.hpp> #include <mapnik/vertex_converters.hpp>
#include <mapnik/safe_cast.hpp>
#pragma GCC diagnostic push #pragma GCC diagnostic push
#include <mapnik/warning_ignore_agg.hpp> #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) void render(renderer_base & ren_base, rasterizer & ras)
{ {
pattern_alignment_enum alignment = get<pattern_alignment_enum, keys::alignment>( coord<double, 2> offset(pattern_offset(sym_, feature_, prj_trans_, common_,
sym_, feature_, common_.vars_); pattern_img_.width(), pattern_img_.height()));
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);
}
agg::rendering_buffer pattern_rbuf((agg::int8u*)pattern_img_.bytes(), agg::rendering_buffer pattern_rbuf((agg::int8u*)pattern_img_.bytes(),
pattern_img_.width(), pattern_img_.height(), pattern_img_.width(), pattern_img_.height(),
pattern_img_.width() * 4); pattern_img_.width() * 4);
agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf); agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf);
img_source_type img_src(pixf_pattern); 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; agg::span_allocator<agg::rgba8> sa;
value_double opacity = get<double, keys::opacity>(sym_, feature_, common_.vars_); 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 struct cairo_renderer_process_visitor_p
{ {
cairo_renderer_process_visitor_p(cairo_context & context, cairo_renderer_process_visitor_p(agg::trans_affine & image_tr)
agg::trans_affine & image_tr, : image_tr_(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) {}
void operator() (marker_null const&) {} image_rgba8 operator() (marker_null const&)
void operator() (marker_svg const& marker)
{ {
mapnik::rasterizer ras; return image_rgba8();
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);
} }
void operator() (marker_rgba8 const& marker) image_rgba8 operator() (marker_svg const& marker)
{ {
cairo_pattern pattern(marker.get_data(), opacity_); mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr_;
pattern.set_extend(CAIRO_EXTEND_REPEAT); mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height());
pattern.set_origin(offset_x_, offset_y_); render_pattern<image_rgba8>(marker, image_tr_, 1.0, image);
context_.set_pattern(pattern); return image;
}
image_rgba8 operator() (marker_rgba8 const& marker)
{
return marker.get_data();
} }
private: private:
cairo_context & context_;
agg::trans_affine & image_tr_; agg::trans_affine & image_tr_;
unsigned offset_x_;
unsigned offset_y_;
float opacity_;
}; };
struct cairo_pattern_base 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) 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_); value_double opacity = get<value_double, keys::opacity>(sym_, feature_, common_.vars_);
agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_);
auto image_transform = get_optional<transform_type>(sym_, keys::image_transform); 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); cairo_save_restore guard(context);
context.set_operator(comp_op); context.set_operator(comp_op);
util::apply_visitor(cairo_renderer_process_visitor_p( image_rgba8 pattern_img(util::apply_visitor(cairo_renderer_process_visitor_p(image_tr), marker_));
context, image_tr, offset_x, offset_y, opacity), 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 apply_vertex_converter_type = detail::apply_vertex_converter<VertexConverter, cairo_context>;
using vertex_processor_type = geometry::vertex_processor<apply_vertex_converter_type>; using vertex_processor_type = geometry::vertex_processor<apply_vertex_converter_type>;

View file

@ -20,56 +20,26 @@
* *
*****************************************************************************/ *****************************************************************************/
#ifndef MAPNIK_PATTERN_ALIGNMENT_HPP #ifndef MAPNIK_PATTERN_ALIGNMENT_HPP
#define MAPNIK_PATTERN_ALIGNMENT_HPP #define MAPNIK_PATTERN_ALIGNMENT_HPP
#include <mapnik/geometry.hpp> #include <mapnik/coord.hpp>
#include <mapnik/vertex_adapters.hpp>
#include <mapnik/transform_path_adapter.hpp>
#pragma GCC diagnostic push namespace mapnik {
#include <mapnik/warning_ignore_agg.hpp>
#include "agg_conv_clip_polygon.h"
#pragma GCC diagnostic pop
namespace mapnik { namespace detail { class symbolizer_base;
class feature_impl;
class proj_transform;
class renderer_common;
struct apply_local_alignment coord<double, 2> pattern_offset(
{ symbolizer_base const & sym,
apply_local_alignment(view_transform const& t, feature_impl const & feature,
proj_transform const& prj_trans, proj_transform const & prj_trans,
box2d<double> const& clip_box, renderer_common const & common,
double & x, double & y) unsigned pattern_width,
: t_(t), unsigned pattern_height);
prj_trans_(prj_trans),
clip_box_(clip_box),
x_(x),
y_(y) {}
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 #endif // MAPNIK_PATTERN_ALIGNMENT_HPP

View file

@ -38,8 +38,7 @@ struct rasterizer;
struct marker_svg; struct marker_svg;
template <typename T> template <typename T>
void render_pattern(rasterizer & ras, void render_pattern(marker_svg const& marker,
marker_svg const& marker,
agg::trans_affine const& tr, agg::trans_affine const& tr,
double opacity, double opacity,
T & image); 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_); 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::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr;
image_rgba8 image(bbox_image.width(), bbox_image.height()); 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); 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_); 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::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr;
mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); 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); render(image);
} }

View file

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

View file

@ -65,13 +65,12 @@ struct prepare_pattern_visitor
std::shared_ptr<cairo_pattern> operator() (mapnik::marker_svg const& marker) std::shared_ptr<cairo_pattern> operator() (mapnik::marker_svg const& marker)
{ {
double opacity = get<value_double, keys::opacity>(sym_, feature_, common_.vars_); 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_); agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_);
auto image_transform = get_optional<transform_type>(sym_, keys::image_transform); 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_); 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::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr;
mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); 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(); width_ = image.width();
height_ = image.height(); height_ = image.height();
return std::make_shared<cairo_pattern>(image, opacity); 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 { namespace mapnik {
template <> template <>
void render_pattern<image_rgba8>(rasterizer & ras, void render_pattern<image_rgba8>(marker_svg const& marker,
marker_svg const& marker,
agg::trans_affine const& tr, agg::trans_affine const& tr,
double opacity, double opacity,
image_rgba8 & image) image_rgba8 & image)
@ -68,6 +67,7 @@ void render_pattern<image_rgba8>(rasterizer & ras,
svg_attribute_type, svg_attribute_type,
renderer_solid, 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); svg_renderer.render(ras, sl, renb, mtx, opacity, bbox);
} }

@ -1 +1 @@
Subproject commit f527cc7438b64c5b21e8d909547a6708859098c1 Subproject commit 540fedb872bcc14af4e319e6e368b273a1660719