Merge pull request #4364 from mapnik/svg-group-render
Svg group renderer [WIP]
This commit is contained in:
commit
8d2388870a
55 changed files with 1254 additions and 581 deletions
|
@ -142,7 +142,10 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${MAPNIK_OUTPUT_DIR}")
|
|||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${MAPNIK_OUTPUT_DIR}/lib")
|
||||
|
||||
# needs to be before the first call of find_boost.
|
||||
if(CMAKE_CXX_STANDARD VERSION_LESS 17)
|
||||
list(APPEND MAPNIK_COMPILE_DEFS BOOST_SPIRIT_X3_HIDE_CXX17_WARNING)
|
||||
endif()
|
||||
|
||||
if(USE_MULTITHREADED)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
list(APPEND MAPNIK_COMPILE_DEFS MAPNIK_THREADSAFE)
|
||||
|
|
|
@ -43,7 +43,7 @@ ICU_LIBS_DEFAULT='/usr/'
|
|||
|
||||
DEFAULT_CC = "cc"
|
||||
DEFAULT_CXX = "c++"
|
||||
DEFAULT_CXX_STD = "14"
|
||||
DEFAULT_CXX_STD = "17"
|
||||
DEFAULT_CXX_CXXFLAGS = " -DU_USING_ICU_NAMESPACE=0"
|
||||
DEFAULT_CXX_LINKFLAGS = ""
|
||||
if sys.platform == 'darwin':
|
||||
|
@ -467,7 +467,7 @@ opts.AddVariables(
|
|||
BoolVariable('MAPNIK_RENDER', 'Compile and install a utility to render a map to an image', 'True'),
|
||||
BoolVariable('COLOR_PRINT', 'Print build status information in color', 'True'),
|
||||
BoolVariable('BIGINT', 'Compile support for 64-bit integers in mapnik::value', 'True'),
|
||||
BoolVariable('USE_BOOST_FILESYSTEM','Use boost::filesytem even if `std::filesystem` is avaible (since c++17)', 'False'),
|
||||
BoolVariable('USE_BOOST_FILESYSTEM','Use boost::filesytem even if `std::filesystem` is available (since c++17)', 'False'),
|
||||
BoolVariable('QUIET', 'Reduce build verbosity', 'False'),
|
||||
)
|
||||
|
||||
|
@ -1633,6 +1633,9 @@ if not preconfigured:
|
|||
if env['BIGINT']:
|
||||
env.Append(CPPDEFINES = '-DBIGINT')
|
||||
|
||||
if int(env['CXX_STD']) < 17:
|
||||
env['USE_BOOST_FILESYSTEM'] = True
|
||||
|
||||
if env['USE_BOOST_FILESYSTEM']:
|
||||
env.Append(CPPDEFINES = '-DUSE_BOOST_FILESYSTEM')
|
||||
|
||||
|
@ -1659,7 +1662,7 @@ if not preconfigured:
|
|||
['program_options', 'boost/program_options.hpp', False]
|
||||
]
|
||||
|
||||
if int(env['CXX_STD']) < 17 or env['USE_BOOST_FILESYSTEM']:
|
||||
if env['USE_BOOST_FILESYSTEM']:
|
||||
BOOST_LIBSHEADERS.append(['system', 'boost/system/system_error.hpp', True])
|
||||
BOOST_LIBSHEADERS.append(['filesystem', 'boost/filesystem/operations.hpp', True])
|
||||
# if requested, sort LIBPATH and CPPPATH before running CheckLibWithHeader tests
|
||||
|
|
|
@ -106,10 +106,7 @@ MainWindow::MainWindow()
|
|||
// slider
|
||||
connect(slider_, SIGNAL(valueChanged(int)), mapWidget_, SLOT(zoomToLevel(int)));
|
||||
// renderer selector
|
||||
connect(renderer_selector_,
|
||||
SIGNAL(currentIndexChanged(QString const&)),
|
||||
mapWidget_,
|
||||
SLOT(updateRenderer(QString const&)));
|
||||
connect(renderer_selector_, SIGNAL(currentIndexChanged(int)), mapWidget_, SLOT(updateRenderer(int)));
|
||||
|
||||
// scale factor
|
||||
connect(scale_factor_, SIGNAL(valueChanged(double)), mapWidget_, SLOT(updateScaleFactor(double)));
|
||||
|
@ -390,7 +387,7 @@ void MainWindow::createToolBars()
|
|||
|
||||
scale_factor_ = new QDoubleSpinBox(fileToolBar);
|
||||
scale_factor_->setMinimum(0.1);
|
||||
scale_factor_->setMaximum(5.0);
|
||||
scale_factor_->setMaximum(10.0);
|
||||
scale_factor_->setSingleStep(0.1);
|
||||
scale_factor_->setValue(1.0);
|
||||
|
||||
|
|
|
@ -545,15 +545,15 @@ void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap& pix)
|
|||
#endif
|
||||
}
|
||||
|
||||
void MapWidget::updateRenderer(QString const& txt)
|
||||
void MapWidget::updateRenderer(int index)
|
||||
{
|
||||
if (txt == "AGG")
|
||||
std::cerr << "updateRenderer:" << index << std::endl;
|
||||
if (index == 0)
|
||||
cur_renderer_ = AGG;
|
||||
else if (txt == "Cairo")
|
||||
else if (index == 1)
|
||||
cur_renderer_ = Cairo;
|
||||
else if (txt == "Grid")
|
||||
else if (index == 2)
|
||||
cur_renderer_ = Grid;
|
||||
std::cerr << "Update renderer called" << std::endl;
|
||||
updateMap();
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ class MapWidget : public QWidget
|
|||
void zoomToLevel(int level);
|
||||
void updateMap();
|
||||
void layerSelected(int);
|
||||
void updateRenderer(QString const& txt);
|
||||
void updateRenderer(int);
|
||||
void updateScaleFactor(double scale_factor);
|
||||
signals:
|
||||
void mapViewChanged();
|
||||
|
|
5
deps/agg/include/agg_pixfmt_rgba.h
vendored
5
deps/agg/include/agg_pixfmt_rgba.h
vendored
|
@ -24,6 +24,7 @@
|
|||
#ifndef AGG_PIXFMT_RGBA_INCLUDED
|
||||
#define AGG_PIXFMT_RGBA_INCLUDED
|
||||
|
||||
#include <mapnik/config.hpp>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include "agg_basics.h"
|
||||
|
@ -3166,6 +3167,10 @@ private:
|
|||
|
||||
|
||||
|
||||
extern template struct MAPNIK_DECL comp_op_rgba_hue<agg::rgba8, agg::order_rgba>;
|
||||
extern template struct MAPNIK_DECL comp_op_rgba_saturation<agg::rgba8, agg::order_rgba>;
|
||||
extern template struct MAPNIK_DECL comp_op_rgba_color<agg::rgba8, agg::order_rgba>;
|
||||
extern template struct MAPNIK_DECL comp_op_rgba_value<agg::rgba8, agg::order_rgba>;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
typedef blender_rgba<rgba8, order_rgba> blender_rgba32; //----blender_rgba32
|
||||
|
|
|
@ -92,7 +92,7 @@ class buffer_stack
|
|||
|
||||
void pop()
|
||||
{
|
||||
// ^ ensure irator is not out-of-range
|
||||
// ^ ensure iterator is not out-of-range
|
||||
// prior calling this method
|
||||
++position_;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class cairo_context;
|
|||
|
||||
void render_vector_marker(cairo_context& context,
|
||||
svg_path_adapter& svg_path,
|
||||
svg_attribute_type const& attributes,
|
||||
svg::group const& group_attr,
|
||||
box2d<double> const& bbox,
|
||||
agg::trans_affine const& tr,
|
||||
double opacity);
|
||||
|
|
|
@ -56,11 +56,11 @@ struct cairo_renderer_process_visitor_p
|
|||
cairo_context context(cairo);
|
||||
|
||||
svg_storage_type& svg = *marker.get_data();
|
||||
svg_attribute_type const& svg_attributes = svg.attributes();
|
||||
auto const& svg_group = svg.svg_group();
|
||||
svg::vertex_stl_adapter<svg::svg_path_storage> stl_storage(svg.source());
|
||||
svg::svg_path_adapter svg_path(stl_storage);
|
||||
|
||||
render_vector_marker(context, svg_path, svg_attributes, bbox, tr, opacity_);
|
||||
render_vector_marker(context, svg_path, svg_group, bbox, tr, opacity_);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,11 @@ struct layer_rendering_material;
|
|||
enum eAttributeCollectionPolicy { DEFAULT = 0, COLLECT_ALL = 1 };
|
||||
|
||||
template<typename Processor>
|
||||
#ifdef __GNUC__
|
||||
class MAPNIK_DECL feature_style_processor
|
||||
#else
|
||||
class feature_style_processor
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
explicit feature_style_processor(Map const& m, double scale_factor = 1.0);
|
||||
|
|
|
@ -42,6 +42,8 @@ MAPNIK_DISABLE_WARNING_POP
|
|||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/coord.hpp>
|
||||
#include <mapnik/geometry/box2d.hpp>
|
||||
// std
|
||||
#include <cstdint>
|
||||
|
||||
BOOST_GEOMETRY_REGISTER_POINT_2D(mapnik::geometry::point<double>, double, boost::geometry::cs::cartesian, x, y)
|
||||
BOOST_GEOMETRY_REGISTER_POINT_2D(mapnik::geometry::point<std::int64_t>,
|
||||
|
|
|
@ -30,8 +30,7 @@
|
|||
MAPNIK_DISABLE_WARNING_PUSH
|
||||
#include <mapnik/warning_ignore.hpp>
|
||||
#include <boost/spirit/include/karma.hpp>
|
||||
#include <boost/spirit/include/phoenix_function.hpp>
|
||||
#include <boost/spirit/home/karma/domain.hpp>
|
||||
#include <boost/phoenix/function.hpp>
|
||||
MAPNIK_DISABLE_WARNING_POP
|
||||
|
||||
#include <string>
|
||||
|
|
|
@ -56,7 +56,7 @@ struct vector_markers_dispatch : util::noncopyable
|
|||
{
|
||||
vector_markers_dispatch(svg_path_ptr const& src,
|
||||
svg_path_adapter& path,
|
||||
svg_attribute_type const& attrs,
|
||||
svg::group const& group_attrs,
|
||||
agg::trans_affine const& marker_trans,
|
||||
symbolizer_base const& sym,
|
||||
Detector& detector,
|
||||
|
@ -69,7 +69,7 @@ struct vector_markers_dispatch : util::noncopyable
|
|||
, renderer_context_(renderer_context)
|
||||
, src_(src)
|
||||
, path_(path)
|
||||
, attrs_(attrs)
|
||||
, group_attrs_(group_attrs)
|
||||
, detector_(detector)
|
||||
{}
|
||||
|
||||
|
@ -86,7 +86,7 @@ struct vector_markers_dispatch : util::noncopyable
|
|||
agg::trans_affine matrix = params_.placement_params.tr;
|
||||
matrix.rotate(angle);
|
||||
matrix.translate(x, y);
|
||||
renderer_context_.render_marker(src_, path_, attrs_, params_, matrix);
|
||||
renderer_context_.render_marker(src_, path_, group_attrs_, params_, matrix);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ struct vector_markers_dispatch : util::noncopyable
|
|||
markers_renderer_context& renderer_context_;
|
||||
svg_path_ptr const& src_;
|
||||
svg_path_adapter& path_;
|
||||
svg_attribute_type const& attrs_;
|
||||
svg::group const& group_attrs_;
|
||||
Detector& detector_;
|
||||
};
|
||||
|
||||
|
@ -152,8 +152,8 @@ void build_ellipse(symbolizer_base const& sym,
|
|||
svg_storage_type& marker_ellipse,
|
||||
svg::svg_path_adapter& svg_path);
|
||||
|
||||
bool push_explicit_style(svg_attribute_type const& src,
|
||||
svg_attribute_type& dst,
|
||||
bool push_explicit_style(svg::group const& src,
|
||||
svg::group& dst,
|
||||
symbolizer_base const& sym,
|
||||
feature_impl& feature,
|
||||
attributes const& vars);
|
||||
|
|
|
@ -27,7 +27,38 @@
|
|||
|
||||
namespace mapnik {
|
||||
|
||||
struct rotation;
|
||||
struct rotation
|
||||
{
|
||||
rotation()
|
||||
: sin(0)
|
||||
, cos(1.)
|
||||
{}
|
||||
rotation(double sin_, double cos_)
|
||||
: sin(sin_)
|
||||
, cos(cos_)
|
||||
{}
|
||||
rotation(double angle)
|
||||
: sin(std::sin(angle))
|
||||
, cos(std::cos(angle))
|
||||
{}
|
||||
void reset()
|
||||
{
|
||||
sin = 0.;
|
||||
cos = 1.;
|
||||
}
|
||||
void init(double angle)
|
||||
{
|
||||
sin = std::sin(angle);
|
||||
cos = std::cos(angle);
|
||||
}
|
||||
double sin;
|
||||
double cos;
|
||||
rotation operator~() const { return rotation(sin, -cos); }
|
||||
rotation operator!() const { return rotation(-sin, cos); }
|
||||
|
||||
double angle() const { return std::atan2(sin, cos); }
|
||||
};
|
||||
|
||||
struct pixel_position
|
||||
{
|
||||
double x;
|
||||
|
@ -59,11 +90,17 @@ struct pixel_position
|
|||
}
|
||||
|
||||
pixel_position rotate(rotation const& rot) const;
|
||||
|
||||
pixel_position operator~() const { return pixel_position(x, -y); }
|
||||
|
||||
double length() { return std::sqrt(x * x + y * y); }
|
||||
};
|
||||
|
||||
inline pixel_position pixel_position::rotate(rotation const& rot) const
|
||||
{
|
||||
return pixel_position(x * rot.cos - y * rot.sin, x * rot.sin + y * rot.cos);
|
||||
}
|
||||
|
||||
inline pixel_position operator*(double factor, pixel_position const& pos)
|
||||
{
|
||||
return pixel_position(factor * pos.x, factor * pos.y);
|
||||
|
|
|
@ -77,7 +77,8 @@ class MAPNIK_DECL projection
|
|||
std::string const& params() const;
|
||||
void forward(double& x, double& y) const;
|
||||
void inverse(double& x, double& y) const;
|
||||
std::string expanded() const;
|
||||
std::string definition() const;
|
||||
std::string description() const;
|
||||
void init_proj() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -58,7 +58,7 @@ struct markers_renderer_context : util::noncopyable
|
|||
|
||||
virtual void render_marker(svg_path_ptr const& src,
|
||||
svg_path_adapter& path,
|
||||
svg_attribute_type const& attrs,
|
||||
svg::group const& group_attrs,
|
||||
markers_dispatch_params const& params,
|
||||
agg::trans_affine const& marker_tr) = 0;
|
||||
};
|
||||
|
|
|
@ -44,20 +44,20 @@ namespace mapnik {
|
|||
struct vector_marker_render_thunk : util::movable
|
||||
{
|
||||
svg_path_ptr src_;
|
||||
svg_attribute_type attrs_;
|
||||
svg::group group_attrs_;
|
||||
agg::trans_affine tr_;
|
||||
double opacity_;
|
||||
composite_mode_e comp_op_;
|
||||
bool snap_to_pixels_;
|
||||
|
||||
vector_marker_render_thunk(svg_path_ptr const& src,
|
||||
svg_attribute_type const& attrs,
|
||||
svg::group const& group_attrs,
|
||||
agg::trans_affine const& marker_trans,
|
||||
double opacity,
|
||||
composite_mode_e comp_op,
|
||||
bool snap_to_pixels)
|
||||
: src_(src)
|
||||
, attrs_(attrs)
|
||||
, group_attrs_(group_attrs)
|
||||
, tr_(marker_trans)
|
||||
, opacity_(opacity)
|
||||
, comp_op_(comp_op)
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
MAPNIK_DISABLE_WARNING_PUSH
|
||||
#include <mapnik/warning_ignore.hpp>
|
||||
#include <boost/spirit/include/karma.hpp>
|
||||
#include <boost/spirit/include/phoenix_function.hpp>
|
||||
#include <boost/spirit/include/phoenix_operator.hpp>
|
||||
#include <boost/phoenix/function.hpp>
|
||||
#include <boost/phoenix/operator.hpp>
|
||||
#include <boost/fusion/adapted/std_tuple.hpp>
|
||||
#include <boost/type_traits/remove_pointer.hpp>
|
||||
MAPNIK_DISABLE_WARNING_POP
|
||||
|
|
114
include/mapnik/svg/svg_bounding_box.hpp
Normal file
114
include/mapnik/svg/svg_bounding_box.hpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2021 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_SVG_BOUNDING_BOX_HPP
|
||||
#define MAPNIK_SVG_BOUNDING_BOX_HPP
|
||||
|
||||
#include <mapnik/svg/svg_group.hpp>
|
||||
#include <mapnik/warning.hpp>
|
||||
MAPNIK_DISABLE_WARNING_PUSH
|
||||
#include <mapnik/warning_ignore_agg.hpp>
|
||||
#include "agg_basics.h"
|
||||
MAPNIK_DISABLE_WARNING_POP
|
||||
|
||||
namespace mapnik {
|
||||
namespace svg {
|
||||
namespace detail {
|
||||
template<typename VertexSource>
|
||||
struct bounding_box
|
||||
{
|
||||
bounding_box(VertexSource& vs, double& x1, double& y1, double& x2, double& y2, bool& first)
|
||||
: vs_(vs)
|
||||
, x1_(x1)
|
||||
, y1_(y1)
|
||||
, x2_(x2)
|
||||
, y2_(y2)
|
||||
, first_(first)
|
||||
{}
|
||||
|
||||
void operator()(group const& g) const
|
||||
{
|
||||
for (auto const& elem : g.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(bounding_box(vs_, x1_, y1_, x2_, y2_, first_), elem);
|
||||
}
|
||||
}
|
||||
void operator()(path_attributes const& attr) const
|
||||
{
|
||||
vs_.rewind(attr.index);
|
||||
vs_.transformer(const_cast<agg::trans_affine&>(attr.transform));
|
||||
unsigned cmd;
|
||||
double x;
|
||||
double y;
|
||||
while (!is_stop(cmd = vs_.vertex(&x, &y)))
|
||||
{
|
||||
if (is_vertex(cmd))
|
||||
{
|
||||
if (first_)
|
||||
{
|
||||
x1_ = x;
|
||||
y1_ = y;
|
||||
x2_ = x;
|
||||
y2_ = y;
|
||||
first_ = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x < x1_)
|
||||
x1_ = x;
|
||||
if (y < y1_)
|
||||
y1_ = y;
|
||||
if (x > x2_)
|
||||
x2_ = x;
|
||||
if (y > y2_)
|
||||
y2_ = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VertexSource& vs_;
|
||||
double& x1_;
|
||||
double& y1_;
|
||||
double& x2_;
|
||||
double& y2_;
|
||||
bool& first_;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template<typename VertexSource>
|
||||
void bounding_box(VertexSource& vs, group const& g, double& x1, double& y1, double& x2, double& y2)
|
||||
{
|
||||
bool first = true;
|
||||
x1 = 1.0;
|
||||
y1 = 1.0;
|
||||
x2 = 0.0;
|
||||
y2 = 0.0; // ^^ FIXME: AGG specific "invalid bbox" logic
|
||||
for (auto const& elem : g.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(detail::bounding_box<VertexSource>(vs, x1, y1, x2, y2, first), elem);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace svg
|
||||
} // namespace mapnik
|
||||
|
||||
#endif // MAPNIK_SVG_BOUNDING_BOX_HPP
|
|
@ -26,6 +26,7 @@
|
|||
// mapnik
|
||||
#include <mapnik/svg/svg_path_attributes.hpp>
|
||||
#include <mapnik/svg/svg_path_adapter.hpp>
|
||||
#include <mapnik/svg/svg_bounding_box.hpp>
|
||||
#include <mapnik/util/noncopyable.hpp>
|
||||
#include <mapnik/safe_cast.hpp>
|
||||
|
||||
|
@ -38,13 +39,16 @@ MAPNIK_DISABLE_WARNING_PUSH
|
|||
#include "agg_conv_contour.h"
|
||||
#include "agg_conv_curve.h"
|
||||
#include "agg_color_rgba.h"
|
||||
#include "agg_bounding_rect.h"
|
||||
MAPNIK_DISABLE_WARNING_POP
|
||||
|
||||
// stl
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <mapbox/variant.hpp>
|
||||
#include <mapnik/svg/svg_group.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
namespace svg {
|
||||
|
||||
|
@ -53,30 +57,41 @@ class svg_converter : util::noncopyable
|
|||
{
|
||||
public:
|
||||
|
||||
svg_converter(VertexSource& source, AttributeSource& attributes)
|
||||
svg_converter(VertexSource& source, group& svg_group)
|
||||
: source_(source)
|
||||
, attributes_(attributes)
|
||||
, svg_group_(svg_group)
|
||||
, attr_stack_()
|
||||
, svg_width_(0.0)
|
||||
, svg_height_(0.0)
|
||||
{}
|
||||
|
||||
void set_opacity(double opacity) { svg_group_.opacity = opacity; }
|
||||
|
||||
void begin_group()
|
||||
{
|
||||
current_group_->elements.emplace_back(group{cur_attr().opacity, {}, current_group_});
|
||||
current_group_ = ¤t_group_->elements.back().get<group>();
|
||||
}
|
||||
|
||||
void end_group() { current_group_ = current_group_->parent; }
|
||||
|
||||
void begin_path()
|
||||
{
|
||||
std::size_t idx = source_.start_new_path();
|
||||
attributes_.emplace_back(cur_attr(), safe_cast<unsigned>(idx));
|
||||
current_group_->elements.emplace_back(path_attributes{cur_attr(), safe_cast<unsigned>(idx)});
|
||||
}
|
||||
|
||||
void end_path()
|
||||
{
|
||||
if (attributes_.empty())
|
||||
if (current_group_->elements.empty())
|
||||
{
|
||||
throw std::runtime_error("end_path : The path was not begun");
|
||||
}
|
||||
path_attributes& attr = attributes_.back();
|
||||
unsigned idx = attr.index;
|
||||
attr = cur_attr();
|
||||
attr.index = idx;
|
||||
// auto& elem = current_group_->elements.back();
|
||||
// auto& attr = elem.get<path_attributes>();
|
||||
// unsigned index = attr.index;
|
||||
// attr = cur_attr();
|
||||
// attr.index = index;
|
||||
}
|
||||
|
||||
void move_to(double x, double y, bool rel = false) // M, m
|
||||
|
@ -295,17 +310,10 @@ class svg_converter : util::noncopyable
|
|||
// Make all polygons CCW-oriented
|
||||
void arrange_orientations() { source_.arrange_orientations_all_paths(agg::path_flags_ccw); }
|
||||
|
||||
// FIXME!!!!
|
||||
unsigned operator[](unsigned idx)
|
||||
{
|
||||
transform_ = attributes_[idx].transform;
|
||||
return attributes_[idx].index;
|
||||
}
|
||||
|
||||
void bounding_rect(double* x1, double* y1, double* x2, double* y2)
|
||||
{
|
||||
agg::conv_transform<mapnik::svg::svg_path_adapter> trans(source_, transform_);
|
||||
agg::bounding_rect(trans, *this, 0, attributes_.size(), x1, y1, x2, y2);
|
||||
agg::conv_transform<mapnik::svg::svg_path_adapter> path(source_, transform_);
|
||||
bounding_box(path, svg_group_, *x1, *y1, *x2, *y2);
|
||||
}
|
||||
|
||||
void set_dimensions(double w, double h)
|
||||
|
@ -334,7 +342,8 @@ class svg_converter : util::noncopyable
|
|||
private:
|
||||
|
||||
VertexSource& source_;
|
||||
AttributeSource& attributes_;
|
||||
group& svg_group_;
|
||||
group* current_group_ = &svg_group_;
|
||||
AttributeSource attr_stack_;
|
||||
agg::trans_affine transform_;
|
||||
double svg_width_;
|
||||
|
|
48
include/mapnik/svg/svg_group.hpp
Normal file
48
include/mapnik/svg/svg_group.hpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2021 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_SVG_GROUP_HPP
|
||||
#define MAPNIK_SVG_GROUP_HPP
|
||||
|
||||
#include <mapnik/svg/svg_path_attributes.hpp>
|
||||
#include <mapnik/svg/svg_path_adapter.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace mapnik {
|
||||
namespace svg {
|
||||
|
||||
struct group;
|
||||
|
||||
using group_element = mapbox::util::variant<path_attributes, group>;
|
||||
|
||||
struct group
|
||||
{
|
||||
double opacity = 1.0;
|
||||
std::vector<group_element> elements;
|
||||
group* parent = nullptr;
|
||||
};
|
||||
|
||||
} // namespace svg
|
||||
} // namespace mapnik
|
||||
|
||||
#endif // MAPNIK_SVG_GROUP_HPP
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
// mapnik
|
||||
#include <mapnik/svg/svg_path_attributes.hpp>
|
||||
#include <mapnik/svg/svg_converter.hpp>
|
||||
#include <mapnik/gradient.hpp>
|
||||
#include <mapnik/geometry/box2d.hpp>
|
||||
#include <mapnik/value/types.hpp>
|
||||
|
@ -41,6 +42,7 @@ MAPNIK_DISABLE_WARNING_POP
|
|||
#include <mapnik/warning.hpp>
|
||||
MAPNIK_DISABLE_WARNING_PUSH
|
||||
#include <mapnik/warning_ignore_agg.hpp>
|
||||
#include "agg_pixfmt_rgba.h"
|
||||
#include "agg_path_storage.h"
|
||||
#include "agg_conv_transform.h"
|
||||
#include "agg_conv_stroke.h"
|
||||
|
@ -62,6 +64,8 @@ MAPNIK_DISABLE_WARNING_PUSH
|
|||
#include "agg_span_interpolator_linear.h"
|
||||
MAPNIK_DISABLE_WARNING_POP
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace mapnik {
|
||||
namespace svg {
|
||||
|
||||
|
@ -124,16 +128,68 @@ class renderer_agg : util::noncopyable
|
|||
using vertex_source_type = VertexSource;
|
||||
using attribute_source_type = AttributeSource;
|
||||
|
||||
renderer_agg(VertexSource& source, AttributeSource const& attributes)
|
||||
// mapnik::svg_path_adapter, mapnik::svg_attribute_type, renderer_solid, agg::pixfmt_rgba32_pre
|
||||
renderer_agg(VertexSource& source, group const& svg_group)
|
||||
: source_(source)
|
||||
, curved_(source_)
|
||||
, curved_dashed_(curved_)
|
||||
, curved_stroked_(curved_)
|
||||
, curved_dashed_stroked_(curved_dashed_)
|
||||
, attributes_(attributes)
|
||||
, svg_group_(svg_group)
|
||||
{}
|
||||
|
||||
template<typename Rasterizer, typename Scanline, typename Renderer>
|
||||
void render(Rasterizer& ras,
|
||||
Scanline& sl,
|
||||
Renderer& ren,
|
||||
agg::trans_affine const& mtx,
|
||||
double opacity,
|
||||
box2d<double> const& symbol_bbox)
|
||||
|
||||
{
|
||||
double adjusted_opacity = opacity * svg_group_.opacity; // adjust top level opacity
|
||||
if (adjusted_opacity < 1.0)
|
||||
{
|
||||
mapnik::image_rgba8 im(ren.width(), ren.height(), true, true);
|
||||
agg::rendering_buffer buf(im.bytes(), im.width(), im.height(), im.row_size());
|
||||
PixelFormat pixf(buf);
|
||||
Renderer ren_g(pixf);
|
||||
for (auto const& elem : svg_group_.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(
|
||||
group_renderer<Rasterizer, Scanline, Renderer>(*this, ras, sl, ren_g, mtx, symbol_bbox),
|
||||
elem);
|
||||
}
|
||||
ren.blend_from(ren_g.ren(), 0, 0, 0, unsigned(adjusted_opacity * 255));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto const& elem : svg_group_.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(
|
||||
group_renderer<Rasterizer, Scanline, Renderer>(*this, ras, sl, ren, mtx, symbol_bbox),
|
||||
elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Rasterizer, typename Scanline, typename Renderer>
|
||||
struct group_renderer
|
||||
{
|
||||
group_renderer(renderer_agg& renderer,
|
||||
Rasterizer& ras,
|
||||
Scanline& sl,
|
||||
Renderer& ren,
|
||||
agg::trans_affine const& mtx,
|
||||
box2d<double> const& symbol_bbox)
|
||||
: renderer_(renderer)
|
||||
, ras_(ras)
|
||||
, sl_(sl)
|
||||
, ren_(ren)
|
||||
, mtx_(mtx)
|
||||
, symbol_bbox_(symbol_bbox)
|
||||
{}
|
||||
|
||||
void render_gradient(Rasterizer& ras,
|
||||
Scanline& sl,
|
||||
Renderer& ren,
|
||||
|
@ -142,7 +198,7 @@ class renderer_agg : util::noncopyable
|
|||
double opacity,
|
||||
box2d<double> const& symbol_bbox,
|
||||
curved_trans_type& curved_trans,
|
||||
unsigned path_id)
|
||||
unsigned path_id) const
|
||||
{
|
||||
using gamma_lut_type = agg::gamma_lut<agg::int8u, agg::int8u>;
|
||||
using color_func_type = agg::gradient_lut<agg::color_interpolator<agg::rgba8>, 1024>;
|
||||
|
@ -168,16 +224,14 @@ class renderer_agg : util::noncopyable
|
|||
}
|
||||
if (m_gradient_lut.build_lut())
|
||||
{
|
||||
agg::trans_affine transform = mtx;
|
||||
double scale = mtx.scale();
|
||||
transform.invert();
|
||||
agg::trans_affine tr;
|
||||
tr = grad.get_transform();
|
||||
tr.invert();
|
||||
agg::trans_affine tr = mtx;
|
||||
agg::trans_affine transform = grad.get_transform();
|
||||
transform *= tr;
|
||||
transform.invert();
|
||||
|
||||
if (grad.get_units() != USER_SPACE_ON_USE)
|
||||
{
|
||||
double scale = mtx.scale();
|
||||
double bx1 = symbol_bbox.minx();
|
||||
double by1 = symbol_bbox.miny();
|
||||
double bx2 = symbol_bbox.maxx();
|
||||
|
@ -190,7 +244,17 @@ class renderer_agg : util::noncopyable
|
|||
transform.translate(-bx1 / scale, -by1 / scale);
|
||||
transform.scale(scale / (bx2 - bx1), scale / (by2 - by1));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
double scaledown = 255;
|
||||
x1 /= scaledown; // fx
|
||||
y1 /= scaledown; // fy
|
||||
x2 /= scaledown; // cx
|
||||
y2 /= scaledown; // cy
|
||||
radius /= scaledown;
|
||||
transform.translate(-symbol_bbox.minx(), -symbol_bbox.miny());
|
||||
transform.scale(1 / scaledown, 1 / scaledown);
|
||||
}
|
||||
if (grad.get_gradient_type() == RADIAL)
|
||||
{
|
||||
using gradient_adaptor_type = agg::gradient_radial_focus;
|
||||
|
@ -199,7 +263,6 @@ class renderer_agg : util::noncopyable
|
|||
|
||||
// the agg radial gradient assumes it is centred on 0
|
||||
transform.translate(-x2, -y2);
|
||||
|
||||
// scale everything up since agg turns things into integers a bit too soon
|
||||
int scaleup = 255;
|
||||
radius *= scaleup;
|
||||
|
@ -207,8 +270,8 @@ class renderer_agg : util::noncopyable
|
|||
y1 *= scaleup;
|
||||
x2 *= scaleup;
|
||||
y2 *= scaleup;
|
||||
|
||||
transform.scale(scaleup, scaleup);
|
||||
|
||||
interpolator_type span_interpolator(transform);
|
||||
gradient_adaptor_type gradient_adaptor(radius, (x1 - x2), (y1 - y2));
|
||||
|
||||
|
@ -240,76 +303,89 @@ class renderer_agg : util::noncopyable
|
|||
}
|
||||
}
|
||||
|
||||
template<typename Rasterizer, typename Scanline, typename Renderer>
|
||||
void render(Rasterizer& ras,
|
||||
Scanline& sl,
|
||||
Renderer& ren,
|
||||
agg::trans_affine const& mtx,
|
||||
double opacity,
|
||||
box2d<double> const& symbol_bbox)
|
||||
void operator()(group const& g) const
|
||||
{
|
||||
double opacity = g.opacity;
|
||||
if (opacity < 1.0)
|
||||
{
|
||||
mapnik::image_rgba8 im(ren_.width(), ren_.height(), true, true);
|
||||
agg::rendering_buffer buf(im.bytes(), im.width(), im.height(), im.row_size());
|
||||
PixelFormat pixf(buf);
|
||||
Renderer ren(pixf);
|
||||
for (auto const& elem : g.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(group_renderer(renderer_, ras_, sl_, ren, mtx_, symbol_bbox_), elem);
|
||||
}
|
||||
ren_.blend_from(ren.ren(), 0, 0, 0, unsigned(opacity * 255));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto const& elem : g.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(group_renderer(renderer_, ras_, sl_, ren_, mtx_, symbol_bbox_), elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(path_attributes const& attr) const
|
||||
{
|
||||
using namespace agg;
|
||||
trans_affine transform;
|
||||
|
||||
curved_stroked_trans_type curved_stroked_trans(curved_stroked_, transform);
|
||||
curved_dashed_stroked_trans_type curved_dashed_stroked_trans(curved_dashed_stroked_, transform);
|
||||
curved_trans_type curved_trans(curved_, transform);
|
||||
curved_stroked_trans_type curved_stroked_trans(renderer_.curved_stroked_, transform);
|
||||
curved_dashed_stroked_trans_type curved_dashed_stroked_trans(renderer_.curved_dashed_stroked_, transform);
|
||||
curved_trans_type curved_trans(renderer_.curved_, transform);
|
||||
curved_trans_contour_type curved_trans_contour(curved_trans);
|
||||
|
||||
curved_trans_contour.auto_detect_orientation(true);
|
||||
|
||||
for (unsigned i = 0; i < attributes_.size(); ++i)
|
||||
{
|
||||
mapnik::svg::path_attributes const& attr = attributes_[i];
|
||||
if (!attr.visibility_flag)
|
||||
continue;
|
||||
return;
|
||||
|
||||
transform = attr.transform;
|
||||
|
||||
transform *= mtx;
|
||||
transform *= mtx_;
|
||||
double scl = transform.scale();
|
||||
// curved_.approximation_method(curve_inc);
|
||||
curved_.approximation_scale(scl);
|
||||
curved_.angle_tolerance(0.0);
|
||||
// renderer_.curved_.approximation_method(curve_inc);
|
||||
renderer_.curved_.approximation_scale(scl);
|
||||
renderer_.curved_.angle_tolerance(0.0);
|
||||
|
||||
typename PixelFormat::color_type color;
|
||||
|
||||
if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT)
|
||||
{
|
||||
ras.reset();
|
||||
ras_.reset();
|
||||
// https://github.com/mapnik/mapnik/issues/1129
|
||||
if (std::fabs(curved_trans_contour.width()) <= 1)
|
||||
{
|
||||
ras.add_path(curved_trans, attr.index);
|
||||
ras_.add_path(curved_trans, attr.index);
|
||||
}
|
||||
else
|
||||
{
|
||||
curved_trans_contour.miter_limit(attr.miter_limit);
|
||||
ras.add_path(curved_trans_contour, attr.index);
|
||||
ras_.add_path(curved_trans_contour, attr.index);
|
||||
}
|
||||
|
||||
if (attr.fill_gradient.get_gradient_type() != NO_GRADIENT)
|
||||
{
|
||||
render_gradient(ras,
|
||||
sl,
|
||||
ren,
|
||||
render_gradient(ras_,
|
||||
sl_,
|
||||
ren_,
|
||||
attr.fill_gradient,
|
||||
transform,
|
||||
attr.fill_opacity * attr.opacity * opacity,
|
||||
symbol_bbox,
|
||||
attr.fill_opacity,
|
||||
symbol_bbox_,
|
||||
curved_trans,
|
||||
attr.index);
|
||||
}
|
||||
else
|
||||
{
|
||||
ras.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero);
|
||||
ras_.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero);
|
||||
color = attr.fill_color;
|
||||
color.opacity(color.opacity() * attr.fill_opacity * attr.opacity * opacity);
|
||||
ScanlineRenderer ren_s(ren);
|
||||
color.opacity(color.opacity() * attr.fill_opacity);
|
||||
ScanlineRenderer ren_s(ren_);
|
||||
color.premultiply();
|
||||
ren_s.color(color);
|
||||
render_scanlines(ras, sl, ren_s);
|
||||
render_scanlines(ras_, sl_, ren_s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,97 +393,207 @@ class renderer_agg : util::noncopyable
|
|||
{
|
||||
if (attr.dash.size() > 0)
|
||||
{
|
||||
curved_dashed_stroked_.width(attr.stroke_width);
|
||||
curved_dashed_stroked_.line_join(attr.line_join);
|
||||
curved_dashed_stroked_.line_cap(attr.line_cap);
|
||||
curved_dashed_stroked_.miter_limit(attr.miter_limit);
|
||||
curved_dashed_stroked_.inner_join(inner_round);
|
||||
curved_dashed_stroked_.approximation_scale(scl);
|
||||
renderer_.curved_dashed_stroked_.width(attr.stroke_width);
|
||||
renderer_.curved_dashed_stroked_.line_join(attr.line_join);
|
||||
renderer_.curved_dashed_stroked_.line_cap(attr.line_cap);
|
||||
renderer_.curved_dashed_stroked_.miter_limit(attr.miter_limit);
|
||||
renderer_.curved_dashed_stroked_.inner_join(inner_round);
|
||||
renderer_.curved_dashed_stroked_.approximation_scale(scl);
|
||||
|
||||
// If the *visual* line width is considerable we
|
||||
// turn on processing of curve cups.
|
||||
//---------------------
|
||||
if (attr.stroke_width * scl > 1.0)
|
||||
{
|
||||
curved_.angle_tolerance(0.2);
|
||||
renderer_.curved_.angle_tolerance(0.2);
|
||||
}
|
||||
ras.reset();
|
||||
curved_dashed_.remove_all_dashes();
|
||||
ras_.reset();
|
||||
renderer_.curved_dashed_.remove_all_dashes();
|
||||
for (auto d : attr.dash)
|
||||
{
|
||||
curved_dashed_.add_dash(std::get<0>(d), std::get<1>(d));
|
||||
renderer_.curved_dashed_.add_dash(std::get<0>(d), std::get<1>(d));
|
||||
}
|
||||
curved_dashed_.dash_start(attr.dash_offset);
|
||||
ras.add_path(curved_dashed_stroked_trans, attr.index);
|
||||
renderer_.curved_dashed_.dash_start(attr.dash_offset);
|
||||
ras_.add_path(curved_dashed_stroked_trans, attr.index);
|
||||
if (attr.stroke_gradient.get_gradient_type() != NO_GRADIENT)
|
||||
{
|
||||
render_gradient(ras,
|
||||
sl,
|
||||
ren,
|
||||
render_gradient(ras_,
|
||||
sl_,
|
||||
ren_,
|
||||
attr.stroke_gradient,
|
||||
transform,
|
||||
attr.stroke_opacity * attr.opacity * opacity,
|
||||
symbol_bbox,
|
||||
attr.stroke_opacity,
|
||||
symbol_bbox_,
|
||||
curved_trans,
|
||||
attr.index);
|
||||
}
|
||||
else
|
||||
{
|
||||
ras.filling_rule(fill_non_zero);
|
||||
ras_.filling_rule(fill_non_zero);
|
||||
color = attr.stroke_color;
|
||||
color.opacity(color.opacity() * attr.stroke_opacity * attr.opacity * opacity);
|
||||
ScanlineRenderer ren_s(ren);
|
||||
color.opacity(color.opacity() * attr.stroke_opacity);
|
||||
ScanlineRenderer ren_s(ren_);
|
||||
color.premultiply();
|
||||
ren_s.color(color);
|
||||
render_scanlines(ras, sl, ren_s);
|
||||
render_scanlines(ras_, sl_, ren_s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
curved_stroked_.width(attr.stroke_width);
|
||||
curved_stroked_.line_join(attr.line_join);
|
||||
curved_stroked_.line_cap(attr.line_cap);
|
||||
curved_stroked_.miter_limit(attr.miter_limit);
|
||||
curved_stroked_.inner_join(inner_round);
|
||||
curved_stroked_.approximation_scale(scl);
|
||||
renderer_.curved_stroked_.width(attr.stroke_width);
|
||||
renderer_.curved_stroked_.line_join(attr.line_join);
|
||||
renderer_.curved_stroked_.line_cap(attr.line_cap);
|
||||
renderer_.curved_stroked_.miter_limit(attr.miter_limit);
|
||||
renderer_.curved_stroked_.inner_join(inner_round);
|
||||
renderer_.curved_stroked_.approximation_scale(scl);
|
||||
|
||||
// If the *visual* line width is considerable we
|
||||
// turn on processing of curve cups.
|
||||
//---------------------
|
||||
if (attr.stroke_width * scl > 1.0)
|
||||
{
|
||||
curved_.angle_tolerance(0.2);
|
||||
renderer_.curved_.angle_tolerance(0.2);
|
||||
}
|
||||
ras.reset();
|
||||
ras.add_path(curved_stroked_trans, attr.index);
|
||||
ras_.reset();
|
||||
ras_.add_path(curved_stroked_trans, attr.index);
|
||||
if (attr.stroke_gradient.get_gradient_type() != NO_GRADIENT)
|
||||
{
|
||||
render_gradient(ras,
|
||||
sl,
|
||||
ren,
|
||||
render_gradient(ras_,
|
||||
sl_,
|
||||
ren_,
|
||||
attr.stroke_gradient,
|
||||
transform,
|
||||
attr.stroke_opacity * attr.opacity * opacity,
|
||||
symbol_bbox,
|
||||
attr.stroke_opacity,
|
||||
symbol_bbox_,
|
||||
curved_trans,
|
||||
attr.index);
|
||||
}
|
||||
else
|
||||
{
|
||||
ras.filling_rule(fill_non_zero);
|
||||
ras_.filling_rule(fill_non_zero);
|
||||
color = attr.stroke_color;
|
||||
color.opacity(color.opacity() * attr.stroke_opacity * attr.opacity * opacity);
|
||||
ScanlineRenderer ren_s(ren);
|
||||
color.opacity(color.opacity() * attr.stroke_opacity);
|
||||
ScanlineRenderer ren_s(ren_);
|
||||
color.premultiply();
|
||||
ren_s.color(color);
|
||||
render_scanlines(ras, sl, ren_s);
|
||||
render_scanlines(ras_, sl_, ren_s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
renderer_agg& renderer_;
|
||||
Rasterizer& ras_;
|
||||
Scanline& sl_;
|
||||
Renderer& ren_;
|
||||
agg::trans_affine const& mtx_;
|
||||
box2d<double> const& symbol_bbox_;
|
||||
};
|
||||
|
||||
#if defined(GRID_RENDERER)
|
||||
|
||||
template<typename Rasterizer, typename Scanline, typename Renderer>
|
||||
struct grid_renderer
|
||||
{
|
||||
grid_renderer(renderer_agg& renderer,
|
||||
Rasterizer& ras,
|
||||
Scanline& sl,
|
||||
Renderer& ren,
|
||||
agg::trans_affine const& mtx,
|
||||
mapnik::value_integer const& feature_id)
|
||||
: renderer_(renderer)
|
||||
, ras_(ras)
|
||||
, sl_(sl)
|
||||
, ren_(ren)
|
||||
, mtx_(mtx)
|
||||
, feature_id_(feature_id)
|
||||
{}
|
||||
|
||||
void operator()(group const& g) const
|
||||
{
|
||||
for (auto const& elem : g.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(grid_renderer(renderer_, ras_, sl_, ren_, mtx_, feature_id_), elem);
|
||||
}
|
||||
}
|
||||
void operator()(path_attributes const& attr) const
|
||||
{
|
||||
using namespace agg;
|
||||
|
||||
trans_affine transform;
|
||||
curved_stroked_trans_type curved_stroked_trans(renderer_.curved_stroked_, transform);
|
||||
curved_trans_type curved_trans(renderer_.curved_, transform);
|
||||
curved_trans_contour_type curved_trans_contour(curved_trans);
|
||||
|
||||
curved_trans_contour.auto_detect_orientation(true);
|
||||
|
||||
if (!attr.visibility_flag)
|
||||
return;
|
||||
|
||||
transform = attr.transform;
|
||||
transform *= mtx_;
|
||||
|
||||
double scl = transform.scale();
|
||||
// renderer_.curved_.approximation_method(curve_inc);
|
||||
renderer_.curved_.approximation_scale(scl);
|
||||
renderer_.curved_.angle_tolerance(0.0);
|
||||
|
||||
typename PixelFormat::color_type color{feature_id_};
|
||||
|
||||
if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT)
|
||||
{
|
||||
ras_.reset();
|
||||
|
||||
if (std::fabs(curved_trans_contour.width()) <= 1)
|
||||
{
|
||||
ras_.add_path(curved_trans, attr.index);
|
||||
}
|
||||
else
|
||||
{
|
||||
curved_trans_contour.miter_limit(attr.miter_limit);
|
||||
ras_.add_path(curved_trans_contour, attr.index);
|
||||
}
|
||||
|
||||
ras_.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero);
|
||||
ScanlineRenderer ren_s(ren_);
|
||||
ren_s.color(color);
|
||||
render_scanlines(ras_, sl_, ren_s);
|
||||
}
|
||||
|
||||
if (attr.stroke_flag || attr.stroke_gradient.get_gradient_type() != NO_GRADIENT)
|
||||
{
|
||||
renderer_.curved_stroked_.width(attr.stroke_width);
|
||||
// m_curved_stroked.line_join((attr.line_join == miter_join) ? miter_join_round : attr.line_join);
|
||||
renderer_.curved_stroked_.line_join(attr.line_join);
|
||||
renderer_.curved_stroked_.line_cap(attr.line_cap);
|
||||
renderer_.curved_stroked_.miter_limit(attr.miter_limit);
|
||||
renderer_.curved_stroked_.inner_join(inner_round);
|
||||
renderer_.curved_stroked_.approximation_scale(scl);
|
||||
|
||||
// If the *visual* line width is considerable we
|
||||
// turn on processing of curve cusps.
|
||||
//---------------------
|
||||
if (attr.stroke_width * scl > 1.0)
|
||||
{
|
||||
renderer_.curved_.angle_tolerance(0.2);
|
||||
}
|
||||
ras_.reset();
|
||||
ras_.add_path(curved_stroked_trans, attr.index);
|
||||
|
||||
ras_.filling_rule(fill_non_zero);
|
||||
ScanlineRenderer ren_s(ren_);
|
||||
ren_s.color(color);
|
||||
render_scanlines(ras_, sl_, ren_s);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(GRID_RENDERER)
|
||||
renderer_agg& renderer_;
|
||||
Rasterizer& ras_;
|
||||
Scanline& sl_;
|
||||
Renderer& ren_;
|
||||
agg::trans_affine const& mtx_;
|
||||
mapnik::value_integer const& feature_id_;
|
||||
};
|
||||
|
||||
template<typename Rasterizer, typename Scanline, typename Renderer>
|
||||
void render_id(Rasterizer& ras,
|
||||
Scanline& sl,
|
||||
|
@ -418,76 +604,11 @@ class renderer_agg : util::noncopyable
|
|||
box2d<double> const& /*symbol_bbox*/)
|
||||
|
||||
{
|
||||
using namespace agg;
|
||||
|
||||
trans_affine transform;
|
||||
curved_stroked_trans_type curved_stroked_trans(curved_stroked_, transform);
|
||||
curved_trans_type curved_trans(curved_, transform);
|
||||
curved_trans_contour_type curved_trans_contour(curved_trans);
|
||||
|
||||
curved_trans_contour.auto_detect_orientation(true);
|
||||
|
||||
for (unsigned i = 0; i < attributes_.size(); ++i)
|
||||
for (auto const& elem : svg_group_.elements)
|
||||
{
|
||||
mapnik::svg::path_attributes const& attr = attributes_[i];
|
||||
if (!attr.visibility_flag)
|
||||
continue;
|
||||
|
||||
transform = attr.transform;
|
||||
|
||||
transform *= mtx;
|
||||
double scl = transform.scale();
|
||||
// curved_.approximation_method(curve_inc);
|
||||
curved_.approximation_scale(scl);
|
||||
curved_.angle_tolerance(0.0);
|
||||
|
||||
typename PixelFormat::color_type color(feature_id);
|
||||
|
||||
if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT)
|
||||
{
|
||||
ras.reset();
|
||||
|
||||
if (std::fabs(curved_trans_contour.width()) <= 1)
|
||||
{
|
||||
ras.add_path(curved_trans, attr.index);
|
||||
}
|
||||
else
|
||||
{
|
||||
curved_trans_contour.miter_limit(attr.miter_limit);
|
||||
ras.add_path(curved_trans_contour, attr.index);
|
||||
}
|
||||
|
||||
ras.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero);
|
||||
ScanlineRenderer ren_s(ren);
|
||||
ren_s.color(color);
|
||||
render_scanlines(ras, sl, ren_s);
|
||||
}
|
||||
|
||||
if (attr.stroke_flag || attr.stroke_gradient.get_gradient_type() != NO_GRADIENT)
|
||||
{
|
||||
curved_stroked_.width(attr.stroke_width);
|
||||
// m_curved_stroked.line_join((attr.line_join == miter_join) ? miter_join_round : attr.line_join);
|
||||
curved_stroked_.line_join(attr.line_join);
|
||||
curved_stroked_.line_cap(attr.line_cap);
|
||||
curved_stroked_.miter_limit(attr.miter_limit);
|
||||
curved_stroked_.inner_join(inner_round);
|
||||
curved_stroked_.approximation_scale(scl);
|
||||
|
||||
// If the *visual* line width is considerable we
|
||||
// turn on processing of curve cusps.
|
||||
//---------------------
|
||||
if (attr.stroke_width * scl > 1.0)
|
||||
{
|
||||
curved_.angle_tolerance(0.2);
|
||||
}
|
||||
ras.reset();
|
||||
ras.add_path(curved_stroked_trans, attr.index);
|
||||
|
||||
ras.filling_rule(fill_non_zero);
|
||||
ScanlineRenderer ren_s(ren);
|
||||
ren_s.color(color);
|
||||
render_scanlines(ras, sl, ren_s);
|
||||
}
|
||||
mapbox::util::apply_visitor(
|
||||
grid_renderer<Rasterizer, Scanline, Renderer>(*this, ras, sl, ren, mtx, feature_id),
|
||||
elem);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -496,9 +617,10 @@ class renderer_agg : util::noncopyable
|
|||
{
|
||||
return source_;
|
||||
}
|
||||
inline AttributeSource const& attributes() const
|
||||
|
||||
inline group const& svg_group() const
|
||||
{
|
||||
return attributes_;
|
||||
return svg_group_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -508,7 +630,7 @@ class renderer_agg : util::noncopyable
|
|||
curved_dashed_type curved_dashed_;
|
||||
curved_stroked_type curved_stroked_;
|
||||
curved_dashed_stroked_type curved_dashed_stroked_;
|
||||
AttributeSource const& attributes_;
|
||||
group const& svg_group_;
|
||||
};
|
||||
|
||||
} // namespace svg
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
// mapnik
|
||||
#include <mapnik/geometry/box2d.hpp>
|
||||
#include <mapnik/util/noncopyable.hpp>
|
||||
#include <mapnik/svg/svg_group.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
namespace svg {
|
||||
|
@ -39,15 +40,9 @@ class svg_storage : util::noncopyable
|
|||
, svg_height_(0)
|
||||
{}
|
||||
|
||||
VertexSource& source() // FIXME!! make const
|
||||
{
|
||||
return source_;
|
||||
}
|
||||
VertexSource& source() { return source_; }
|
||||
|
||||
AttributeSource& attributes() // FIXME!! make const
|
||||
{
|
||||
return attributes_;
|
||||
}
|
||||
svg::group& svg_group() { return svg_group_; }
|
||||
|
||||
void set_bounding_box(box2d<double> const& b) { bounding_box_ = b; }
|
||||
|
||||
|
@ -68,7 +63,7 @@ class svg_storage : util::noncopyable
|
|||
private:
|
||||
|
||||
VertexSource source_;
|
||||
AttributeSource attributes_;
|
||||
svg::group svg_group_;
|
||||
box2d<double> bounding_box_;
|
||||
double svg_width_;
|
||||
double svg_height_;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
// mapnik
|
||||
#include <mapnik/geometry/box2d.hpp>
|
||||
#include <mapnik/pixel_position.hpp>
|
||||
#include <mapnik/text/rotation.hpp>
|
||||
#include <mapnik/marker_cache.hpp>
|
||||
#include <mapnik/text/glyph_info.hpp>
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <mapnik/pixel_position.hpp>
|
||||
#include <mapnik/text/text_layout.hpp>
|
||||
#include <mapnik/text/glyph_positions.hpp>
|
||||
#include <mapnik/text/rotation.hpp>
|
||||
#include <mapnik/util/noncopyable.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef MAPNIK_ROTATION_HPP
|
||||
#define MAPNIK_ROTATION_HPP
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
struct rotation
|
||||
{
|
||||
rotation()
|
||||
: sin(0)
|
||||
, cos(1.)
|
||||
{}
|
||||
rotation(double sin_, double cos_)
|
||||
: sin(sin_)
|
||||
, cos(cos_)
|
||||
{}
|
||||
rotation(double angle)
|
||||
: sin(std::sin(angle))
|
||||
, cos(std::cos(angle))
|
||||
{}
|
||||
void reset()
|
||||
{
|
||||
sin = 0.;
|
||||
cos = 1.;
|
||||
}
|
||||
void init(double angle)
|
||||
{
|
||||
sin = std::sin(angle);
|
||||
cos = std::cos(angle);
|
||||
}
|
||||
double sin;
|
||||
double cos;
|
||||
rotation operator~() const { return rotation(sin, -cos); }
|
||||
rotation operator!() const { return rotation(-sin, cos); }
|
||||
|
||||
double angle() const { return std::atan2(sin, cos); }
|
||||
};
|
||||
} // namespace mapnik
|
||||
|
||||
#endif // ROTATION_HPP
|
|
@ -33,7 +33,6 @@
|
|||
#include <mapnik/text/itemizer.hpp>
|
||||
#include <mapnik/font_engine_freetype.hpp>
|
||||
#include <mapnik/text/evaluated_format_properties_ptr.hpp>
|
||||
#include <mapnik/text/rotation.hpp>
|
||||
|
||||
// stl
|
||||
#include <vector>
|
||||
|
|
|
@ -44,6 +44,8 @@ endif()
|
|||
|
||||
set_target_properties(mapnik PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
VISIBILITY_INLINES_HIDDEN ON
|
||||
OUTPUT_NAME "mapnik"
|
||||
PREFIX "lib"
|
||||
IMPORT_PREFIX "lib" # for the archive on dll platforms
|
||||
|
|
|
@ -432,7 +432,7 @@ struct agg_render_marker_visitor
|
|||
svg_path_adapter svg_path(stl_storage);
|
||||
svg::renderer_agg<svg_path_adapter, svg_attribute_type, renderer_type, pixfmt_comp_type> svg_renderer(
|
||||
svg_path,
|
||||
marker.get_data()->attributes());
|
||||
marker.get_data()->svg_group());
|
||||
|
||||
// https://github.com/mapnik/mapnik/issues/1316
|
||||
// https://github.com/mapnik/mapnik/issues/1866
|
||||
|
|
|
@ -92,7 +92,7 @@ struct thunk_renderer<image_rgba8> : render_thunk_list_dispatch
|
|||
renderer_base renb(pixf);
|
||||
svg::vertex_stl_adapter<svg::svg_path_storage> stl_storage(thunk.src_->source());
|
||||
svg_path_adapter svg_path(stl_storage);
|
||||
svg_renderer_type svg_renderer(svg_path, thunk.attrs_);
|
||||
svg_renderer_type svg_renderer(svg_path, thunk.group_attrs_);
|
||||
|
||||
agg::trans_affine offset_tr = thunk.tr_;
|
||||
offset_tr.translate(offset_.x, offset_.y);
|
||||
|
|
|
@ -75,11 +75,11 @@ struct agg_markers_renderer_context : markers_renderer_context
|
|||
|
||||
virtual void render_marker(svg_path_ptr const& src,
|
||||
svg_path_adapter& path,
|
||||
svg_attribute_type const& attrs,
|
||||
svg::group const& group_attrs,
|
||||
markers_dispatch_params const& params,
|
||||
agg::trans_affine const& marker_tr)
|
||||
{
|
||||
SvgRenderer svg_renderer(path, attrs);
|
||||
SvgRenderer svg_renderer(path, group_attrs);
|
||||
render_vector_marker(svg_renderer,
|
||||
ras_,
|
||||
renb_,
|
||||
|
|
|
@ -36,7 +36,7 @@ cairo_face::cairo_face(std::shared_ptr<font_library> const& library, face_ptr co
|
|||
: face_(face)
|
||||
{
|
||||
static cairo_user_data_key_t key;
|
||||
c_face_ = cairo_ft_font_face_create_for_ft_face(face->get_face(), FT_LOAD_NO_HINTING);
|
||||
c_face_ = cairo_ft_font_face_create_for_ft_face(face->get_face(), FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
|
||||
cairo_font_face_set_user_data(c_face_, &key, new handle(library, face), destroy);
|
||||
}
|
||||
|
||||
|
@ -381,6 +381,7 @@ void cairo_context::add_image(agg::trans_affine const& tr, image_rgba8 const& da
|
|||
void cairo_context::set_font_face(cairo_face_manager& manager, face_ptr face)
|
||||
{
|
||||
cairo_set_font_face(cairo_.get(), manager.get_face(face)->face());
|
||||
check_object_status_and_throw_exception(*this);
|
||||
}
|
||||
|
||||
void cairo_context::set_font_matrix(cairo_matrix_t const& matrix)
|
||||
|
|
|
@ -30,23 +30,49 @@
|
|||
#include <mapnik/svg/svg_path_attributes.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
void render_vector_marker(cairo_context& context,
|
||||
svg_path_adapter& svg_path,
|
||||
svg_attribute_type const& attributes,
|
||||
|
||||
box2d<double> const& bbox,
|
||||
agg::trans_affine const& tr,
|
||||
double opacity)
|
||||
namespace {
|
||||
struct group_renderer
|
||||
{
|
||||
agg::trans_affine transform;
|
||||
group_renderer(agg::trans_affine const& transform,
|
||||
cairo_context& context,
|
||||
svg_path_adapter& svg_path,
|
||||
box2d<double> const& bbox)
|
||||
: transform_(transform)
|
||||
, context_(context)
|
||||
, svg_path_(svg_path)
|
||||
, bbox_(bbox)
|
||||
{}
|
||||
|
||||
for (auto const& attr : attributes)
|
||||
void operator()(svg::group const& g) const
|
||||
{
|
||||
double opacity = g.opacity;
|
||||
if (opacity < 1.0)
|
||||
{
|
||||
context_.push_group();
|
||||
for (auto const& elem : g.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(group_renderer(transform_, context_, svg_path_, bbox_), elem);
|
||||
}
|
||||
context_.pop_group();
|
||||
context_.paint(opacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto const& elem : g.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(group_renderer(transform_, context_, svg_path_, bbox_), elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(svg::path_attributes const& attr) const
|
||||
{
|
||||
if (!attr.visibility_flag)
|
||||
continue;
|
||||
cairo_save_restore guard(context);
|
||||
transform = attr.transform;
|
||||
transform *= tr;
|
||||
return;
|
||||
cairo_save_restore guard(context_);
|
||||
agg::trans_affine transform = attr.transform;
|
||||
transform *= transform_;
|
||||
|
||||
// TODO - this 'is_valid' check is not used in the AGG renderer and also
|
||||
// appears to lead to bogus results with
|
||||
|
@ -58,66 +84,99 @@ void render_vector_marker(cairo_context& context,
|
|||
transform.store_to(m);
|
||||
cairo_matrix_t matrix;
|
||||
cairo_matrix_init(&matrix, m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||
context.transform(matrix);
|
||||
context_.transform(matrix);
|
||||
}
|
||||
|
||||
if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT)
|
||||
{
|
||||
context.add_agg_path(svg_path, attr.index);
|
||||
context_.add_agg_path(svg_path_, attr.index);
|
||||
if (attr.even_odd_flag)
|
||||
{
|
||||
context.set_fill_rule(CAIRO_FILL_RULE_EVEN_ODD);
|
||||
context_.set_fill_rule(CAIRO_FILL_RULE_EVEN_ODD);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.set_fill_rule(CAIRO_FILL_RULE_WINDING);
|
||||
context_.set_fill_rule(CAIRO_FILL_RULE_WINDING);
|
||||
}
|
||||
if (attr.fill_gradient.get_gradient_type() != NO_GRADIENT)
|
||||
{
|
||||
cairo_gradient g(attr.fill_gradient, attr.fill_opacity * attr.opacity * opacity);
|
||||
cairo_gradient g(attr.fill_gradient, attr.fill_opacity * attr.opacity);
|
||||
|
||||
context.set_gradient(g, bbox);
|
||||
context.fill();
|
||||
context_.set_gradient(g, bbox_);
|
||||
context_.fill();
|
||||
}
|
||||
else if (attr.fill_flag)
|
||||
{
|
||||
double fill_opacity = attr.fill_opacity * attr.opacity * opacity * attr.fill_color.opacity();
|
||||
context.set_color(attr.fill_color.r / 255.0,
|
||||
double fill_opacity = attr.fill_opacity * attr.opacity * attr.fill_color.opacity();
|
||||
context_.set_color(attr.fill_color.r / 255.0,
|
||||
attr.fill_color.g / 255.0,
|
||||
attr.fill_color.b / 255.0,
|
||||
fill_opacity);
|
||||
context.fill();
|
||||
context_.fill();
|
||||
}
|
||||
}
|
||||
|
||||
if (attr.stroke_gradient.get_gradient_type() != NO_GRADIENT || attr.stroke_flag)
|
||||
{
|
||||
context.add_agg_path(svg_path, attr.index);
|
||||
context_.add_agg_path(svg_path_, attr.index);
|
||||
if (attr.stroke_gradient.get_gradient_type() != NO_GRADIENT)
|
||||
{
|
||||
context.set_line_width(attr.stroke_width);
|
||||
context.set_line_cap(line_cap_enum(attr.line_cap));
|
||||
context.set_line_join(line_join_enum(attr.line_join));
|
||||
context.set_miter_limit(attr.miter_limit);
|
||||
cairo_gradient g(attr.stroke_gradient, attr.fill_opacity * attr.opacity * opacity);
|
||||
context.set_gradient(g, bbox);
|
||||
context.stroke();
|
||||
context_.set_line_width(attr.stroke_width);
|
||||
context_.set_line_cap(line_cap_enum(attr.line_cap));
|
||||
context_.set_line_join(line_join_enum(attr.line_join));
|
||||
context_.set_miter_limit(attr.miter_limit);
|
||||
cairo_gradient g(attr.stroke_gradient, attr.fill_opacity * attr.opacity);
|
||||
context_.set_gradient(g, bbox_);
|
||||
context_.stroke();
|
||||
}
|
||||
else if (attr.stroke_flag)
|
||||
{
|
||||
double stroke_opacity = attr.stroke_opacity * attr.opacity * opacity * attr.stroke_color.opacity();
|
||||
context.set_color(attr.stroke_color.r / 255.0,
|
||||
double stroke_opacity = attr.stroke_opacity * attr.opacity * attr.stroke_color.opacity();
|
||||
context_.set_color(attr.stroke_color.r / 255.0,
|
||||
attr.stroke_color.g / 255.0,
|
||||
attr.stroke_color.b / 255.0,
|
||||
stroke_opacity);
|
||||
context.set_line_width(attr.stroke_width);
|
||||
context.set_line_cap(line_cap_enum(attr.line_cap));
|
||||
context.set_line_join(line_join_enum(attr.line_join));
|
||||
context.set_miter_limit(attr.miter_limit);
|
||||
context.stroke();
|
||||
context_.set_line_width(attr.stroke_width);
|
||||
context_.set_line_cap(line_cap_enum(attr.line_cap));
|
||||
context_.set_line_join(line_join_enum(attr.line_join));
|
||||
context_.set_miter_limit(attr.miter_limit);
|
||||
context_.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
agg::trans_affine const& transform_;
|
||||
cairo_context& context_;
|
||||
svg_path_adapter& svg_path_;
|
||||
box2d<double> const& bbox_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void render_vector_marker(cairo_context& context,
|
||||
svg_path_adapter& svg_path,
|
||||
svg::group const& group_attrs,
|
||||
box2d<double> const& bbox,
|
||||
agg::trans_affine const& tr,
|
||||
double opacity)
|
||||
{
|
||||
double adjusted_opacity = opacity * group_attrs.opacity; // adjust top level opacity
|
||||
if (adjusted_opacity < 1.0)
|
||||
{
|
||||
context.push_group();
|
||||
for (auto const& elem : group_attrs.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(group_renderer(tr, context, svg_path, bbox), elem);
|
||||
}
|
||||
context.pop_group();
|
||||
context.paint(opacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto const& elem : group_attrs.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(group_renderer(tr, context, svg_path, bbox), elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mapnik
|
||||
|
|
|
@ -269,11 +269,10 @@ struct cairo_render_marker_visitor
|
|||
marker_tr *= tr_;
|
||||
}
|
||||
marker_tr *= agg::trans_affine_scaling(common_.scale_factor_);
|
||||
auto const& attributes = vmarker->attributes();
|
||||
svg::vertex_stl_adapter<svg::svg_path_storage> stl_storage(vmarker->source());
|
||||
svg::svg_path_adapter svg_path(stl_storage);
|
||||
marker_tr.translate(pos_.x, pos_.y);
|
||||
render_vector_marker(context_, svg_path, attributes, bbox, marker_tr, opacity_);
|
||||
render_vector_marker(context_, svg_path, vmarker->svg_group(), bbox, marker_tr, opacity_);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ struct thunk_renderer : render_thunk_list_dispatch
|
|||
offset_tr.translate(offset_.x, offset_.y);
|
||||
mapnik::render_vector_marker(context_,
|
||||
svg_path,
|
||||
thunk.attrs_,
|
||||
thunk.group_attrs_,
|
||||
thunk.src_->bounding_box(),
|
||||
offset_tr,
|
||||
thunk.opacity_);
|
||||
|
|
|
@ -40,11 +40,11 @@ struct cairo_markers_renderer_context : markers_renderer_context
|
|||
|
||||
virtual void render_marker(svg_path_ptr const& src,
|
||||
svg_path_adapter& path,
|
||||
svg_attribute_type const& attrs,
|
||||
svg::group const& group_attrs,
|
||||
markers_dispatch_params const& params,
|
||||
agg::trans_affine const& marker_tr)
|
||||
{
|
||||
render_vector_marker(ctx_, path, attrs, src->bounding_box(), marker_tr, params.opacity);
|
||||
render_vector_marker(ctx_, path, group_attrs, src->bounding_box(), marker_tr, params.opacity);
|
||||
}
|
||||
|
||||
virtual void
|
||||
|
|
|
@ -184,7 +184,7 @@ struct grid_render_marker_visitor
|
|||
svg_path_adapter svg_path(stl_storage);
|
||||
svg::renderer_agg<svg_path_adapter, svg_attribute_type, renderer_type, pixfmt_type> svg_renderer(
|
||||
svg_path,
|
||||
marker.get_data()->attributes());
|
||||
marker.get_data()->svg_group());
|
||||
|
||||
svg_renderer.render_id(*ras_ptr_, sl, renb, feature_.id(), mtx, opacity_, bbox);
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ struct thunk_renderer : render_thunk_list_dispatch
|
|||
renderer_type ren(renb);
|
||||
svg::vertex_stl_adapter<svg::svg_path_storage> stl_storage(thunk.src_->source());
|
||||
svg_path_adapter svg_path(stl_storage);
|
||||
svg_renderer_type svg_renderer(svg_path, thunk.attrs_);
|
||||
svg_renderer_type svg_renderer(svg_path, thunk.group_attrs_);
|
||||
agg::trans_affine offset_tr = thunk.tr_;
|
||||
offset_tr.translate(offset_.x, offset_.y);
|
||||
agg::scanline_bin sl;
|
||||
|
|
|
@ -91,11 +91,11 @@ struct grid_markers_renderer_context : markers_renderer_context
|
|||
|
||||
virtual void render_marker(svg_path_ptr const& src,
|
||||
svg_path_adapter& path,
|
||||
svg_attribute_type const& attrs,
|
||||
svg::group const& svg_group,
|
||||
markers_dispatch_params const& params,
|
||||
agg::trans_affine const& marker_tr)
|
||||
{
|
||||
SvgRenderer svg_renderer_(path, attrs);
|
||||
SvgRenderer svg_renderer_(path, svg_group);
|
||||
agg::scanline_bin sl_;
|
||||
svg_renderer_.render_id(ras_, sl_, renb_, feature_.id(), marker_tr, params.opacity, src->bounding_box());
|
||||
place_feature();
|
||||
|
@ -153,6 +153,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
|
||||
template void grid_renderer<grid>::process(markers_symbolizer const&, mapnik::feature_impl&, proj_transform const&);
|
||||
|
||||
} // namespace mapnik
|
||||
|
||||
#endif
|
||||
#endif // GRID_RENDEDER
|
||||
|
|
|
@ -170,7 +170,7 @@ std::shared_ptr<mapnik::marker const> marker_cache::find(std::string const& uri,
|
|||
svg_path_ptr marker_path(std::make_shared<svg_storage_type>());
|
||||
vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
|
||||
svg_path_adapter svg_path(stl_storage);
|
||||
svg_converter_type svg(svg_path, marker_path->attributes());
|
||||
svg_converter_type svg(svg_path, marker_path->svg_group());
|
||||
svg_parser p(svg, strict);
|
||||
p.parse_from_string(known_svg_string);
|
||||
|
||||
|
@ -211,7 +211,7 @@ std::shared_ptr<mapnik::marker const> marker_cache::find(std::string const& uri,
|
|||
svg_path_ptr marker_path(std::make_shared<svg_storage_type>());
|
||||
vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
|
||||
svg_path_adapter svg_path(stl_storage);
|
||||
svg_converter_type svg(svg_path, marker_path->attributes());
|
||||
svg_converter_type svg(svg_path, marker_path->svg_group());
|
||||
svg_parser p(svg, strict);
|
||||
p.parse(uri);
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ void build_ellipse(symbolizer_base const& sym,
|
|||
{
|
||||
half_stroke_width = get<double>(sym, keys::stroke_width, feature, vars, 0.0) / 2.0;
|
||||
}
|
||||
svg::svg_converter_type styled_svg(svg_path, marker_ellipse.attributes());
|
||||
svg::svg_converter_type styled_svg(svg_path, marker_ellipse.svg_group());
|
||||
styled_svg.push_attr();
|
||||
styled_svg.begin_path();
|
||||
agg::ellipse c(0, 0, width / 2.0, height / 2.0);
|
||||
|
@ -78,8 +78,107 @@ void build_ellipse(symbolizer_base const& sym,
|
|||
marker_ellipse.set_bounding_box(lox, loy, hix, hiy);
|
||||
}
|
||||
|
||||
bool push_explicit_style(svg_attribute_type const& src,
|
||||
svg_attribute_type& dst,
|
||||
namespace detail {
|
||||
|
||||
struct push_explicit_style
|
||||
{
|
||||
push_explicit_style(svg::group& dst,
|
||||
boost::optional<color> const& fill_color,
|
||||
boost::optional<double> const& fill_opacity,
|
||||
boost::optional<color> const& stroke_color,
|
||||
boost::optional<double> const& stroke_width,
|
||||
boost::optional<double> const& stroke_opacity)
|
||||
: current_group_(&dst)
|
||||
, fill_color_(fill_color)
|
||||
, fill_opacity_(fill_opacity)
|
||||
, stroke_color_(stroke_color)
|
||||
, stroke_width_(stroke_width)
|
||||
, stroke_opacity_(stroke_opacity)
|
||||
{}
|
||||
|
||||
bool operator()(svg::group const& g) const
|
||||
{
|
||||
current_group_->elements.emplace_back(svg::group{g.opacity, {}, current_group_});
|
||||
current_group_ = ¤t_group_->elements.back().get<svg::group>();
|
||||
bool success = false;
|
||||
for (auto const& elem : g.elements)
|
||||
{
|
||||
if (mapbox::util::apply_visitor(push_explicit_style(*current_group_,
|
||||
fill_color_,
|
||||
fill_opacity_,
|
||||
stroke_color_,
|
||||
stroke_width_,
|
||||
stroke_opacity_),
|
||||
elem))
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
current_group_ = current_group_->parent;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool operator()(svg::path_attributes const& attr) const
|
||||
{
|
||||
svg::path_attributes new_attr{attr, attr.index};
|
||||
|
||||
if (!attr.visibility_flag)
|
||||
return false;
|
||||
|
||||
if (!attr.stroke_none)
|
||||
{
|
||||
if (stroke_width_)
|
||||
{
|
||||
new_attr.stroke_width = *stroke_width_;
|
||||
new_attr.stroke_flag = true;
|
||||
}
|
||||
if (stroke_color_)
|
||||
{
|
||||
color const& s_color = *stroke_color_;
|
||||
new_attr.stroke_color = agg::rgba(s_color.red() / 255.0,
|
||||
s_color.green() / 255.0,
|
||||
s_color.blue() / 255.0,
|
||||
s_color.alpha() / 255.0);
|
||||
new_attr.stroke_flag = true;
|
||||
}
|
||||
if (stroke_opacity_)
|
||||
{
|
||||
new_attr.stroke_opacity = *stroke_opacity_;
|
||||
new_attr.stroke_flag = true;
|
||||
}
|
||||
}
|
||||
if (!attr.fill_none)
|
||||
{
|
||||
if (fill_color_)
|
||||
{
|
||||
color const& f_color = *fill_color_;
|
||||
new_attr.fill_color = agg::rgba(f_color.red() / 255.0,
|
||||
f_color.green() / 255.0,
|
||||
f_color.blue() / 255.0,
|
||||
f_color.alpha() / 255.0);
|
||||
new_attr.fill_flag = true;
|
||||
}
|
||||
if (fill_opacity_)
|
||||
{
|
||||
new_attr.fill_opacity = *fill_opacity_;
|
||||
new_attr.fill_flag = true;
|
||||
}
|
||||
}
|
||||
current_group_->elements.emplace_back(new_attr);
|
||||
return true;
|
||||
}
|
||||
mutable svg::group* current_group_;
|
||||
boost::optional<color> const& fill_color_;
|
||||
boost::optional<double> const& fill_opacity_;
|
||||
boost::optional<color> const& stroke_color_;
|
||||
boost::optional<double> const& stroke_width_;
|
||||
boost::optional<double> const& stroke_opacity_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
bool push_explicit_style(svg::group const& src,
|
||||
svg::group& dst,
|
||||
symbolizer_base const& sym,
|
||||
feature_impl& feature,
|
||||
attributes const& vars)
|
||||
|
@ -89,61 +188,24 @@ bool push_explicit_style(svg_attribute_type const& src,
|
|||
auto stroke_color = get_optional<color>(sym, keys::stroke, feature, vars);
|
||||
auto stroke_width = get_optional<double>(sym, keys::stroke_width, feature, vars);
|
||||
auto stroke_opacity = get_optional<double>(sym, keys::stroke_opacity, feature, vars);
|
||||
bool success = false;
|
||||
dst.opacity = src.opacity;
|
||||
if (fill_color || fill_opacity || stroke_color || stroke_width || stroke_opacity)
|
||||
{
|
||||
bool success = false;
|
||||
for (unsigned i = 0; i < src.size(); ++i)
|
||||
for (auto const& elem : src.elements)
|
||||
{
|
||||
dst.push_back(src[i]);
|
||||
mapnik::svg::path_attributes& attr = dst.back();
|
||||
if (!attr.visibility_flag)
|
||||
continue;
|
||||
if (mapbox::util::apply_visitor(detail::push_explicit_style(dst,
|
||||
fill_color,
|
||||
fill_opacity,
|
||||
stroke_color,
|
||||
stroke_width,
|
||||
stroke_opacity),
|
||||
elem))
|
||||
success = true;
|
||||
|
||||
if (!attr.stroke_none)
|
||||
{
|
||||
if (stroke_width)
|
||||
{
|
||||
attr.stroke_width = *stroke_width;
|
||||
attr.stroke_flag = true;
|
||||
}
|
||||
if (stroke_color)
|
||||
{
|
||||
color const& s_color = *stroke_color;
|
||||
attr.stroke_color = agg::rgba(s_color.red() / 255.0,
|
||||
s_color.green() / 255.0,
|
||||
s_color.blue() / 255.0,
|
||||
s_color.alpha() / 255.0);
|
||||
attr.stroke_flag = true;
|
||||
}
|
||||
if (stroke_opacity)
|
||||
{
|
||||
attr.stroke_opacity = *stroke_opacity;
|
||||
attr.stroke_flag = true;
|
||||
}
|
||||
}
|
||||
if (!attr.fill_none)
|
||||
{
|
||||
if (fill_color)
|
||||
{
|
||||
color const& f_color = *fill_color;
|
||||
attr.fill_color = agg::rgba(f_color.red() / 255.0,
|
||||
f_color.green() / 255.0,
|
||||
f_color.blue() / 255.0,
|
||||
f_color.alpha() / 255.0);
|
||||
attr.fill_flag = true;
|
||||
}
|
||||
if (fill_opacity)
|
||||
{
|
||||
attr.fill_opacity = *fill_opacity;
|
||||
attr.fill_flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void setup_transform_scaling(agg::trans_affine& tr,
|
||||
double svg_width,
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
// proj
|
||||
#include <proj.h>
|
||||
#include <cmath> // HUGE_VAL
|
||||
#include <cstring> // strlen
|
||||
#endif
|
||||
|
||||
namespace mapnik {
|
||||
|
@ -196,12 +197,26 @@ projection::~projection()
|
|||
#endif
|
||||
}
|
||||
|
||||
std::string projection::expanded() const
|
||||
std::string projection::description() const
|
||||
{
|
||||
#ifdef MAPNIK_USE_PROJ
|
||||
if (proj_)
|
||||
{
|
||||
PJ_PROJ_INFO info = proj_pj_info(proj_);
|
||||
if (std::strlen(info.description) > 0)
|
||||
return mapnik::util::trim_copy(info.description);
|
||||
}
|
||||
#endif
|
||||
return std::string("Undefined");
|
||||
}
|
||||
|
||||
std::string projection::definition() const
|
||||
{
|
||||
#ifdef MAPNIK_USE_PROJ
|
||||
if (proj_)
|
||||
{
|
||||
PJ_PROJ_INFO info = proj_pj_info(proj_);
|
||||
if (std::strlen(info.definition) > 0)
|
||||
return mapnik::util::trim_copy(info.definition);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -55,14 +55,13 @@ struct render_marker_symbolizer_visitor
|
|||
, renderer_context_(renderer_context)
|
||||
{}
|
||||
|
||||
svg_attribute_type const& get_marker_attributes(svg_path_ptr const& stock_marker,
|
||||
svg_attribute_type& custom_attr) const
|
||||
svg::group const& get_marker_attributes(svg_path_ptr const& stock_marker, svg::group& custom_group_attrs) const
|
||||
{
|
||||
auto const& stock_attr = stock_marker->attributes();
|
||||
if (push_explicit_style(stock_attr, custom_attr, sym_, feature_, common_.vars_))
|
||||
return custom_attr;
|
||||
auto const& stock_group_attrs = stock_marker->svg_group();
|
||||
if (push_explicit_style(stock_group_attrs, custom_group_attrs, sym_, feature_, common_.vars_))
|
||||
return custom_group_attrs;
|
||||
else
|
||||
return stock_attr;
|
||||
return stock_group_attrs;
|
||||
}
|
||||
|
||||
template<typename Marker, typename Dispatch>
|
||||
|
@ -130,8 +129,9 @@ struct render_marker_symbolizer_visitor
|
|||
svg_path_ptr marker_ptr = stock_vector_marker;
|
||||
bool is_ellipse = false;
|
||||
|
||||
svg_attribute_type s_attributes;
|
||||
auto const& r_attributes = get_marker_attributes(stock_vector_marker, s_attributes);
|
||||
// svg_attribute_type s_attributes;
|
||||
svg::group svg_group_attrs;
|
||||
auto const& svg_group_attrs_updated = get_marker_attributes(stock_vector_marker, svg_group_attrs);
|
||||
|
||||
// special case for simple ellipse markers
|
||||
// to allow for full control over rx/ry dimensions
|
||||
|
@ -161,7 +161,7 @@ struct render_marker_symbolizer_visitor
|
|||
|
||||
vector_dispatch_type rasterizer_dispatch(marker_ptr,
|
||||
svg_path,
|
||||
r_attributes,
|
||||
svg_group_attrs_updated,
|
||||
image_tr,
|
||||
sym_,
|
||||
*common_.detector_,
|
||||
|
|
|
@ -47,11 +47,15 @@ void render_pattern<image_rgba8>(marker_svg const& marker,
|
|||
double opacity,
|
||||
image_rgba8& image)
|
||||
{
|
||||
using pixfmt = agg::pixfmt_rgba32_pre;
|
||||
using color_type = agg::rgba8;
|
||||
using order_type = agg::order_rgba;
|
||||
using blender_type = agg::comp_op_adaptor_rgba_pre<color_type, order_type>; // comp blender
|
||||
using buf_type = agg::rendering_buffer;
|
||||
using pixfmt = agg::pixfmt_custom_blend_rgba<blender_type, buf_type>;
|
||||
using renderer_base = agg::renderer_base<pixfmt>;
|
||||
using renderer_solid = agg::renderer_scanline_aa_solid<renderer_base>;
|
||||
agg::scanline_u8 sl;
|
||||
|
||||
agg::scanline_u8 sl;
|
||||
mapnik::box2d<double> const& bbox = marker.bounding_box() * tr;
|
||||
mapnik::coord<double, 2> c = bbox.center();
|
||||
agg::trans_affine mtx = agg::trans_affine_translation(-c.x, -c.y);
|
||||
|
@ -66,9 +70,8 @@ void render_pattern<image_rgba8>(marker_svg const& marker,
|
|||
svg_path_adapter svg_path(stl_storage);
|
||||
svg::renderer_agg<svg_path_adapter, svg_attribute_type, renderer_solid, pixfmt> svg_renderer(
|
||||
svg_path,
|
||||
marker.get_data()->attributes());
|
||||
marker.get_data()->svg_group());
|
||||
rasterizer ras;
|
||||
|
||||
svg_renderer.render(ras, sl, renb, mtx, opacity, bbox);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,11 +48,11 @@ struct thunk_markers_renderer_context : markers_renderer_context
|
|||
|
||||
virtual void render_marker(svg_path_ptr const& src,
|
||||
svg_path_adapter& path,
|
||||
svg_attribute_type const& attrs,
|
||||
svg::group const& group_attrs,
|
||||
markers_dispatch_params const& params,
|
||||
agg::trans_affine const& marker_tr)
|
||||
{
|
||||
vector_marker_render_thunk thunk(src, attrs, marker_tr, params.opacity, comp_op_, params.snap_to_pixels);
|
||||
vector_marker_render_thunk thunk(src, group_attrs, marker_tr, params.opacity, comp_op_, params.snap_to_pixels);
|
||||
thunks_.emplace_back(std::move(thunk));
|
||||
}
|
||||
|
||||
|
|
|
@ -539,6 +539,7 @@ void traverse_tree(svg_parser& parser, rapidxml::xml_node<char> const* node)
|
|||
if (parser.css_style_)
|
||||
process_css(parser, node);
|
||||
parse_attr(parser, node);
|
||||
parser.path_.begin_group();
|
||||
}
|
||||
break;
|
||||
case "use"_case:
|
||||
|
@ -547,7 +548,11 @@ void traverse_tree(svg_parser& parser, rapidxml::xml_node<char> const* node)
|
|||
if (parser.css_style_)
|
||||
process_css(parser, node);
|
||||
parse_attr(parser, node);
|
||||
if (parser.path_.cur_attr().opacity < 1.0)
|
||||
parser.path_.begin_group();
|
||||
parse_use(parser, node);
|
||||
if (parser.path_.cur_attr().opacity < 1.0)
|
||||
parser.path_.end_group();
|
||||
parser.path_.pop_attr();
|
||||
break;
|
||||
default:
|
||||
|
@ -558,7 +563,11 @@ void traverse_tree(svg_parser& parser, rapidxml::xml_node<char> const* node)
|
|||
parse_attr(parser, node);
|
||||
if (parser.path_.display())
|
||||
{
|
||||
if (parser.path_.cur_attr().opacity < 1.0)
|
||||
parser.path_.begin_group();
|
||||
parse_element(parser, node->name(), node);
|
||||
if (parser.path_.cur_attr().opacity < 1.0)
|
||||
parser.path_.end_group();
|
||||
}
|
||||
parser.path_.pop_attr();
|
||||
}
|
||||
|
@ -611,6 +620,7 @@ void end_element(svg_parser& parser, rapidxml::xml_node<char> const* node)
|
|||
auto name = name_to_int(node->name());
|
||||
if (!parser.is_defs_ && (name == "g"_case))
|
||||
{
|
||||
parser.path_.end_group();
|
||||
if (node->first_node() != nullptr)
|
||||
{
|
||||
parser.path_.pop_attr();
|
||||
|
@ -618,10 +628,10 @@ void end_element(svg_parser& parser, rapidxml::xml_node<char> const* node)
|
|||
}
|
||||
else if (name == "svg"_case)
|
||||
{
|
||||
if (node->first_node() != nullptr)
|
||||
{
|
||||
parser.path_.pop_attr();
|
||||
}
|
||||
// if (node->first_node() != nullptr)
|
||||
//{
|
||||
// parser.path_.pop_attr();
|
||||
//}
|
||||
}
|
||||
else if (name == "defs"_case)
|
||||
{
|
||||
|
@ -670,9 +680,10 @@ void parse_element(svg_parser& parser, char const* name, rapidxml::xml_node<char
|
|||
parse_ellipse(parser, node);
|
||||
break;
|
||||
case "svg"_case:
|
||||
parser.path_.push_attr();
|
||||
// parser.path_.push_attr();
|
||||
parse_dimensions(parser, node);
|
||||
parse_attr(parser, node);
|
||||
parser.path_.set_opacity(parser.path_.cur_attr().opacity);
|
||||
break;
|
||||
default:
|
||||
handle_unsupported(parser, unsupported_elements, name, "element");
|
||||
|
@ -864,6 +875,7 @@ void parse_attr(svg_parser& parser, char const* name, char const* value)
|
|||
|
||||
void parse_attr(svg_parser& parser, rapidxml::xml_node<char> const* node)
|
||||
{
|
||||
parser.path_.opacity(1.0); // default path opacity = 1.0
|
||||
for (rapidxml::xml_attribute<char> const* attr = node->first_attribute(); attr; attr = attr->next_attribute())
|
||||
{
|
||||
auto const* name = attr->name();
|
||||
|
@ -1521,8 +1533,8 @@ void parse_radial_gradient(svg_parser& parser, rapidxml::xml_node<char> const* n
|
|||
return;
|
||||
double cx = 0.5;
|
||||
double cy = 0.5;
|
||||
double fx = 0.0;
|
||||
double fy = 0.0;
|
||||
double fx = 0.5;
|
||||
double fy = 0.5;
|
||||
double r = 0.5;
|
||||
bool has_percent = false;
|
||||
|
||||
|
@ -1531,12 +1543,20 @@ void parse_radial_gradient(svg_parser& parser, rapidxml::xml_node<char> const* n
|
|||
{
|
||||
cx = parse_svg_value(parser, attr->value(), has_percent);
|
||||
}
|
||||
else if (gr.get_units() == USER_SPACE_ON_USE)
|
||||
{
|
||||
cx = 0.5 * (parser.vbox_ ? parser.vbox_->width : parser.path_.width()); // 50%
|
||||
}
|
||||
|
||||
attr = node->first_attribute("cy");
|
||||
if (attr != nullptr)
|
||||
{
|
||||
cy = parse_svg_value(parser, attr->value(), has_percent);
|
||||
}
|
||||
else if (gr.get_units() == USER_SPACE_ON_USE)
|
||||
{
|
||||
cy = 0.5 * (parser.vbox_ ? parser.vbox_->height : parser.path_.height()); // 50%
|
||||
}
|
||||
|
||||
attr = node->first_attribute("fx");
|
||||
if (attr != nullptr)
|
||||
|
@ -1544,25 +1564,26 @@ void parse_radial_gradient(svg_parser& parser, rapidxml::xml_node<char> const* n
|
|||
fx = parse_svg_value(parser, attr->value(), has_percent);
|
||||
}
|
||||
else
|
||||
{
|
||||
fx = cx;
|
||||
|
||||
}
|
||||
attr = node->first_attribute("fy");
|
||||
if (attr != nullptr)
|
||||
{
|
||||
fy = parse_svg_value(parser, attr->value(), has_percent);
|
||||
}
|
||||
else
|
||||
{
|
||||
fy = cy;
|
||||
|
||||
}
|
||||
attr = node->first_attribute("r");
|
||||
if (attr != nullptr)
|
||||
{
|
||||
r = parse_svg_value(parser, attr->value(), has_percent);
|
||||
}
|
||||
// this logic for detecting %'s will not support mixed coordinates.
|
||||
if (has_percent && gr.get_units() == USER_SPACE_ON_USE)
|
||||
else if (gr.get_units() == USER_SPACE_ON_USE)
|
||||
{
|
||||
gr.set_units(USER_SPACE_ON_USE_BOUNDING_BOX);
|
||||
r = 0.5 * parser.normalized_diagonal_; // 50%
|
||||
}
|
||||
|
||||
gr.set_gradient_type(RADIAL);
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
// mapnik
|
||||
#include <mapnik/text/glyph_positions.hpp>
|
||||
#include <mapnik/pixel_position.hpp>
|
||||
#include <mapnik/text/rotation.hpp>
|
||||
#include <mapnik/text/glyph_info.hpp>
|
||||
|
||||
// stl
|
||||
|
|
|
@ -87,11 +87,6 @@ pixel_position evaluate_displacement(double dx, double dy, directions_e dir)
|
|||
}
|
||||
}
|
||||
|
||||
pixel_position pixel_position::rotate(rotation const& rot) const
|
||||
{
|
||||
return pixel_position(x * rot.cos - y * rot.sin, x * rot.sin + y * rot.cos);
|
||||
}
|
||||
|
||||
text_layout::text_layout(face_manager_freetype& font_manager,
|
||||
feature_impl const& feature,
|
||||
attributes const& attrs,
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 90dc594c693055eae69aeb66f00685969fc3113c
|
||||
Subproject commit b5d6733df57557788d190a50eb6207418ae4c32a
|
|
@ -1 +1 @@
|
|||
Subproject commit ac363ee887d2a55039fd19390c186663d8f0f206
|
||||
Subproject commit 7dfd4568d6181da8be3543c8b7522b596a79b774
|
|
@ -30,12 +30,126 @@
|
|||
#include <mapnik/svg/svg_converter.hpp>
|
||||
#include <mapnik/svg/svg_path_adapter.hpp>
|
||||
#include <mapnik/svg/svg_path_attributes.hpp>
|
||||
#include <mapnik/util/fs.hpp>
|
||||
#include "util.hpp"
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
// boost
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/xml_parser.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
namespace // internal
|
||||
{
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, agg::rgba8 const& c)
|
||||
{
|
||||
os << mapnik::color{c.r, c.g, c.b, c.a};
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, mapnik::gradient const& gr)
|
||||
{
|
||||
double cx, cy, fx, fy, r;
|
||||
gr.get_control_points(fx, fy, cx, cy, r);
|
||||
|
||||
os << "<gradient cx=\"" << cx << "\" cy=\"" << cy << "\""
|
||||
<< " fx=\"" << fx << "\" fy=\"" << fy << "\" r=\"" << r << "\">\n";
|
||||
for (auto const& stop : gr.get_stop_array())
|
||||
{
|
||||
os << " <stop offset=\"" << std::get<0>(stop) << "\" color=\"" << std::get<1>(stop) << "\"/>\n";
|
||||
}
|
||||
|
||||
os << "</gradient>\n";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, agg::trans_affine const& tr)
|
||||
{
|
||||
os << "<transform>matrix(" << tr.sx << "," << tr.shy << "," << tr.shx << "," << tr.sy << "," << tr.tx << ","
|
||||
<< tr.ty << ")</transform>";
|
||||
return os;
|
||||
}
|
||||
|
||||
struct group_attribute_visitor
|
||||
{
|
||||
group_attribute_visitor(std::stringstream& ss, unsigned padding)
|
||||
: ss_(ss)
|
||||
, padding_(padding)
|
||||
{}
|
||||
|
||||
void operator()(mapnik::svg::group const& g) const
|
||||
{
|
||||
padding_ += 2;
|
||||
// ss_ << "padding=>" << padding_ << std::endl;
|
||||
std::string pad(padding_, ' ');
|
||||
ss_ << pad << "<g opacity=\"" << g.opacity << "\">" << std::endl;
|
||||
for (auto const& elem : g.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(group_attribute_visitor(ss_, padding_), elem);
|
||||
}
|
||||
ss_ << pad << "</g>" << std::endl;
|
||||
padding_ -= 2;
|
||||
}
|
||||
void operator()(mapnik::svg::path_attributes const& attr) const
|
||||
{
|
||||
padding_ += 2;
|
||||
std::string pad(padding_, ' ');
|
||||
ss_ << pad << "<attribute index=\"" << attr.index << "\">" << std::endl;
|
||||
ss_ << pad << attr.transform << std::endl;
|
||||
if (!attr.fill_gradient.get_stop_array().empty())
|
||||
ss_ << pad << attr.fill_gradient;
|
||||
if (!attr.stroke_gradient.get_stop_array().empty())
|
||||
ss_ << pad << attr.stroke_gradient;
|
||||
|
||||
ss_ << pad << " <opacity>" << attr.opacity << "</opacity>" << std::endl;
|
||||
ss_ << pad << " <fill>" << attr.fill_color << "</fill>" << std::endl;
|
||||
ss_ << pad << " <fill-opacity>" << attr.fill_opacity << "</fill-opacity>" << std::endl;
|
||||
ss_ << pad << " <stroke>" << attr.stroke_color << "</stroke>" << std::endl;
|
||||
ss_ << pad << " <stroke-width>" << attr.stroke_width << "</stroke-width>" << std::endl;
|
||||
ss_ << pad << " <stroke-opacity>" << attr.stroke_opacity << "</stroke-opacity>" << std::endl;
|
||||
ss_ << pad << "</attribute>" << std::endl;
|
||||
padding_ -= 2;
|
||||
}
|
||||
std::stringstream& ss_;
|
||||
mutable unsigned padding_;
|
||||
};
|
||||
|
||||
bool check_equal_attributes(std::string const& svg_file, mapnik::svg::group const& g)
|
||||
{
|
||||
unsigned padding = 0;
|
||||
std::stringstream ss;
|
||||
ss << "<svg opacity=\"" << g.opacity << "\">" << std::endl;
|
||||
for (auto const& elem : g.elements)
|
||||
{
|
||||
mapbox::util::apply_visitor(group_attribute_visitor(ss, padding), elem);
|
||||
}
|
||||
ss << "</svg>" << std::endl;
|
||||
|
||||
std::string well_known_xml = svg_file + ".xml";
|
||||
if (!mapnik::util::exists(well_known_xml))
|
||||
{
|
||||
std::cerr << "Well-known-xml-filename:" << well_known_xml << std::endl;
|
||||
std::cerr << ss.str() << std::endl;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::property_tree::ptree t0, t1;
|
||||
boost::property_tree::read_xml(well_known_xml, t0, boost::property_tree::xml_parser::trim_whitespace);
|
||||
boost::property_tree::read_xml(ss, t1, boost::property_tree::xml_parser::trim_whitespace);
|
||||
|
||||
if (t0 != t1)
|
||||
{
|
||||
std::cerr << ss.str() << std::endl;
|
||||
}
|
||||
return (t0 == t1);
|
||||
}
|
||||
}
|
||||
|
||||
struct test_parser
|
||||
{
|
||||
mapnik::svg_storage_type path;
|
||||
|
@ -47,7 +161,7 @@ struct test_parser
|
|||
explicit test_parser(bool strict = false)
|
||||
: stl_storage(path.source())
|
||||
, svg_path(stl_storage)
|
||||
, svg(svg_path, path.attributes())
|
||||
, svg(svg_path, path.svg_group())
|
||||
, p(svg, strict)
|
||||
{}
|
||||
|
||||
|
@ -261,10 +375,10 @@ TEST_CASE("SVG parser")
|
|||
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(storage->source());
|
||||
mapnik::svg::svg_path_adapter path(stl_storage);
|
||||
|
||||
auto const& attrs = storage->attributes();
|
||||
auto const& group_attrs = storage->svg_group();
|
||||
agg::line_cap_e expected_cap(agg::square_cap);
|
||||
REQUIRE(attrs.size() == 1);
|
||||
REQUIRE(attrs[0].line_cap == expected_cap);
|
||||
|
||||
REQUIRE(check_equal_attributes(svg_name, group_attrs));
|
||||
|
||||
double x, y;
|
||||
unsigned cmd;
|
||||
|
@ -427,23 +541,22 @@ TEST_CASE("SVG parser")
|
|||
REQUIRE(storage);
|
||||
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(storage->source());
|
||||
|
||||
auto const& attrs = storage->attributes();
|
||||
auto const& group_attrs = storage->svg_group();
|
||||
agg::line_join_e expected_join(agg::bevel_join);
|
||||
REQUIRE(attrs.size() == 1);
|
||||
REQUIRE(attrs[0].line_join == expected_join);
|
||||
REQUIRE(check_equal_attributes(svg_name, group_attrs));
|
||||
}
|
||||
|
||||
SECTION("SVG <line>")
|
||||
{
|
||||
//
|
||||
std::string svg_name("./test/data/svg/line.svg");
|
||||
std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(svg_name, false);
|
||||
REQUIRE(marker);
|
||||
REQUIRE(marker->is<mapnik::marker_svg>());
|
||||
mapnik::marker_svg const& svg = mapnik::util::get<mapnik::marker_svg>(*marker);
|
||||
auto bbox = svg.bounding_box();
|
||||
// REQUIRE(bbox == mapnik::box2d<double>(0.3543307086614174,0.3543307086614174,
|
||||
// 424.8425196850394059,141.3779527559055396));
|
||||
REQUIRE(
|
||||
bbox ==
|
||||
mapnik::box2d<double>(0.3779527559055118, 0.3779527559055118, 453.1653543307086807, 150.8031496062992005));
|
||||
auto storage = svg.get_data();
|
||||
REQUIRE(storage);
|
||||
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(storage->source());
|
||||
|
@ -471,14 +584,15 @@ TEST_CASE("SVG parser")
|
|||
|
||||
SECTION("SVG <polyline>")
|
||||
{
|
||||
//
|
||||
std::string svg_name("./test/data/svg/polyline.svg");
|
||||
std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(svg_name, false);
|
||||
REQUIRE(marker);
|
||||
REQUIRE(marker->is<mapnik::marker_svg>());
|
||||
mapnik::marker_svg const& svg = mapnik::util::get<mapnik::marker_svg>(*marker);
|
||||
auto bbox = svg.bounding_box();
|
||||
// REQUIRE(bbox == mapnik::box2d<double>(1.0,1.0,1199.0,399.0));
|
||||
REQUIRE(
|
||||
bbox ==
|
||||
mapnik::box2d<double>(0.3779527559055118, 0.3779527559055118, 453.1653543307086807, 150.8031496062992005));
|
||||
auto storage = svg.get_data();
|
||||
REQUIRE(storage);
|
||||
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(storage->source());
|
||||
|
@ -510,14 +624,15 @@ TEST_CASE("SVG parser")
|
|||
|
||||
SECTION("SVG <polygon>")
|
||||
{
|
||||
//
|
||||
std::string svg_name("./test/data/svg/polygon.svg");
|
||||
std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(svg_name, false);
|
||||
REQUIRE(marker);
|
||||
REQUIRE(marker->is<mapnik::marker_svg>());
|
||||
mapnik::marker_svg const& svg = mapnik::util::get<mapnik::marker_svg>(*marker);
|
||||
auto bbox = svg.bounding_box();
|
||||
// REQUIRE(bbox == mapnik::box2d<double>(1.0,1.0,1199.0,399.0));
|
||||
REQUIRE(
|
||||
bbox ==
|
||||
mapnik::box2d<double>(0.3779527559055118, 0.3779527559055118, 453.1653543307086807, 150.8031496062992005));
|
||||
auto storage = svg.get_data();
|
||||
REQUIRE(storage);
|
||||
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(storage->source());
|
||||
|
@ -548,14 +663,16 @@ TEST_CASE("SVG parser")
|
|||
|
||||
SECTION("SVG <gradient>")
|
||||
{
|
||||
//
|
||||
std::string svg_name("./test/data/svg/gradient.svg");
|
||||
std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(svg_name, false);
|
||||
REQUIRE(marker);
|
||||
REQUIRE(marker->is<mapnik::marker_svg>());
|
||||
mapnik::marker_svg const& svg = mapnik::util::get<mapnik::marker_svg>(*marker);
|
||||
auto bbox = svg.bounding_box();
|
||||
// REQUIRE(bbox == mapnik::box2d<double>(1.0,1.0,799.0,599.0));
|
||||
|
||||
REQUIRE(
|
||||
bbox ==
|
||||
mapnik::box2d<double>(75.7795275590551114, 0.1889763779527559, 226.5826771653543119, 113.1968503937007853));
|
||||
auto storage = svg.get_data();
|
||||
REQUIRE(storage);
|
||||
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(storage->source());
|
||||
|
@ -651,15 +768,17 @@ TEST_CASE("SVG parser")
|
|||
REQUIRE(marker->is<mapnik::marker_svg>());
|
||||
mapnik::marker_svg const& svg = mapnik::util::get<mapnik::marker_svg>(*marker);
|
||||
auto bbox = svg.bounding_box();
|
||||
// REQUIRE(bbox == mapnik::box2d<double>(1.0,1.0,699.0,199.0));
|
||||
|
||||
REQUIRE(
|
||||
bbox ==
|
||||
mapnik::box2d<double>(0.3779527559055118, 0.3779527559055118, 264.1889763779527698, 75.2125984251968447));
|
||||
auto storage = svg.get_data();
|
||||
REQUIRE(storage);
|
||||
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(storage->source());
|
||||
|
||||
auto const& attrs = storage->attributes();
|
||||
REQUIRE(attrs.size() == 3);
|
||||
REQUIRE(attrs[1].fill_gradient == attrs[2].fill_gradient);
|
||||
auto const& group_attrs = storage->svg_group();
|
||||
|
||||
REQUIRE(check_equal_attributes(svg_name, group_attrs));
|
||||
mapnik::svg::svg_path_adapter path(stl_storage);
|
||||
double x, y;
|
||||
unsigned cmd;
|
||||
|
@ -694,24 +813,20 @@ TEST_CASE("SVG parser")
|
|||
|
||||
SECTION("SVG <gradient> with transformations")
|
||||
{
|
||||
//
|
||||
std::string svg_name("./test/data/svg/gradient-transform.svg");
|
||||
std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(svg_name, false);
|
||||
REQUIRE(marker);
|
||||
REQUIRE(marker->is<mapnik::marker_svg>());
|
||||
mapnik::marker_svg const& svg = mapnik::util::get<mapnik::marker_svg>(*marker);
|
||||
auto bbox = svg.bounding_box();
|
||||
// REQUIRE(bbox == mapnik::box2d<double>(1.0,1.0,799.0,599.0));
|
||||
REQUIRE(
|
||||
bbox ==
|
||||
mapnik::box2d<double>(75.7795275590551114, 0.1889763779527559, 226.5826771653543119, 113.1968503937007853));
|
||||
auto storage = svg.get_data();
|
||||
REQUIRE(storage);
|
||||
|
||||
auto const& attrs = storage->attributes();
|
||||
REQUIRE(attrs.size() == 3);
|
||||
REQUIRE(attrs[1].fill_gradient == attrs[2].fill_gradient);
|
||||
REQUIRE(attrs[1].fill_gradient.get_gradient_type() == mapnik::RADIAL);
|
||||
agg::trans_affine transform;
|
||||
transform *= agg::trans_affine_translation(240, 155);
|
||||
REQUIRE(attrs[1].fill_gradient.get_transform() == transform);
|
||||
auto const& group_attrs = storage->svg_group();
|
||||
REQUIRE(check_equal_attributes(svg_name, group_attrs));
|
||||
}
|
||||
|
||||
SECTION("SVG <gradient> with xlink:href")
|
||||
|
@ -722,15 +837,12 @@ TEST_CASE("SVG parser")
|
|||
REQUIRE(marker->is<mapnik::marker_svg>());
|
||||
mapnik::marker_svg const& svg = mapnik::util::get<mapnik::marker_svg>(*marker);
|
||||
auto bbox = svg.bounding_box();
|
||||
// REQUIRE(bbox == mapnik::box2d<double>(20,20,460,230));
|
||||
REQUIRE(bbox == mapnik::box2d<double>(20, 20, 460, 230));
|
||||
auto storage = svg.get_data();
|
||||
REQUIRE(storage);
|
||||
|
||||
auto const& attrs = storage->attributes();
|
||||
REQUIRE(attrs.size() == 2);
|
||||
REQUIRE(attrs[0].fill_gradient.get_gradient_type() == mapnik::LINEAR);
|
||||
REQUIRE(attrs[1].fill_gradient.get_gradient_type() == mapnik::LINEAR);
|
||||
REQUIRE(attrs[1].fill_gradient.has_stop());
|
||||
auto const& group_attrs = storage->svg_group();
|
||||
REQUIRE(check_equal_attributes(svg_name, group_attrs));
|
||||
}
|
||||
|
||||
SECTION("SVG <gradient> with radial percents")
|
||||
|
@ -741,21 +853,10 @@ TEST_CASE("SVG parser")
|
|||
REQUIRE(marker->is<mapnik::marker_svg>());
|
||||
mapnik::marker_svg const& svg = mapnik::util::get<mapnik::marker_svg>(*marker);
|
||||
auto bbox = svg.bounding_box();
|
||||
// REQUIRE(bbox == mapnik::box2d<double>(0,0,200,200));
|
||||
REQUIRE(bbox == mapnik::box2d<double>(0, 0, 200, 200));
|
||||
auto storage = svg.get_data();
|
||||
REQUIRE(storage);
|
||||
|
||||
double x1, x2, y1, y2, r;
|
||||
auto const& attrs = storage->attributes();
|
||||
REQUIRE(attrs.size() == 1);
|
||||
REQUIRE(attrs[0].fill_gradient.get_gradient_type() == mapnik::RADIAL);
|
||||
REQUIRE(attrs[0].fill_gradient.has_stop());
|
||||
attrs[0].fill_gradient.get_control_points(x1, y1, x2, y2, r);
|
||||
REQUIRE(x1 == 0);
|
||||
REQUIRE(y1 == 0.25);
|
||||
REQUIRE(x2 == 0.10);
|
||||
REQUIRE(y2 == 0.10);
|
||||
REQUIRE(r == 0.75);
|
||||
REQUIRE(check_equal_attributes(svg_name, storage->svg_group()));
|
||||
}
|
||||
|
||||
SECTION("SVG <clipPath>")
|
||||
|
|
|
@ -38,7 +38,7 @@ void test_path_parser(std::string const& str, Expected const& expected)
|
|||
mapnik::svg_path_ptr marker_path(std::make_shared<mapnik::svg_storage_type>());
|
||||
vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
|
||||
svg_path_adapter svg_path(stl_storage);
|
||||
svg_converter_type svg(svg_path, marker_path->attributes());
|
||||
svg_converter_type svg(svg_path, marker_path->svg_group());
|
||||
|
||||
CHECK(mapnik::svg::parse_path(str.c_str(), svg));
|
||||
double x, y;
|
||||
|
|
|
@ -48,12 +48,17 @@ namespace {
|
|||
|
||||
mapnik::image_rgba8 render_svg(std::string const& filename, double scale_factor)
|
||||
{
|
||||
using pixfmt = agg::pixfmt_rgba32_pre;
|
||||
using color_type = agg::rgba8;
|
||||
using order_type = agg::order_rgba;
|
||||
using blender_type = agg::comp_op_adaptor_rgba_pre<color_type, order_type>; // comp blender
|
||||
using buf_type = agg::rendering_buffer;
|
||||
using pixfmt = agg::pixfmt_custom_blend_rgba<blender_type, buf_type>;
|
||||
using renderer_base = agg::renderer_base<pixfmt>;
|
||||
using renderer_solid = agg::renderer_scanline_aa_solid<renderer_base>;
|
||||
|
||||
agg::rasterizer_scanline_aa<> ras_ptr;
|
||||
agg::scanline_u8 sl;
|
||||
|
||||
std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(filename, false);
|
||||
mapnik::marker_svg const& svg = mapnik::util::get<mapnik::marker_svg>(*marker);
|
||||
double svg_width, svg_height;
|
||||
|
@ -72,9 +77,9 @@ mapnik::image_rgba8 render_svg(std::string const& filename, double scale_factor)
|
|||
|
||||
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(svg.get_data()->source());
|
||||
mapnik::svg::svg_path_adapter svg_path(stl_storage);
|
||||
mapnik::svg::
|
||||
renderer_agg<mapnik::svg_path_adapter, mapnik::svg_attribute_type, renderer_solid, agg::pixfmt_rgba32_pre>
|
||||
renderer(svg_path, svg.get_data()->attributes());
|
||||
mapnik::svg::renderer_agg<mapnik::svg_path_adapter, mapnik::svg_attribute_type, renderer_solid, pixfmt> renderer(
|
||||
svg_path,
|
||||
svg.get_data()->svg_group());
|
||||
double opacity = 1.0;
|
||||
renderer.render(ras_ptr, sl, renb, mtx, opacity, {0, 0, svg_width, svg_height});
|
||||
return im;
|
||||
|
@ -101,8 +106,8 @@ TEST_CASE("SVG renderer")
|
|||
double scale_factor = 1.0;
|
||||
std::string octocat_inline("./test/data/svg/octocat.svg");
|
||||
std::string octocat_css("./test/data/svg/octocat-css.svg");
|
||||
auto image1 = render_svg(octocat_inline, 1.0);
|
||||
auto image2 = render_svg(octocat_css, 1.0);
|
||||
auto image1 = render_svg(octocat_inline, scale_factor);
|
||||
auto image2 = render_svg(octocat_css, scale_factor);
|
||||
REQUIRE(equal(image1, image2));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,16 +8,21 @@
|
|||
#include <mapnik/unicode.hpp>
|
||||
#include <mapnik/datasource_cache.hpp>
|
||||
#include <mapnik/font_engine_freetype.hpp>
|
||||
|
||||
#include <mapnik/proj_transform.hpp>
|
||||
#include <mapnik/filesystem.hpp>
|
||||
#include <mapnik/warning.hpp>
|
||||
MAPNIK_DISABLE_WARNING_PUSH
|
||||
#include <mapnik/warning_ignore.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/spirit/home/x3.hpp>
|
||||
#include <boost/fusion/adapted/struct.hpp>
|
||||
MAPNIK_DISABLE_WARNING_POP
|
||||
|
||||
#include <string>
|
||||
|
||||
BOOST_FUSION_ADAPT_STRUCT(mapnik::box2d<double>, (double, minx_)(double, miny_)(double, maxx_)(double, maxy_))
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
namespace po = boost::program_options;
|
||||
|
@ -35,7 +40,6 @@ int main(int argc, char** argv)
|
|||
logger.set_severity(mapnik::logger::error);
|
||||
int map_width = 600;
|
||||
int map_height = 400;
|
||||
|
||||
try
|
||||
{
|
||||
po::options_description desc("mapnik-render utility");
|
||||
|
@ -51,7 +55,10 @@ int main(int argc, char** argv)
|
|||
("map-width",po::value<int>(),"map width in pixels")
|
||||
("map-height",po::value<int>(),"map height in pixels")
|
||||
("variables","make map parameters available as render-time variables")
|
||||
;
|
||||
("bbox", po::value<std::string>(), "bounding box e.g <minx,miny,maxx,maxy> in Map's SRS")
|
||||
("geographic,g","bounding box is in WGS 84 lon/lat")
|
||||
("plugins-dir", po::value<std::string>(), "directory containing input plug-ins (default: ./plugins/input)")
|
||||
("fonts-dir", po::value<std::string>(), "directory containing fonts (default: relative to <plugins-dir> or ./fonts if no <plugins-dir> specified)");
|
||||
// clang-format on
|
||||
po::positional_options_description p;
|
||||
p.add("xml", 1);
|
||||
|
@ -65,7 +72,6 @@ int main(int argc, char** argv)
|
|||
std::clog << "version " << MAPNIK_VERSION_STRING << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (vm.count("help"))
|
||||
{
|
||||
std::clog << desc << std::endl;
|
||||
|
@ -88,7 +94,8 @@ int main(int argc, char** argv)
|
|||
}
|
||||
else
|
||||
{
|
||||
std::clog << "please provide an xml map as first argument!" << std::endl;
|
||||
std::clog << "mapnik-render: no XML map specified" << std::endl;
|
||||
std::clog << "Try \"mapnik-render --help\" for more information" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -122,11 +129,94 @@ int main(int argc, char** argv)
|
|||
map_height = vm["map-height"].as<int>();
|
||||
}
|
||||
|
||||
mapnik::datasource_cache::instance().register_datasources("./plugins/input/");
|
||||
if (vm.count("plugins-dir"))
|
||||
{
|
||||
mapnik::datasource_cache::instance().register_datasources(vm["plugins-dir"].as<std::string>());
|
||||
if (vm.count("fonts-dir"))
|
||||
{
|
||||
mapnik::freetype_engine::register_fonts(vm["fonts-dir"].as<std::string>(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// relative to plugins-dir
|
||||
try
|
||||
{
|
||||
mapnik::fs::path p(vm["plugins-dir"].as<std::string>());
|
||||
p = p.parent_path() / "fonts";
|
||||
mapnik::freetype_engine::register_fonts(p.string(), true);
|
||||
}
|
||||
catch (...)
|
||||
{}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mapnik::datasource_cache::instance().register_datasources("./plugins/input");
|
||||
mapnik::freetype_engine::register_fonts("./fonts", true);
|
||||
}
|
||||
if (verbose)
|
||||
{
|
||||
auto plugin_names = mapnik::datasource_cache::instance().plugin_names();
|
||||
if (plugin_names.empty())
|
||||
{
|
||||
std::cerr << "*WARNING*: no datasource plug-ings registered" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Registered datasource plug-ins:";
|
||||
for (auto const& name : plugin_names)
|
||||
{
|
||||
std::cerr << name << " ";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
mapnik::Map map(map_width, map_height);
|
||||
mapnik::load_map(map, xml_file, true);
|
||||
|
||||
if (vm.count("bbox"))
|
||||
{
|
||||
namespace x3 = boost::spirit::x3;
|
||||
|
||||
mapnik::box2d<double> bbox;
|
||||
std::string str = vm["bbox"].as<std::string>();
|
||||
|
||||
auto start = str.begin();
|
||||
auto end = str.end();
|
||||
if (!x3::phrase_parse(start,
|
||||
end,
|
||||
x3::double_ >> -x3::lit(',') >> x3::double_ >> -x3::lit(',') >> x3::double_ >>
|
||||
-x3::lit(',') >> x3::double_,
|
||||
x3::space,
|
||||
bbox))
|
||||
{
|
||||
std::cerr << "Failed to parse BBOX: " << str << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if (!bbox.valid())
|
||||
{
|
||||
std::cerr << "Invalid BBOX: " << str << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if (vm.count("geographic"))
|
||||
{
|
||||
mapnik::projection source("epsg:4326");
|
||||
mapnik::projection destination(map.srs());
|
||||
mapnik::proj_transform tr(source, destination);
|
||||
if (!tr.forward(bbox))
|
||||
{
|
||||
std::cerr << "Failed to project input BBOX into " << map.srs() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
std::cerr << "zoom to:" << bbox << std::endl;
|
||||
map.zoom_to_box(bbox);
|
||||
}
|
||||
else
|
||||
{
|
||||
map.zoom_all();
|
||||
}
|
||||
mapnik::image_rgba8 im(map.width(), map.height());
|
||||
mapnik::request req(map.width(), map.height(), map.get_current_extent());
|
||||
req.set_buffer_size(map.buffer_size());
|
||||
|
|
|
@ -56,22 +56,32 @@ MAPNIK_DISABLE_WARNING_POP
|
|||
|
||||
struct main_marker_visitor
|
||||
{
|
||||
main_marker_visitor(std::string const& svg_name, double scale_factor, bool verbose, bool auto_open)
|
||||
main_marker_visitor(std::string const& svg_name, double scale_factor, double opacity, bool verbose, bool auto_open)
|
||||
: svg_name_(svg_name)
|
||||
, scale_factor_(scale_factor)
|
||||
, opacity_(opacity)
|
||||
, verbose_(verbose)
|
||||
, auto_open_(auto_open)
|
||||
{}
|
||||
|
||||
int operator()(mapnik::marker_svg const& marker) const
|
||||
{
|
||||
#if 1
|
||||
using color_type = agg::rgba8;
|
||||
using order_type = agg::order_rgba;
|
||||
using blender_type = agg::comp_op_adaptor_rgba_pre<color_type, order_type>; // comp blender
|
||||
using buf_type = agg::rendering_buffer;
|
||||
using pixfmt = agg::pixfmt_custom_blend_rgba<blender_type, buf_type>;
|
||||
using renderer_base = agg::renderer_base<pixfmt>;
|
||||
using renderer_solid = agg::renderer_scanline_aa_solid<renderer_base>;
|
||||
#else
|
||||
using pixfmt = agg::pixfmt_rgba32_pre;
|
||||
using renderer_base = agg::renderer_base<pixfmt>;
|
||||
using renderer_solid = agg::renderer_scanline_aa_solid<renderer_base>;
|
||||
#endif
|
||||
agg::rasterizer_scanline_aa<> ras_ptr;
|
||||
agg::scanline_u8 sl;
|
||||
|
||||
double opacity = 1;
|
||||
double w, h;
|
||||
std::tie(w, h) = marker.dimensions();
|
||||
if (w == 0 || h == 0)
|
||||
|
@ -110,11 +120,10 @@ struct main_marker_visitor
|
|||
|
||||
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::
|
||||
renderer_agg<mapnik::svg_path_adapter, mapnik::svg_attribute_type, renderer_solid, agg::pixfmt_rgba32_pre>
|
||||
svg_renderer_this(svg_path, marker.get_data()->attributes());
|
||||
mapnik::svg::renderer_agg<mapnik::svg_path_adapter, mapnik::svg_attribute_type, renderer_solid, pixfmt>
|
||||
svg_renderer_this(svg_path, marker.get_data()->svg_group());
|
||||
|
||||
svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox);
|
||||
svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity_, bbox);
|
||||
|
||||
std::string png_name(svg_name_);
|
||||
boost::algorithm::ireplace_last(png_name, ".svg", ".png");
|
||||
|
@ -147,11 +156,21 @@ struct main_marker_visitor
|
|||
|
||||
private:
|
||||
std::string svg_name_;
|
||||
double scale_factor_ = 1.0;
|
||||
double scale_factor_;
|
||||
double opacity_;
|
||||
bool verbose_;
|
||||
bool auto_open_;
|
||||
};
|
||||
|
||||
void check_opacity_range(double opacity)
|
||||
{
|
||||
using namespace boost::program_options;
|
||||
if (opacity < 0.0 || opacity > 1.0)
|
||||
{
|
||||
throw invalid_option_value(std::to_string(opacity));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
namespace po = boost::program_options;
|
||||
|
@ -163,7 +182,8 @@ int main(int argc, char** argv)
|
|||
std::vector<std::string> svg_files;
|
||||
mapnik::setup();
|
||||
mapnik::logger::instance().set_severity(mapnik::logger::error);
|
||||
double scale_factor = 1.0;
|
||||
double scale_factor;
|
||||
double opacity;
|
||||
std::string usage = "Usage: svg2png [options] <svg-file(s)>";
|
||||
try
|
||||
{
|
||||
|
@ -175,7 +195,8 @@ int main(int argc, char** argv)
|
|||
("verbose,v","verbose output")
|
||||
("open,o","automatically open the file after rendering (os x only)")
|
||||
("strict,s","enables strict SVG parsing")
|
||||
("scale-factor", po::value<double>(), "provide scaling factor (default: 1.0)")
|
||||
("scale-factor", po::value<double>()->default_value(1.0), "provide scaling factor (default: 1.0)")
|
||||
("opacity", po::value<double>()->default_value(1.0)->notifier(&check_opacity_range), "top level opacity (default: 1.0)")
|
||||
("svg",po::value<std::vector<std::string> >(),"svg file to read")
|
||||
;
|
||||
// clang-format on
|
||||
|
@ -216,6 +237,10 @@ int main(int argc, char** argv)
|
|||
{
|
||||
scale_factor = vm["scale-factor"].as<double>();
|
||||
}
|
||||
if (vm.count("opacity"))
|
||||
{
|
||||
opacity = vm["opacity"].as<double>();
|
||||
}
|
||||
if (vm.count("svg"))
|
||||
{
|
||||
svg_files = vm["svg"].as<std::vector<std::string>>();
|
||||
|
@ -241,7 +266,7 @@ int main(int argc, char** argv)
|
|||
}
|
||||
std::shared_ptr<mapnik::marker const> marker =
|
||||
mapnik::marker_cache::instance().find(svg_name, false, strict);
|
||||
main_marker_visitor visitor(svg_name, scale_factor, verbose, auto_open);
|
||||
main_marker_visitor visitor(svg_name, scale_factor, opacity, verbose, auto_open);
|
||||
status = mapnik::util::apply_visitor(visitor, *marker);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue