True global pattern alignment, fixed local alignment

This commit is contained in:
Jiri Drbalek 2018-09-13 16:10:48 +02:00
parent 73b8369178
commit e472ad965e
5 changed files with 130 additions and 103 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,44 +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&) {}
image_rgba8 operator() (marker_null const&)
{
return image_rgba8();
}
void operator() (marker_svg const& marker)
image_rgba8 operator() (marker_svg const& marker)
{
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);
cairo_pattern pattern(image, opacity_);
pattern.set_extend(CAIRO_EXTEND_REPEAT);
pattern.set_origin(offset_x_, offset_y_);
context_.set_pattern(pattern);
return image;
}
void operator() (marker_rgba8 const& marker)
image_rgba8 operator() (marker_rgba8 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);
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
@ -122,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);
@ -149,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,
coord<double, 2> pattern_offset(
symbolizer_base const & sym,
feature_impl const & feature,
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) {}
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

@ -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

@ -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);
}
}