new feature: transform expressions are now dynamic

(cherry picked from commit 173c402b5c142310087246b0ea54dbec54edcac8)

Conflicts:

	include/mapnik/vertex_converters.hpp
	src/agg/process_markers_symbolizer.cpp
	src/agg/process_point_symbolizer.cpp
	src/agg/process_polygon_pattern_symbolizer.cpp
	src/load_map.cpp
This commit is contained in:
Mickey Rose 2012-05-27 23:50:09 +02:00
parent dad0bdacfc
commit bd9609c370
30 changed files with 1071 additions and 163 deletions

View file

@ -23,10 +23,14 @@
#define MAPNIK_PYTHON_BINDING_SVG_INCLUDED
// mapnik
#include <mapnik/parse_transform.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/svg/svg_path_parser.hpp>
#include <mapnik/value_error.hpp>
// boost
#include <boost/make_shared.hpp>
// agg
#include "agg_trans_affine.h"
@ -51,9 +55,9 @@ void set_svg_transform(T& symbolizer, std::string const& transform_wkt)
<< "', expected SVG transform attribute";
throw mapnik::value_error(ss.str());
}
mapnik::transform_type matrix;
tr.store_to(&matrix[0]);
symbolizer.set_image_transform(matrix);
transform_list_ptr trans = boost::make_shared<transform_list>();
trans->push_back(matrix_node(tr));
symbolizer.set_image_transform(trans);
}
} // end of namespace mapnik

View file

@ -115,6 +115,13 @@ public:
void painted(bool painted);
protected:
template <typename R>
void debug_draw_box(R& buf, box2d<double> const& extent,
double x, double y, double angle = 0.0);
void debug_draw_box(box2d<double> const& extent,
double x, double y, double angle = 0.0);
private:
buffer_type & pixmap_;
boost::shared_ptr<buffer_type> internal_buffer_;

View file

@ -25,6 +25,7 @@
// mapnik
#include <mapnik/rule.hpp>
#include <mapnik/parse_transform.hpp>
// boost
#include <boost/utility.hpp>
#include <boost/variant.hpp>
@ -35,9 +36,10 @@
namespace mapnik {
template <typename Container>
struct expression_attributes : boost::static_visitor<void>
{
explicit expression_attributes(std::set<std::string> & names)
explicit expression_attributes(Container& names)
: names_(names) {}
void operator() (value_type const& x) const
@ -53,35 +55,35 @@ struct expression_attributes : boost::static_visitor<void>
template <typename Tag>
void operator() (binary_node<Tag> const& x) const
{
boost::apply_visitor(expression_attributes(names_),x.left);
boost::apply_visitor(expression_attributes(names_),x.right);
boost::apply_visitor(*this, x.left);
boost::apply_visitor(*this, x.right);
}
template <typename Tag>
void operator() (unary_node<Tag> const& x) const
{
boost::apply_visitor(expression_attributes(names_),x.expr);
boost::apply_visitor(*this, x.expr);
}
void operator() (regex_match_node const& x) const
{
boost::apply_visitor(expression_attributes(names_),x.expr);
boost::apply_visitor(*this, x.expr);
}
void operator() (regex_replace_node const& x) const
{
boost::apply_visitor(expression_attributes(names_),x.expr);
boost::apply_visitor(*this, x.expr);
}
private:
std::set<std::string>& names_;
Container& names_;
};
struct symbolizer_attributes : public boost::static_visitor<>
{
symbolizer_attributes(std::set<std::string>& names)
: names_(names) {}
: names_(names), f_attr(names) {}
template <typename T>
void operator () (T const&) const {}
@ -91,12 +93,12 @@ struct symbolizer_attributes : public boost::static_visitor<>
expression_set::const_iterator it;
expression_set expressions;
sym.get_placement_options()->add_expressions(expressions);
expression_attributes f_attr(names_);
for (it=expressions.begin(); it != expressions.end(); it++)
{
if (*it) boost::apply_visitor(f_attr, **it);
}
collect_metawriter(sym);
collect_transform(sym.get_transform());
}
void operator () (point_symbolizer const& sym)
@ -107,12 +109,14 @@ struct symbolizer_attributes : public boost::static_visitor<>
path_processor_type::collect_attributes(*filename_expr,names_);
}
collect_metawriter(sym);
collect_transform(sym.get_image_transform());
collect_transform(sym.get_transform());
}
void operator () (line_symbolizer const& sym)
{
collect_metawriter(sym);
collect_transform(sym.get_transform());
}
void operator () (line_pattern_symbolizer const& sym)
@ -123,11 +127,14 @@ struct symbolizer_attributes : public boost::static_visitor<>
path_processor_type::collect_attributes(*filename_expr,names_);
}
collect_metawriter(sym);
collect_transform(sym.get_image_transform());
collect_transform(sym.get_transform());
}
void operator () (polygon_symbolizer const& sym)
{
collect_metawriter(sym);
collect_transform(sym.get_transform());
}
void operator () (polygon_pattern_symbolizer const& sym)
@ -138,6 +145,8 @@ struct symbolizer_attributes : public boost::static_visitor<>
path_processor_type::collect_attributes(*filename_expr,names_);
}
collect_metawriter(sym);
collect_transform(sym.get_image_transform());
collect_transform(sym.get_transform());
}
void operator () (shield_symbolizer const& sym)
@ -145,7 +154,6 @@ struct symbolizer_attributes : public boost::static_visitor<>
expression_set::const_iterator it;
expression_set expressions;
sym.get_placement_options()->add_expressions(expressions);
expression_attributes f_attr(names_);
for (it=expressions.begin(); it != expressions.end(); it++)
{
if (*it) boost::apply_visitor(f_attr, **it);
@ -157,11 +165,15 @@ struct symbolizer_attributes : public boost::static_visitor<>
path_processor_type::collect_attributes(*filename_expr,names_);
}
collect_metawriter(sym);
collect_transform(sym.get_image_transform());
collect_transform(sym.get_transform());
}
void operator () (markers_symbolizer const& sym)
{
collect_metawriter(sym);
collect_transform(sym.get_image_transform());
collect_transform(sym.get_transform());
}
void operator () (building_symbolizer const& sym)
@ -169,20 +181,28 @@ struct symbolizer_attributes : public boost::static_visitor<>
expression_ptr const& height_expr = sym.height();
if (height_expr)
{
expression_attributes f_attr(names_);
boost::apply_visitor(f_attr,*height_expr);
}
collect_metawriter(sym);
collect_transform(sym.get_transform());
}
// TODO - support remaining syms
private:
std::set<std::string>& names_;
expression_attributes<std::set<std::string> > f_attr;
void collect_metawriter(symbolizer_base const& sym)
{
metawriter_properties const& properties = sym.get_metawriter_properties();
names_.insert(properties.begin(), properties.end());
}
void collect_transform(transform_list_ptr const& trans_expr)
{
if (trans_expr)
{
transform_processor_type::collect_attributes(names_, *trans_expr);
}
}
};
@ -190,10 +210,11 @@ class attribute_collector : public boost::noncopyable
{
private:
std::set<std::string>& names_;
expression_attributes<std::set<std::string> > f_attr;
public:
attribute_collector(std::set<std::string>& names)
: names_(names) {}
: names_(names), f_attr(names) {}
template <typename RuleType>
void operator() (RuleType const& r)
@ -207,7 +228,6 @@ public:
}
expression_ptr const& expr = r.get_filter();
expression_attributes f_attr(names_);
boost::apply_visitor(f_attr,*expr);
}
};

View file

@ -79,6 +79,21 @@ public:
{
}
box2d<double> bounding_box() const
{
if (is_vector())
{
return (*vector_data_)->bounding_box();
}
if (is_bitmap())
{
double width = (*bitmap_data_)->width();
double height = (*bitmap_data_)->height();
return box2d<double>(0, 0, width, height);
}
return box2d<double>();
}
inline double width() const
{
if (is_bitmap())

View file

@ -0,0 +1,243 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 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_PARSE_TRANSFORM_HPP
#define MAPNIK_PARSE_TRANSFORM_HPP
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/value.hpp>
#include <mapnik/transform_expression.hpp>
#include <mapnik/expression_evaluator.hpp>
// boost
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/variant.hpp>
#include <boost/foreach.hpp>
// agg
#include <agg_trans_affine.h>
namespace mapnik {
template <typename Container> struct expression_attributes;
template <typename Iterator> struct transform_expression_grammar;
MAPNIK_DECL transform_list_ptr parse_transform(std::string const & str);
MAPNIK_DECL bool parse_transform(transform_list& list,
std::string const & str,
transform_expression_grammar<std::string::const_iterator> const& g);
template <typename T>
struct transform_processor
{
typedef T feature_type;
typedef agg::trans_affine transform_type;
template <typename Container>
struct attribute_collector : boost::static_visitor<void>
{
expression_attributes<Container> collect_;
attribute_collector(Container& names)
: collect_(names) {}
void operator() (identity_node const& node) const
{
boost::ignore_unused_variable_warning(node);
}
void operator() (matrix_node const& node) const
{
boost::apply_visitor(collect_, node.a_);
boost::apply_visitor(collect_, node.b_);
boost::apply_visitor(collect_, node.c_);
boost::apply_visitor(collect_, node.d_);
boost::apply_visitor(collect_, node.e_);
boost::apply_visitor(collect_, node.f_);
}
void operator() (translate_node const& node) const
{
boost::apply_visitor(collect_, node.tx_);
boost::apply_visitor(collect_, node.ty_);
}
void operator() (scale_node const& node) const
{
boost::apply_visitor(collect_, node.sx_);
boost::apply_visitor(collect_, node.sy_);
}
void operator() (rotate_node const& node) const
{
boost::apply_visitor(collect_, node.angle_);
boost::apply_visitor(collect_, node.cx_);
boost::apply_visitor(collect_, node.cy_);
}
void operator() (skewX_node const& node) const
{
boost::apply_visitor(collect_, node.angle_);
}
void operator() (skewY_node const& node) const
{
boost::apply_visitor(collect_, node.angle_);
}
};
struct node_evaluator : boost::static_visitor<void>
{
node_evaluator(transform_type& tr, feature_type const& feat)
: transform_(tr), feature_(feat) {}
void operator() (identity_node const& node)
{
boost::ignore_unused_variable_warning(node);
}
void operator() (matrix_node const& node)
{
double a = eval(node.a_);
double b = eval(node.b_);
double c = eval(node.c_);
double d = eval(node.d_);
double e = eval(node.e_);
double f = eval(node.f_);
transform_.multiply(agg::trans_affine(a, b, c, d, e, f));
}
void operator() (translate_node const& node)
{
double tx = eval(node.tx_);
double ty = eval(node.ty_, 0.0);
transform_.translate(tx, ty);
}
void operator() (scale_node const& node)
{
double sx = eval(node.sx_);
double sy = eval(node.sy_, sx);
transform_.scale(sx, sy);
}
void operator() (rotate_node const& node)
{
double angle = deg2rad(eval(node.angle_));
double cx = eval(node.cx_, 0.0);
double cy = eval(node.cy_, 0.0);
transform_.translate(-cx, -cy);
transform_.rotate(angle);
transform_.translate(cx, cy);
}
void operator() (skewX_node const& node)
{
double angle = deg2rad(eval(node.angle_));
transform_.multiply(agg::trans_affine_skewing(angle, 0.0));
}
void operator() (skewY_node const& node)
{
double angle = deg2rad(eval(node.angle_));
transform_.multiply(agg::trans_affine_skewing(0.0, angle));
}
private:
static double deg2rad(double d)
{
return d * M_PI / 180.0;
}
double eval(expr_node const& x) const
{
mapnik::evaluate<feature_type, value_type> e(feature_);
return boost::apply_visitor(e, x).to_double();
}
double eval(expr_node const& x, double def) const
{
return is_null(x) ? def : eval(x);
}
transform_type& transform_;
feature_type const& feature_;
};
template <typename Container>
static void collect_attributes(Container& names,
transform_list const& list)
{
attribute_collector<Container> collect(names);
BOOST_FOREACH (transform_node const& node, list)
{
boost::apply_visitor(collect, *node);
}
}
static void evaluate(transform_type& tr, feature_type const& feat,
transform_list const& list)
{
node_evaluator eval(tr, feat);
#ifdef MAPNIK_LOG
MAPNIK_LOG_DEBUG(transform) << "transform: begin with " << to_string(matrix_node(tr));
#endif
BOOST_REVERSE_FOREACH (transform_node const& node, list)
{
boost::apply_visitor(eval, *node);
#ifdef MAPNIK_LOG
MAPNIK_LOG_DEBUG(transform) << "transform: apply " << to_string(*node);
MAPNIK_LOG_DEBUG(transform) << "transform: result " << to_string(matrix_node(tr));
#endif
}
#ifdef MAPNIK_LOG
MAPNIK_LOG_DEBUG(transform) << "transform: end";
#endif
}
static std::string to_string(transform_node const& node)
{
return to_expression_string(node);
}
static std::string to_string(transform_list const& list)
{
return to_expression_string(list);
}
};
typedef mapnik::transform_processor<Feature> transform_processor_type;
} // namespace mapnik
#endif // MAPNIK_PARSE_TRANSFORM_HPP

View file

@ -28,6 +28,7 @@
#include <mapnik/parse_path.hpp>
#include <mapnik/metawriter.hpp>
#include <mapnik/image_compositing.hpp>
#include <mapnik/transform_expression.hpp>
// boost
#include <boost/array.hpp>
@ -36,7 +37,10 @@
namespace mapnik
{
typedef boost::array<double,6> transform_type;
typedef transform_list_ptr transform_type;
MAPNIK_DECL void evaluate_transform(agg::trans_affine& tr, Feature const& feature,
transform_type const& trans_expr);
class Map;

View file

@ -150,6 +150,21 @@ public:
init_marker();
}
box2d<double> const& get_marker_extent() const
{
return marker_ext_;
}
double get_marker_height() const
{
return marker_h_;
}
double get_marker_width() const
{
return marker_w_;
}
bool next();
pixel_position get_marker_position(text_path const& p);
marker & get_marker() const;

View file

@ -0,0 +1,181 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 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_TRANSFORM_EXPRESSION_HPP
#define MAPNIK_TRANSFORM_EXPRESSION_HPP
// mapnik
#include <mapnik/expression_node.hpp>
// boost
#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/variant.hpp>
// agg
#include <agg_trans_affine.h>
// stl
#include <vector>
namespace mapnik {
struct identity_node {};
struct matrix_node
{
expr_node a_;
expr_node b_;
expr_node c_;
expr_node d_;
expr_node e_;
expr_node f_;
explicit matrix_node(double const* m)
: a_(m[0]), b_(m[1]), c_(m[2]), d_(m[3]), e_(m[4]), f_(m[5]) {}
explicit matrix_node(agg::trans_affine const& m)
: a_(m.sx), b_(m.shy), c_(m.shx), d_(m.sy), e_(m.tx), f_(m.ty) {}
matrix_node(expr_node const& a, expr_node const& b, expr_node const& c,
expr_node const& d, expr_node const& e, expr_node const& f)
: a_(a), b_(b), c_(c), d_(d), e_(e), f_(f) {}
};
struct translate_node
{
expr_node tx_;
expr_node ty_;
translate_node(expr_node const& tx,
boost::optional<expr_node> const& ty)
: tx_(tx)
, ty_(ty ? *ty : value_null()) {}
};
struct scale_node
{
expr_node sx_;
expr_node sy_;
scale_node(expr_node const& sx,
boost::optional<expr_node> const& sy)
: sx_(sx)
, sy_(sy ? *sy : value_null()) {}
};
struct rotate_node
{
expr_node angle_;
expr_node cx_;
expr_node cy_;
rotate_node(expr_node const& angle,
boost::optional<expr_node> const& cx,
boost::optional<expr_node> const& cy)
: angle_(angle)
, cx_(cx ? *cx : value_null())
, cy_(cy ? *cy : value_null()) {}
};
struct skewX_node
{
expr_node angle_;
explicit skewX_node(expr_node const& angle)
: angle_(angle) {}
};
struct skewY_node
{
expr_node angle_;
explicit skewY_node(expr_node const& angle)
: angle_(angle) {}
};
namespace detail {
// boost::spirit::traits::clear<T>(T& val) [with T = boost::variant<...>]
// attempts to assign to the variant's current value a default-constructed
// value ot the same type, which not only requires that each value-type is
// default-constructible, but also makes little sense with our variant of
// transform nodes...
typedef boost::variant< identity_node
, matrix_node
, translate_node
, scale_node
, rotate_node
, skewX_node
, skewY_node
> transform_variant;
// ... thus we wrap the variant-type in a distinct type and provide
// a custom clear overload, which resets the value to identity_node
struct transform_node
{
transform_variant base_;
transform_node()
: base_() {}
template <typename T>
transform_node(T const& val)
: base_(val) {}
template <typename T>
transform_node& operator= (T const& val)
{
base_ = val;
return *this;
}
transform_variant const& operator* () const
{
return base_;
}
transform_variant& operator* ()
{
return base_;
}
};
inline void clear(transform_node& val)
{
val.base_ = identity_node();
}
} // namespace detail
typedef detail::transform_node transform_node;
typedef std::vector<transform_node> transform_list;
typedef boost::shared_ptr<transform_list> transform_list_ptr;
MAPNIK_DECL std::string to_expression_string(transform_node const& node);
MAPNIK_DECL std::string to_expression_string(transform_list const& list);
} // namespace mapnik
#endif // MAPNIK_TRANSFORM_EXPRESSION_HPP

View file

@ -0,0 +1,121 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 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_TRANSFORM_EXPRESSION_GRAMMAR_HPP
#define MAPNIK_TRANSFORM_EXPRESSION_GRAMMAR_HPP
// mapnik
#include <mapnik/expression_grammar.hpp>
#include <mapnik/transform_expression.hpp>
// spirit
#include <boost/spirit/home/phoenix/object/construct.hpp>
#include <boost/spirit/home/qi.hpp>
namespace mapnik {
namespace qi = boost::spirit::qi;
template <typename Iterator>
struct transform_expression_grammar
: qi::grammar<Iterator, transform_list(), space_type>
{
explicit transform_expression_grammar(expression_grammar<Iterator> const& g)
: transform_expression_grammar::base_type(start)
{
using boost::phoenix::construct;
using qi::_a; using qi::_1; using qi::_4;
using qi::_b; using qi::_2; using qi::_5;
using qi::_c; using qi::_3; using qi::_6;
using qi::_val;
using qi::char_;
using qi::lit;
using qi::no_case;
using qi::no_skip;
start = transform_ % no_skip[char_(", ")] ;
transform_ = matrix | translate | scale | rotate | skewX | skewY ;
matrix = no_case[lit("matrix")]
>> (lit('(')
>> expr >> -lit(',')
>> expr >> -lit(',')
>> expr >> -lit(',')
>> expr >> -lit(',')
>> expr >> -lit(',')
>> expr >> lit(')'))
[ _val = construct<matrix_node>(_1,_2,_3,_4,_5,_6) ];
translate = no_case[lit("translate")]
>> (lit('(')
>> expr >> -lit(',')
>> -expr >> lit(')'))
[ _val = construct<translate_node>(_1,_2) ];
scale = no_case[lit("scale")]
>> (lit('(')
>> expr >> -lit(',')
>> -expr >> lit(')'))
[ _val = construct<scale_node>(_1,_2) ];
rotate = no_case[lit("rotate")]
>> lit('(')
>> expr[_a = _1] >> -lit(',')
>> -(expr [_b = _1] >> -lit(',') >> expr[_c = _1])
>> lit(')')
[ _val = construct<rotate_node>(_a,_b,_c) ];
skewX = no_case[lit("skewX")]
>> lit('(')
>> expr [ _val = construct<skewX_node>(_1) ]
>> lit(')');
skewY = no_case[lit("skewY")]
>> lit('(')
>> expr [ _val = construct<skewY_node>(_1) ]
>> lit(')');
expr = g.expr.alias();
}
typedef qi::locals<expr_node, boost::optional<expr_node>,
boost::optional<expr_node>
> rotate_locals;
typedef qi::rule<Iterator, transform_node(), space_type> node_rule;
typedef qi::rule<Iterator, transform_list(), space_type> list_rule;
// rules
typename expression_grammar<Iterator>::rule_type expr;
qi::rule<Iterator, transform_list(), space_type> start;
qi::rule<Iterator, transform_node(), space_type> transform_;
qi::rule<Iterator, transform_node(), space_type> matrix;
qi::rule<Iterator, transform_node(), space_type> translate;
qi::rule<Iterator, transform_node(), space_type> scale;
qi::rule<Iterator, transform_node(), space_type, rotate_locals> rotate;
qi::rule<Iterator, transform_node(), space_type> skewX;
qi::rule<Iterator, transform_node(), space_type> skewY;
};
} // namespace mapnik
#endif // MAPNIK_TRANSFORM_EXPRESSION_GRAMMAR_HPP

View file

@ -120,9 +120,8 @@ struct converter_traits<T, mapnik::dash_tag>
template <typename Args>
static void setup(geometry_type & geom, Args const& args)
{
typename boost::mpl::at<Args,boost::mpl::int_<2> >::type sym = boost::fusion::at_c<2>(args);
double scale_factor = boost::fusion::at_c<5>(args);
double scale_factor = boost::fusion::at_c<6>(args);
stroke const& stroke_ = sym.get_stroke();
dash_array const& d = stroke_.get_dash_array();
dash_array::const_iterator itr = d.begin();
@ -149,7 +148,7 @@ struct converter_traits<T, mapnik::stroke_tag>
stroke const& stroke_ = sym.get_stroke();
set_join_caps(stroke_,geom);
geom.generator().miter_limit(stroke_.get_miterlimit());
double scale_factor = boost::fusion::at_c<5>(args);
double scale_factor = boost::fusion::at_c<6>(args);
geom.generator().width(stroke_.get_width() * scale_factor);
}
};
@ -179,10 +178,8 @@ struct converter_traits<T,mapnik::transform_tag>
template <typename Args>
static void setup(geometry_type & geom, Args const& args)
{
typename boost::mpl::at<Args,boost::mpl::int_<3> >::type tr = boost::fusion::at_c<3>(args);
typename boost::mpl::at<Args,boost::mpl::int_<4> >::type prj_trans = boost::fusion::at_c<4>(args);
geom.set_proj_trans(prj_trans);
geom.set_trans(tr);
geom.set_proj_trans(boost::fusion::at_c<4>(args));
geom.set_trans(boost::fusion::at_c<3>(args));
}
};
@ -191,21 +188,19 @@ template <typename T>
struct converter_traits<T,mapnik::affine_transform_tag>
{
typedef T geometry_type;
typedef agg::conv_transform<geometry_type, agg::trans_affine const>
conv_base_type;
struct conv_type : public agg::conv_transform<geometry_type>
struct conv_type : public conv_base_type
{
agg::trans_affine trans_;
conv_type(geometry_type& geom)
: agg::conv_transform<geometry_type>(geom, trans_) {}
: conv_base_type(geom, agg::trans_affine::identity) {}
};
template <typename Args>
static void setup(geometry_type & geom, Args & args)
{
typename boost::mpl::at<Args,boost::mpl::int_<2> >::type sym = boost::fusion::at_c<2>(args);
boost::array<double,6> const& m = sym.get_transform();
geom.trans_.load_from(&m[0]);
geom.transformer(boost::fusion::at_c<5>(args));
}
};
@ -303,15 +298,16 @@ struct dispatcher
template <typename B, typename R, typename S, typename P, typename T, typename C >
template <typename B, typename R, typename S, typename T, typename P, typename A, typename C >
struct vertex_converter : private boost::noncopyable
{
typedef C conv_types;
typedef B bbox_type;
typedef R rasterizer_type;
typedef S symbolizer_type;
typedef P proj_trans_type;
typedef T trans_type;
typedef P proj_trans_type;
typedef A affine_trans_type;
typedef typename boost::fusion::vector
<
bbox_type const&,
@ -319,16 +315,20 @@ struct vertex_converter : private boost::noncopyable
symbolizer_type const&,
trans_type const&,
proj_trans_type const&,
affine_trans_type const&,
double //scale-factor
> args_type;
vertex_converter(bbox_type const& b, rasterizer_type & ras,
symbolizer_type const& sym, trans_type & tr,
proj_trans_type const& prj_trans,
affine_trans_type const& affine_trans,
double scale_factor)
: disp_(args_type(boost::cref(b), boost::ref(ras),
boost::cref(sym), boost::cref(tr),
boost::cref(prj_trans),scale_factor)) {}
boost::cref(prj_trans),
boost::cref(affine_trans),
scale_factor)) {}
template <typename Geometry>
void apply(Geometry & geom)

View file

@ -26,6 +26,7 @@
#include <mapnik/xml_node.hpp>
#include <mapnik/expression_grammar.hpp>
#include <mapnik/path_expression_grammar.hpp>
#include <mapnik/transform_expression_grammar.hpp>
// boost
#include <boost/format.hpp>
@ -57,6 +58,7 @@ public:
mapnik::css_color_grammar<std::string::const_iterator> color_grammar;
mapnik::expression_grammar<std::string::const_iterator> expr_grammar;
path_expression_grammar<std::string::const_iterator> path_expr_grammar;
transform_expression_grammar<std::string::const_iterator> transform_expr_grammar;
};
} //ns mapnik

View file

@ -277,7 +277,7 @@ void agg_renderer<T>::render_marker(pixel_position const& pos, marker const& mar
mtx *= tr;
mtx *= agg::trans_affine_scaling(scale_factor_);
// render the marker at the center of the marker box
mtx.translate(pos.x+0.5 * marker.width(), pos.y+0.5 * marker.height());
mtx.translate(pos.x, pos.y);
using namespace mapnik::svg;
vertex_stl_adapter<svg_path_storage> stl_storage((*marker.get_vector_data())->source());
svg_path_adapter svg_path(stl_storage);
@ -291,10 +291,12 @@ void agg_renderer<T>::render_marker(pixel_position const& pos, marker const& mar
}
else
{
double cx = 0.5 * (*marker.get_bitmap_data())->width();
double cy = 0.5 * (*marker.get_bitmap_data())->height();
composite(current_buffer_->data(), **marker.get_bitmap_data(),
comp_op, opacity,
boost::math::iround(pos.x),
boost::math::iround(pos.y),
boost::math::iround(pos.x - cx),
boost::math::iround(pos.y - cy),
false, false);
}
}
@ -305,5 +307,57 @@ void agg_renderer<T>::painted(bool painted)
pixmap_.painted(painted);
}
template class agg_renderer<image_32>;
template <typename T>
void agg_renderer<T>::debug_draw_box(box2d<double> const& box,
double x, double y, double angle)
{
agg::rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_ * 4);
debug_draw_box(buf, box, x, y, angle);
}
template <typename T> template <typename R>
void agg_renderer<T>::debug_draw_box(R& buf, box2d<double> const& box,
double x, double y, double angle)
{
typedef agg::pixfmt_rgba32 pixfmt;
typedef agg::renderer_base<pixfmt> renderer_base;
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_type;
agg::scanline_p8 sl_line;
pixfmt pixf(buf);
renderer_base renb(pixf);
renderer_type ren(renb);
// compute tranformation matrix
agg::trans_affine_rotation tr(angle);
tr.translate(x, y);
// prepare path
agg::path_storage pbox;
pbox.start_new_path();
pbox.move_to(box.minx(), box.miny());
pbox.line_to(box.maxx(), box.miny());
pbox.line_to(box.maxx(), box.maxy());
pbox.line_to(box.minx(), box.maxy());
pbox.line_to(box.minx(), box.miny());
// prepare stroke with applied transformation
typedef agg::conv_transform<agg::path_storage> conv_transform;
typedef agg::conv_stroke<conv_transform> conv_stroke;
conv_transform tbox(pbox, tr);
conv_stroke sbox(tbox);
sbox.generator().width(1.0 * scale_factor_);
// render the outline
ras_ptr->reset();
ras_ptr->add_path(sbox);
ren.color(agg::rgba8(0x33, 0x33, 0xff, 0xcc)); // blue is fine
agg::render_scanlines(*ras_ptr, sl_line, ren);
}
template class agg_renderer<image_32>;
template void agg_renderer<image_32>::debug_draw_box<agg::rendering_buffer>(
agg::rendering_buffer& buf,
box2d<double> const& box,
double x, double y, double angle);
}

View file

@ -94,9 +94,13 @@ void agg_renderer<T>::process(line_pattern_symbolizer const& sym,
renderer_type ren(ren_base, pattern);
rasterizer_type ras(ren);
agg::trans_affine tr;
evaluate_transform(tr, *feature, sym.get_transform());
typedef boost::mpl::vector<clip_line_tag,transform_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>,rasterizer_type,line_pattern_symbolizer, proj_transform, CoordTransform, conv_types>
converter(ext,ras,sym,t_,prj_trans,scale_factor_);
vertex_converter<box2d<double>, rasterizer_type, line_pattern_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(ext,ras,sym,t_,prj_trans,tr,scale_factor_);
if (sym.clip()) converter.set<clip_line_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform

View file

@ -76,6 +76,9 @@ void agg_renderer<T>::process(line_symbolizer const& sym,
pixfmt_comp_type pixf(buf);
renderer_base renb(pixf);
agg::trans_affine tr;
evaluate_transform(tr, *feature, sym.get_transform());
if (sym.get_rasterizer() == RASTERIZER_FAST)
{
typedef agg::renderer_outline_aa<renderer_base> renderer_type;
@ -89,8 +92,9 @@ void agg_renderer<T>::process(line_symbolizer const& sym,
set_join_caps_aa(stroke_,ras);
typedef boost::mpl::vector<clip_line_tag,transform_tag, offset_transform_tag, affine_transform_tag, smooth_tag, dash_tag, stroke_tag> conv_types;
vertex_converter<box2d<double>,rasterizer_type,line_symbolizer, proj_transform, CoordTransform,conv_types>
converter(query_extent_,ras,sym,t_,prj_trans,scaled);
vertex_converter<box2d<double>, rasterizer_type, line_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,ras,sym,t_,prj_trans,tr,scaled);
if (sym.clip()) converter.set<clip_line_tag>(); // optional clip (default: true)
converter.set<transform_tag>(); // always transform
@ -111,8 +115,9 @@ void agg_renderer<T>::process(line_symbolizer const& sym,
else
{
typedef boost::mpl::vector<clip_line_tag,transform_tag, offset_transform_tag, affine_transform_tag, smooth_tag, dash_tag, stroke_tag> conv_types;
vertex_converter<box2d<double>,rasterizer,line_symbolizer, proj_transform, CoordTransform,conv_types>
converter(query_extent_,*ras_ptr,sym,t_,prj_trans,scale_factor_);
vertex_converter<box2d<double>, rasterizer, line_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
if (sym.clip()) converter.set<clip_line_tag>(); // optional clip (default: true)
converter.set<transform_tag>(); // always transform

View file

@ -73,8 +73,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
renderer_base renb(pixf);
renderer_type ren(renb);
agg::trans_affine tr;
boost::array<double,6> const& m = sym.get_image_transform();
tr.load_from(&m[0]);
evaluate_transform(tr, *feature, sym.get_image_transform());
tr = agg::trans_affine_scaling(scale_factor_) * tr;
std::string filename = path_processor_type::evaluate(*sym.get_filename(), *feature);
marker_placement_e placement_method = sym.get_marker_placement();
@ -94,17 +93,12 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
}
boost::optional<path_ptr> marker = (*mark)->get_vector_data();
box2d<double> const& bbox = (*marker)->bounding_box();
double x1 = bbox.minx();
double y1 = bbox.miny();
double x2 = bbox.maxx();
double y2 = bbox.maxy();
double w = (*mark)->width();
double h = (*mark)->height();
coord2d const center = bbox.center();
agg::trans_affine_translation const recenter(-center.x, -center.y);
agg::trans_affine const recenter_tr = recenter * tr;
box2d<double> extent = bbox * recenter_tr;
agg::trans_affine recenter = agg::trans_affine_translation(-0.5*(x1+x2),-0.5*(y1+y2));
tr.transform(&x1,&y1);
tr.transform(&x2,&y2);
box2d<double> extent(x1,y1,x2,y2);
using namespace mapnik::svg;
vertex_stl_adapter<svg_path_storage> stl_storage((*marker)->source());
svg_path_adapter svg_path(stl_storage);
@ -132,7 +126,11 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
detector_->has_placement(extent))
{
render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h) ,**mark, tr, sym.get_opacity(), sym.comp_op());
render_marker(pixel_position(x, y), **mark, tr, sym.get_opacity(), sym.comp_op());
if (/* DEBUG */ 0) {
debug_draw_box(buf, extent, 0, 0, 0.0);
}
// TODO - impl this for markers?
//if (!sym.get_ignore_placement())
@ -154,8 +152,22 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
while (placement.get_point(&x, &y, &angle))
{
agg::trans_affine matrix = recenter * tr *agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y);
agg::trans_affine matrix = recenter_tr;
matrix.rotate(angle);
matrix.translate(x, y);
svg_renderer.render(*ras_ptr, sl, renb, matrix, sym.get_opacity(),bbox);
if (/* DEBUG */ 0) {
agg::trans_affine_rotation r(angle);
debug_draw_box(buf, extent * r, x, y, 0.0);
// note: debug_draw_box(buf, extent, x, y, angle)
// would draw a rotated box showing the proper
// bounds of the marker, while the above will
// draw the box used for collision detection,
// which embraces the rotated extent but isn't
// rotated itself
}
if (writer.first)
{
//writer.first->add_box(label_ext, feature, t_, writer.second);

View file

@ -63,26 +63,15 @@ void agg_renderer<T>::process(point_symbolizer const& sym,
if (marker)
{
double w = (*marker)->width();
double h = (*marker)->height();
box2d<double> const& bbox = (*marker)->bounding_box();
coord2d const center = bbox.center();
agg::trans_affine tr;
boost::array<double,6> const& m = sym.get_image_transform();
tr.load_from(&m[0]);
double px0 = - 0.5 * w;
double py0 = - 0.5 * h;
double px1 = 0.5 * w;
double py1 = 0.5 * h;
double px2 = px1;
double py2 = py0;
double px3 = px0;
double py3 = py1;
tr.transform(&px0,&py0);
tr.transform(&px1,&py1);
tr.transform(&px2,&py2);
tr.transform(&px3,&py3);
box2d<double> label_ext (px0, py0, px1, py1);
label_ext.expand_to_include(px2, py2);
label_ext.expand_to_include(px3, py3);
evaluate_transform(tr, *feature, sym.get_image_transform());
agg::trans_affine_translation const recenter(-center.x, -center.y);
agg::trans_affine const recenter_tr = recenter * tr;
box2d<double> label_ext = bbox * recenter_tr;
for (unsigned i=0; i<feature->num_geometries(); ++i)
{
@ -103,7 +92,11 @@ void agg_renderer<T>::process(point_symbolizer const& sym,
detector_->has_placement(label_ext))
{
render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h) ,**marker,tr, sym.get_opacity(), sym.comp_op());
render_marker(pixel_position(x, y), **marker, tr, sym.get_opacity(), sym.comp_op());
if (/* DEBUG */ 0) {
debug_draw_box(label_ext, 0, 0, 0.0);
}
if (!sym.get_ignore_placement())
detector_->insert(label_ext);

View file

@ -136,10 +136,14 @@ void agg_renderer<T>::process(polygon_pattern_symbolizer const& sym,
agg::span_allocator<agg::rgba8> sa;
renderer_type rp(renb,sa, sg);
agg::trans_affine tr;
evaluate_transform(tr, *feature, sym.get_transform());
box2d<double> inflated_extent = query_extent_ * 1.0;
typedef boost::mpl::vector<clip_poly_tag,transform_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>,rasterizer,polygon_pattern_symbolizer, proj_transform, CoordTransform,conv_types>
converter(inflated_extent,*ras_ptr,sym,t_,prj_trans, scale_factor_);
vertex_converter<box2d<double>, rasterizer, polygon_pattern_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(inflated_extent,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform

View file

@ -50,9 +50,13 @@ void agg_renderer<T>::process(polygon_symbolizer const& sym,
box2d<double> inflated_extent = query_extent_ * 1.0;
agg::trans_affine tr;
evaluate_transform(tr, *feature, sym.get_transform());
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>,rasterizer,polygon_symbolizer, proj_transform, CoordTransform,conv_types>
converter(inflated_extent,*ras_ptr,sym,t_,prj_trans,scale_factor_);
vertex_converter<box2d<double>, rasterizer, polygon_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(inflated_extent,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform

View file

@ -52,7 +52,15 @@ void agg_renderer<T>::process(shield_symbolizer const& sym,
placements_type &placements = helper.placements();
for (unsigned int ii = 0; ii < placements.size(); ++ii)
{
render_marker(helper.get_marker_position(placements[ii]),
// get_marker_position returns (minx,miny) corner position,
// while (currently only) agg_renderer::render_marker newly
// expects center position;
// until all renderers and shield_symbolizer_helper are
// modified accordingly, we must adjust the position here
pixel_position pos = helper.get_marker_position(placements[ii]);
pos.x += 0.5 * helper.get_marker_width();
pos.y += 0.5 * helper.get_marker_height();
render_marker(pos,
helper.get_marker(),
helper.get_image_transform(),
sym.get_opacity(),

View file

@ -110,6 +110,7 @@ source = Split(
deepcopy.cpp
expression_string.cpp
expression.cpp
transform_expression.cpp
feature_kv_iterator.cpp
feature_type_style.cpp
font_engine_freetype.cpp
@ -126,6 +127,7 @@ source = Split(
load_map.cpp
memory.cpp
parse_path.cpp
parse_transform.cpp
palette.cpp
placement_finder.cpp
plugin.cpp

View file

@ -833,9 +833,13 @@ void cairo_renderer_base::start_map_processing(Map const& map)
context.set_operator(sym.comp_op());
context.set_color(sym.get_fill(), sym.get_opacity());
agg::trans_affine tr;
evaluate_transform(tr, *feature, sym.get_transform());
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>,cairo_context,polygon_symbolizer, proj_transform, CoordTransform, conv_types>
converter(query_extent_,context,sym,t_,prj_trans,1.0);
vertex_converter<box2d<double>, cairo_context, polygon_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,context,sym,t_,prj_trans,tr,1.0);
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
@ -980,10 +984,13 @@ void cairo_renderer_base::start_map_processing(Map const& map)
context.set_dash(stroke_.get_dash_array());
}
agg::trans_affine tr;
evaluate_transform(tr, *feature, sym.get_transform());
typedef boost::mpl::vector<clip_line_tag,transform_tag, offset_transform_tag, affine_transform_tag, smooth_tag> conv_types;
vertex_converter<box2d<double>,cairo_context,line_symbolizer, proj_transform, CoordTransform,conv_types>
converter(query_extent_,context ,sym,t_,prj_trans,1.0);
vertex_converter<box2d<double>, cairo_context, line_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,context,sym,t_,prj_trans,tr,1.0);
if (sym.clip()) converter.set<clip_line_tag>(); // optional clip (default: true)
converter.set<transform_tag>(); // always transform
@ -1131,6 +1138,9 @@ void cairo_renderer_base::start_map_processing(Map const& map)
marker.reset(boost::make_shared<mapnik::marker>());
}
agg::trans_affine mtx;
evaluate_transform(mtx, *feature, sym.get_image_transform());
if (marker)
{
for (unsigned i = 0; i < feature->num_geometries(); ++i)
@ -1157,10 +1167,6 @@ void cairo_renderer_base::start_map_processing(Map const& map)
if (sym.get_allow_overlap() ||
detector_.has_placement(label_ext))
{
agg::trans_affine mtx;
boost::array<double,6> const& m = sym.get_image_transform();
mtx.load_from(&m[0]);
render_marker(pixel_position(px,py),**marker, mtx, sym.get_opacity());
if (!sym.get_ignore_placement())
@ -1293,9 +1299,13 @@ void cairo_renderer_base::start_map_processing(Map const& map)
context.set_pattern(pattern);
agg::trans_affine tr;
evaluate_transform(tr, *feature, sym.get_transform());
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>,cairo_context,polygon_pattern_symbolizer, proj_transform, CoordTransform, conv_types>
converter(query_extent_,context,sym,t_,prj_trans,1.0);
vertex_converter<box2d<double>, cairo_context, polygon_pattern_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,context,sym,t_,prj_trans,tr,1.0);
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
@ -1371,8 +1381,8 @@ void cairo_renderer_base::start_map_processing(Map const& map)
typedef coord_transform<CoordTransform,clipped_geometry_type> path_type;
agg::trans_affine tr;
boost::array<double,6> const& m = sym.get_image_transform();
tr.load_from(&m[0]);
evaluate_transform(tr, *feature, sym.get_image_transform());
// TODO - use this?
//tr = agg::trans_affine_scaling(scale_factor_) * tr;
std::string filename = path_processor_type::evaluate(*sym.get_filename(), *feature);

View file

@ -69,8 +69,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
ras_ptr->reset();
agg::trans_affine tr;
boost::array<double,6> const& m = sym.get_image_transform();
tr.load_from(&m[0]);
evaluate_transform(tr, *feature, sym.get_image_transform());
unsigned int res = pixmap_.get_resolution();
tr = agg::trans_affine_scaling(scale_factor_*(1.0/res)) * tr;
std::string filename = path_processor_type::evaluate(*sym.get_filename(), *feature);

View file

@ -55,6 +55,9 @@ void grid_renderer<T>::process(point_symbolizer const& sym,
if (marker)
{
agg::trans_affine tr;
evaluate_transform(tr, *feature, sym.get_image_transform());
for (unsigned i=0; i<feature->num_geometries(); ++i)
{
geometry_type const& geom = feature->get_geometry(i);
@ -78,10 +81,6 @@ void grid_renderer<T>::process(point_symbolizer const& sym,
if (sym.get_allow_overlap() ||
detector_.has_placement(label_ext))
{
agg::trans_affine tr;
boost::array<double,6> const& m = sym.get_image_transform();
tr.load_from(&m[0]);
render_marker(feature, pixmap_.get_resolution(),
pixel_position(px, py),
**marker, tr,

View file

@ -42,6 +42,7 @@
#include <mapnik/expression.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/parse_transform.hpp>
#include <mapnik/raster_colorizer.hpp>
#include <mapnik/svg/svg_path_parser.hpp>
@ -838,8 +839,8 @@ void map_parser::parse_symbolizer_base(symbolizer_base &sym, xml_node const &pt)
optional<std::string> transform_wkt = pt.get_opt_attr<std::string>("transform");
if (transform_wkt)
{
agg::trans_affine tr;
if (!mapnik::svg::parse_transform((*transform_wkt).c_str(),tr))
mapnik::transform_list_ptr tl = boost::make_shared<mapnik::transform_list>();
if (!mapnik::parse_transform(*tl, *transform_wkt, pt.get_tree().transform_expr_grammar))
{
std::stringstream ss;
ss << "Could not parse transform from '" << transform_wkt << "', expected SVG transform attribute";
@ -848,9 +849,7 @@ void map_parser::parse_symbolizer_base(symbolizer_base &sym, xml_node const &pt)
else
std::clog << "### WARNING: " << ss.str() << endl;
}
boost::array<double,6> matrix;
tr.store_to(&matrix[0]);
sym.set_transform(matrix);
sym.set_transform(tl);
}
optional<boolean> clip = pt.get_opt_attr<boolean>("clip");
@ -919,8 +918,8 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym)
optional<std::string> image_transform_wkt = sym.get_opt_attr<std::string>("image-transform");
if (image_transform_wkt)
{
agg::trans_affine tr;
if (!mapnik::svg::parse_transform((*image_transform_wkt).c_str(),tr))
mapnik::transform_list_ptr tl = boost::make_shared<mapnik::transform_list>();
if (!mapnik::parse_transform(*tl, *image_transform_wkt, sym.get_tree().transform_expr_grammar))
{
std::stringstream ss;
ss << "Could not parse transform from '" << *image_transform_wkt
@ -934,9 +933,7 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym)
MAPNIK_LOG_WARN(load_map) << "map_parser: " << ss;
}
}
boost::array<double,6> matrix;
tr.store_to(&matrix[0]);
symbol.set_image_transform(matrix);
symbol.set_image_transform(tl);
}
}
catch (image_reader_exception const & ex)
@ -1014,8 +1011,8 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym)
optional<std::string> image_transform_wkt = sym.get_opt_attr<std::string>("image-transform");
if (image_transform_wkt)
{
agg::trans_affine tr;
if (!mapnik::svg::parse_transform((*image_transform_wkt).c_str(),tr))
mapnik::transform_list_ptr tl = boost::make_shared<mapnik::transform_list>();
if (!mapnik::parse_transform(*tl, *image_transform_wkt, sym.get_tree().transform_expr_grammar))
{
std::stringstream ss;
ss << "Could not parse transform from '" << *image_transform_wkt
@ -1029,9 +1026,7 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym)
MAPNIK_LOG_WARN(load_map) << "map_parser: " << ss;
}
}
boost::array<double,6> matrix;
tr.store_to(&matrix[0]);
symbol.set_image_transform(matrix);
symbol.set_image_transform(tl);
}
optional<color> c = sym.get_opt_attr<color>("fill");
@ -1257,8 +1252,8 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym)
optional<std::string> image_transform_wkt = sym.get_opt_attr<std::string>("image-transform");
if (image_transform_wkt)
{
agg::trans_affine tr;
if (!mapnik::svg::parse_transform((*image_transform_wkt).c_str(),tr))
mapnik::transform_list_ptr tl = boost::make_shared<mapnik::transform_list>();
if (!mapnik::parse_transform(*tl, *image_transform_wkt, sym.get_tree().transform_expr_grammar))
{
std::stringstream ss;
ss << "Could not parse transform from '" << *image_transform_wkt
@ -1272,9 +1267,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym)
MAPNIK_LOG_WARN(load_map) << "map_parser: " << ss;
}
}
boost::array<double,6> matrix;
tr.store_to(&matrix[0]);
shield_symbol.set_image_transform(matrix);
shield_symbol.set_image_transform(tl);
}
// shield displacement

46
src/parse_transform.cpp Normal file
View file

@ -0,0 +1,46 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#include <mapnik/parse_transform.hpp>
#include <mapnik/transform_expression_grammar.hpp>
#include <boost/make_shared.hpp>
namespace mapnik {
bool parse_transform(transform_list& transform,
std::string const & str,
transform_expression_grammar<std::string::const_iterator> const& g)
{
std::string::const_iterator itr = str.begin();
std::string::const_iterator end = str.end();
bool r = qi::phrase_parse(itr, end, g, space_type(), transform);
#ifdef MAPNIK_LOG
MAPNIK_LOG_DEBUG(load_map) << "map_parser: Parsed transform [ "
<< transform_processor_type::to_string(transform) << " ]";
#endif
return (r && itr==end);
}
}

View file

@ -244,8 +244,10 @@ public:
{
set_attr( sym_node, "fill-opacity", sym.get_opacity() );
}
set_attr( sym_node, "height", to_expression_string(*sym.height()) );
if (sym.height())
{
set_attr( sym_node, "height", mapnik::to_expression_string(*sym.height()) );
}
add_metawriter_attributes(sym_node, sym);
}
@ -255,8 +257,9 @@ public:
ptree & sym_node = rule_.push_back(
ptree::value_type("MarkersSymbolizer", ptree()))->second;
markers_symbolizer dfl(parse_path("")); //TODO: Parameter?
std::string const& filename = path_processor_type::to_string( *sym.get_filename());
if ( ! filename.empty() ) {
if (sym.get_filename())
{
std::string filename = path_processor_type::to_string(*sym.get_filename());
set_attr( sym_node, "file", filename );
}
if (sym.get_allow_overlap() != dfl.get_allow_overlap() || explicit_defaults_)
@ -299,9 +302,9 @@ public:
{
set_attr( sym_node, "placement", sym.get_marker_placement() );
}
std::string tr_str = sym.get_image_transform_string();
if (tr_str != "matrix(1, 0, 0, 1, 0, 0)" || explicit_defaults_ )
if (sym.get_image_transform())
{
std::string tr_str = sym.get_image_transform_string();
set_attr( sym_node, "image-transform", tr_str );
}
@ -349,8 +352,9 @@ private:
void add_image_attributes(ptree & node, const symbolizer_with_image & sym)
{
std::string const& filename = path_processor_type::to_string( *sym.get_filename());
if ( ! filename.empty() ) {
if (sym.get_filename())
{
std::string filename = path_processor_type::to_string( *sym.get_filename());
set_attr( node, "file", filename );
}
if (sym.get_opacity() != 1.0 || explicit_defaults_ )
@ -358,6 +362,7 @@ private:
set_attr( node, "opacity", sym.get_opacity() );
}
}
void add_font_attributes(ptree & node, const text_symbolizer & sym)
{
text_placements_ptr p = sym.get_placement_options();
@ -386,7 +391,6 @@ private:
}
}
void add_stroke_attributes(ptree & node, const stroke & strk)
{
@ -434,8 +438,8 @@ private:
}
set_attr( node, "stroke-dasharray", os.str() );
}
}
void add_metawriter_attributes(ptree & node, symbolizer_base const& sym)
{
if (!sym.get_metawriter_name().empty() || explicit_defaults_) {
@ -444,13 +448,11 @@ private:
if (!sym.get_metawriter_properties_overrides().empty() || explicit_defaults_) {
set_attr(node, "meta-output", sym.get_metawriter_properties_overrides().to_string());
}
std::string tr_str = sym.get_transform_string();
if (tr_str != "matrix(1, 0, 0, 1, 0, 0)" || explicit_defaults_ ) // FIXME !!
if (sym.get_transform())
{
std::string tr_str = sym.get_transform_string();
set_attr( node, "transform", tr_str );
}
}
ptree & rule_;

View file

@ -23,9 +23,26 @@
//mapnik
#include <mapnik/symbolizer.hpp>
#include <mapnik/map.hpp>
#include <mapnik/parse_transform.hpp>
namespace mapnik {
void evaluate_transform(agg::trans_affine& tr, Feature const& feature,
transform_list_ptr const& trans_expr)
{
#ifdef MAPNIK_LOG
MAPNIK_LOG_DEBUG(transform) << "transform: evaluate "
<< (trans_expr
? transform_processor_type::to_string(*trans_expr)
: std::string("null"));
#endif
if (trans_expr)
{
transform_processor_type::evaluate(tr, feature, *trans_expr);
}
}
// default ctor
symbolizer_base::symbolizer_base()
: properties_(),
@ -36,12 +53,6 @@ symbolizer_base::symbolizer_base()
clip_(true),
smooth_value_(0.0)
{
affine_transform_[0] = 1.0;
affine_transform_[1] = 0.0;
affine_transform_[2] = 0.0;
affine_transform_[3] = 1.0;
affine_transform_[4] = 0.0;
affine_transform_[5] = 0.0;
}
// copy ctor
@ -107,6 +118,13 @@ composite_mode_e symbolizer_base::comp_op() const
void symbolizer_base::set_transform(transform_type const& affine_transform)
{
affine_transform_ = affine_transform;
#ifdef MAPNIK_LOG
MAPNIK_LOG_DEBUG(load_map) << "map_parser: set_transform: "
<< (affine_transform_
? transform_processor_type::to_string(*affine_transform_)
: std::string("null"));
#endif
}
transform_type const& symbolizer_base::get_transform() const
@ -116,11 +134,10 @@ transform_type const& symbolizer_base::get_transform() const
std::string symbolizer_base::get_transform_string() const
{
std::stringstream ss;
ss << "matrix(" << affine_transform_[0] << ", " << affine_transform_[1] << ", "
<< affine_transform_[2] << ", " << affine_transform_[3] << ", "
<< affine_transform_[4] << ", " << affine_transform_[5] << ")";
return ss.str();
if (affine_transform_)
return transform_processor_type::to_string(*affine_transform_);
else
return std::string();
}
void symbolizer_base::set_clip(bool clip)
@ -149,12 +166,6 @@ symbolizer_with_image::symbolizer_with_image(path_expression_ptr file)
: image_filename_( file ),
image_opacity_(1.0f)
{
image_transform_[0] = 1.0;
image_transform_[1] = 0.0;
image_transform_[2] = 0.0;
image_transform_[3] = 1.0;
image_transform_[4] = 0.0;
image_transform_[5] = 0.0;
}
symbolizer_with_image::symbolizer_with_image( symbolizer_with_image const& rhs)
@ -187,6 +198,13 @@ float symbolizer_with_image::get_opacity() const
void symbolizer_with_image::set_image_transform(transform_type const& tr)
{
image_transform_ = tr;
#ifdef MAPNIK_LOG
MAPNIK_LOG_DEBUG(load_map) << "map_parser: set_image_transform: "
<< (image_transform_
? transform_processor_type::to_string(*image_transform_)
: std::string("null"));
#endif
}
transform_type const& symbolizer_with_image::get_image_transform() const
@ -196,11 +214,10 @@ transform_type const& symbolizer_with_image::get_image_transform() const
std::string symbolizer_with_image::get_image_transform_string() const
{
std::stringstream ss;
ss << "matrix(" << image_transform_[0] << ", " << image_transform_[1] << ", "
<< image_transform_[2] << ", " << image_transform_[3] << ", "
<< image_transform_[4] << ", " << image_transform_[5] << ")";
return ss.str();
if (image_transform_)
return transform_processor_type::to_string(*image_transform_);
else
return std::string();
}
} // end of namespace mapnik

View file

@ -350,8 +350,7 @@ template <typename FaceManagerT, typename DetectorT>
void shield_symbolizer_helper<FaceManagerT, DetectorT>::init_marker()
{
std::string filename = path_processor_type::evaluate(*sym_.get_filename(), this->feature_);
boost::array<double,6> const& m = sym_.get_image_transform();
image_transform_.load_from(&m[0]);
evaluate_transform(image_transform_, feature_, sym_.get_image_transform());
marker_.reset();
if (!filename.empty())
{

View file

@ -0,0 +1,144 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 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
*
*****************************************************************************/
// mapnik
#include <mapnik/expression_string.hpp>
#include <mapnik/transform_expression.hpp>
// boost
#include <boost/foreach.hpp>
// stl
#include <sstream>
namespace mapnik {
struct transform_node_to_expression_string
: public boost::static_visitor<void>
{
std::ostringstream& os_;
transform_node_to_expression_string(std::ostringstream& os)
: os_(os) {}
void operator() (identity_node const& node) const
{
boost::ignore_unused_variable_warning(node);
}
void operator() (matrix_node const& node)
{
os_ << "matrix("
<< to_expression_string(node.a_) << ", "
<< to_expression_string(node.b_) << ", "
<< to_expression_string(node.c_) << ", "
<< to_expression_string(node.d_) << ", "
<< to_expression_string(node.e_) << ", "
<< to_expression_string(node.f_) << ")";
}
void operator() (translate_node const& node)
{
if (is_null(node.ty_))
{
os_ << "translate("
<< to_expression_string(node.tx_) << ")";
}
else
{
os_ << "translate("
<< to_expression_string(node.tx_) << ", "
<< to_expression_string(node.ty_) << ")";
}
}
void operator() (scale_node const& node)
{
if (is_null(node.sy_))
{
os_ << "scale("
<< to_expression_string(node.sx_) << ")";
}
else
{
os_ << "scale("
<< to_expression_string(node.sx_) << ", "
<< to_expression_string(node.sy_) << ")";
}
}
void operator() (rotate_node const& node)
{
if (is_null(node.cy_) || is_null(node.cy_))
{
os_ << "rotate("
<< to_expression_string(node.angle_) << ")";
}
else
{
os_ << "rotate("
<< to_expression_string(node.angle_) << ", "
<< to_expression_string(node.cx_) << ", "
<< to_expression_string(node.cy_) << ")";
}
}
void operator() (skewX_node const& node)
{
os_ << "skewX("
<< to_expression_string(node.angle_) << ")";
}
void operator() (skewY_node const& node)
{
os_ << "skewY("
<< to_expression_string(node.angle_) << ")";
}
};
std::string to_expression_string(transform_node const& node)
{
std::ostringstream os; // FIXME set precision?
transform_node_to_expression_string to_string(os);
boost::apply_visitor(to_string, *node);
return os.str();
}
std::string to_expression_string(transform_list const& list)
{
std::ostringstream os; // FIXME set precision?
std::streamsize first = 1;
transform_node_to_expression_string to_string(os);
BOOST_FOREACH (transform_node const& node, list)
{
os.write(" ", first ? (first = 0) : 1);
boost::apply_visitor(to_string, *node);
}
return os.str();
}
} // namespace mapnik

View file

@ -172,7 +172,8 @@ xml_tree::xml_tree(std::string const& encoding)
tr_(encoding),
color_grammar(),
expr_grammar(tr_),
path_expr_grammar()
path_expr_grammar(),
transform_expr_grammar(expr_grammar)
{
node_.set_processed(true); //root node is always processed
}