245 lines
6.2 KiB
C++
245 lines
6.2 KiB
C++
/*****************************************************************************
|
|
*
|
|
* This file is part of Mapnik (c++ mapping toolkit)
|
|
*
|
|
* Copyright (C) 2015 Artem Pavlenko
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#ifndef MAPNIK_TRANSFORM_EXPRESSION_HPP
|
|
#define MAPNIK_TRANSFORM_EXPRESSION_HPP
|
|
|
|
// mapnik
|
|
#include <mapnik/config.hpp>
|
|
#include <mapnik/attribute.hpp>
|
|
#include <mapnik/value/types.hpp>
|
|
#include <mapnik/expression_node_types.hpp>
|
|
#include <mapnik/expression_node.hpp>
|
|
#include <mapnik/util/variant.hpp>
|
|
|
|
#pragma GCC diagnostic push
|
|
#include <mapnik/warning_ignore.hpp>
|
|
#include <boost/optional.hpp>
|
|
#include <boost/fusion/include/at.hpp>
|
|
#include <boost/fusion/include/vector.hpp>
|
|
#pragma GCC diagnostic pop
|
|
|
|
// stl
|
|
#include <vector>
|
|
#include <memory>
|
|
|
|
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_;
|
|
|
|
matrix_node() = default;
|
|
|
|
template <typename T>
|
|
explicit matrix_node(T 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() = default;
|
|
|
|
translate_node(expr_node const& tx,
|
|
boost::optional<expr_node> const& ty)
|
|
: tx_(tx)
|
|
, ty_(ty ? expr_node(*ty) : value_null()) {}
|
|
};
|
|
|
|
struct scale_node
|
|
{
|
|
expr_node sx_;
|
|
expr_node sy_;
|
|
|
|
scale_node() = default;
|
|
|
|
scale_node(expr_node const& sx,
|
|
boost::optional<expr_node> const& sy)
|
|
: sx_(sx)
|
|
, sy_(sy ? expr_node(*sy) : value_null()) {}
|
|
};
|
|
|
|
struct rotate_node
|
|
{
|
|
using coords_type = boost::fusion::vector2<expr_node, expr_node>;
|
|
|
|
expr_node angle_;
|
|
expr_node cx_;
|
|
expr_node cy_;
|
|
|
|
rotate_node() = default;
|
|
|
|
explicit rotate_node(expr_node const& angle)
|
|
: angle_(angle) {}
|
|
|
|
rotate_node(expr_node const& angle,
|
|
expr_node const& cx, expr_node const& cy)
|
|
: angle_(angle), cx_(cx), cy_(cy) {}
|
|
|
|
rotate_node(expr_node const& angle,
|
|
boost::optional<expr_node> const& cx,
|
|
boost::optional<expr_node> const& cy)
|
|
: angle_(angle)
|
|
, cx_(cx ? expr_node(*cx) : value_null())
|
|
, cy_(cy ? expr_node(*cy) : value_null()) {}
|
|
|
|
rotate_node(expr_node const& angle,
|
|
boost::optional<coords_type> const& center)
|
|
: angle_(angle)
|
|
{
|
|
if (center)
|
|
{
|
|
cx_ = boost::fusion::at_c<0>(*center);
|
|
cy_ = boost::fusion::at_c<1>(*center);
|
|
}
|
|
}
|
|
};
|
|
|
|
struct skewX_node
|
|
{
|
|
expr_node angle_;
|
|
skewX_node() = default;
|
|
skewX_node(expr_node const& angle)
|
|
: angle_(angle) {}
|
|
};
|
|
|
|
struct skewY_node
|
|
{
|
|
expr_node angle_;
|
|
skewY_node() = default;
|
|
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 of 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...
|
|
|
|
using transform_variant = mapnik::util::variant< identity_node,
|
|
matrix_node,
|
|
translate_node,
|
|
scale_node,
|
|
rotate_node,
|
|
skewX_node,
|
|
skewY_node >;
|
|
|
|
// ... 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 {
|
|
|
|
struct is_null_transform_node
|
|
{
|
|
bool operator() (value const& val) const
|
|
{
|
|
return val.is_null();
|
|
}
|
|
|
|
bool operator() (value_null const&) const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator() (T const&) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool operator() (detail::transform_variant const& var) const
|
|
{
|
|
return util::apply_visitor(*this, var);
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
template <typename T>
|
|
bool is_null_node (T const& node)
|
|
{
|
|
return util::apply_visitor(is_null_transform_node(), node);
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
using transform_node = detail::transform_node;
|
|
using transform_list = std::vector<transform_node>;
|
|
using transform_list_ptr = std::shared_ptr<transform_list>;
|
|
|
|
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
|