// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP #define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP #include // Remove the ublas checking, otherwise the inverse might fail // (while nothing seems to be wrong) #define BOOST_UBLAS_TYPE_CHECK 0 #include #if defined(__clang__) // Avoid warning about unused UBLAS function: boost_numeric_ublas_abs #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" #endif #include #include #if defined(__clang__) #pragma clang diagnostic pop #endif #include #include #include #include #include #include namespace boost { namespace geometry { namespace strategy { namespace transform { /*! \brief Affine transformation strategy in Cartesian system. \details The strategy serves as a generic definition of affine transformation matrix and procedure of application it to given point. \see http://en.wikipedia.org/wiki/Affine_transformation and http://www.devmaster.net/wiki/Transformation_matrices \ingroup strategies \tparam Dimension1 number of dimensions to transform from \tparam Dimension2 number of dimensions to transform to */ template < typename CalculationType, std::size_t Dimension1, std::size_t Dimension2 > class ublas_transformer { }; template class ublas_transformer { protected : typedef CalculationType ct; typedef boost::numeric::ublas::matrix matrix_type; matrix_type m_matrix; public : inline ublas_transformer( ct const& m_0_0, ct const& m_0_1, ct const& m_0_2, ct const& m_1_0, ct const& m_1_1, ct const& m_1_2, ct const& m_2_0, ct const& m_2_1, ct const& m_2_2) : m_matrix(3, 3) { m_matrix(0,0) = m_0_0; m_matrix(0,1) = m_0_1; m_matrix(0,2) = m_0_2; m_matrix(1,0) = m_1_0; m_matrix(1,1) = m_1_1; m_matrix(1,2) = m_1_2; m_matrix(2,0) = m_2_0; m_matrix(2,1) = m_2_1; m_matrix(2,2) = m_2_2; } inline ublas_transformer(matrix_type const& matrix) : m_matrix(matrix) {} inline ublas_transformer() : m_matrix(3, 3) {} template inline bool apply(P1 const& p1, P2& p2) const { assert_dimension_greater_equal(); assert_dimension_greater_equal(); ct const& c1 = get<0>(p1); ct const& c2 = get<1>(p1); ct p2x = c1 * m_matrix(0,0) + c2 * m_matrix(0,1) + m_matrix(0,2); ct p2y = c1 * m_matrix(1,0) + c2 * m_matrix(1,1) + m_matrix(1,2); typedef typename geometry::coordinate_type::type ct2; set<0>(p2, boost::numeric_cast(p2x)); set<1>(p2, boost::numeric_cast(p2y)); return true; } matrix_type const& matrix() const { return m_matrix; } }; // It IS possible to go from 3 to 2 coordinates template class ublas_transformer : public ublas_transformer { typedef CalculationType ct; public : inline ublas_transformer( ct const& m_0_0, ct const& m_0_1, ct const& m_0_2, ct const& m_1_0, ct const& m_1_1, ct const& m_1_2, ct const& m_2_0, ct const& m_2_1, ct const& m_2_2) : ublas_transformer( m_0_0, m_0_1, m_0_2, m_1_0, m_1_1, m_1_2, m_2_0, m_2_1, m_2_2) {} inline ublas_transformer() : ublas_transformer() {} }; template class ublas_transformer { protected : typedef CalculationType ct; typedef boost::numeric::ublas::matrix matrix_type; matrix_type m_matrix; public : inline ublas_transformer( ct const& m_0_0, ct const& m_0_1, ct const& m_0_2, ct const& m_0_3, ct const& m_1_0, ct const& m_1_1, ct const& m_1_2, ct const& m_1_3, ct const& m_2_0, ct const& m_2_1, ct const& m_2_2, ct const& m_2_3, ct const& m_3_0, ct const& m_3_1, ct const& m_3_2, ct const& m_3_3 ) : m_matrix(4, 4) { m_matrix(0,0) = m_0_0; m_matrix(0,1) = m_0_1; m_matrix(0,2) = m_0_2; m_matrix(0,3) = m_0_3; m_matrix(1,0) = m_1_0; m_matrix(1,1) = m_1_1; m_matrix(1,2) = m_1_2; m_matrix(1,3) = m_1_3; m_matrix(2,0) = m_2_0; m_matrix(2,1) = m_2_1; m_matrix(2,2) = m_2_2; m_matrix(2,3) = m_2_3; m_matrix(3,0) = m_3_0; m_matrix(3,1) = m_3_1; m_matrix(3,2) = m_3_2; m_matrix(3,3) = m_3_3; } inline ublas_transformer() : m_matrix(4, 4) {} template inline bool apply(P1 const& p1, P2& p2) const { ct const& c1 = get<0>(p1); ct const& c2 = get<1>(p1); ct const& c3 = get<2>(p1); typedef typename geometry::coordinate_type::type ct2; set<0>(p2, boost::numeric_cast( c1 * m_matrix(0,0) + c2 * m_matrix(0,1) + c3 * m_matrix(0,2) + m_matrix(0,3))); set<1>(p2, boost::numeric_cast( c1 * m_matrix(1,0) + c2 * m_matrix(1,1) + c3 * m_matrix(1,2) + m_matrix(1,3))); set<2>(p2, boost::numeric_cast( c1 * m_matrix(2,0) + c2 * m_matrix(2,1) + c3 * m_matrix(2,2) + m_matrix(2,3))); return true; } matrix_type const& matrix() const { return m_matrix; } }; /*! \brief Strategy of translate transformation in Cartesian system. \details Translate moves a geometry a fixed distance in 2 or 3 dimensions. \see http://en.wikipedia.org/wiki/Translation_%28geometry%29 \ingroup strategies \tparam Dimension1 number of dimensions to transform from \tparam Dimension2 number of dimensions to transform to */ template < typename CalculationType, std::size_t Dimension1, std::size_t Dimension2 > class translate_transformer { }; template class translate_transformer : public ublas_transformer { public : // To have translate transformers compatible for 2/3 dimensions, the // constructor takes an optional third argument doing nothing. inline translate_transformer(CalculationType const& translate_x, CalculationType const& translate_y, CalculationType const& = 0) : ublas_transformer( 1, 0, translate_x, 0, 1, translate_y, 0, 0, 1) {} }; template class translate_transformer : public ublas_transformer { public : inline translate_transformer(CalculationType const& translate_x, CalculationType const& translate_y, CalculationType const& translate_z) : ublas_transformer( 1, 0, 0, translate_x, 0, 1, 0, translate_y, 0, 0, 1, translate_z, 0, 0, 0, 1) {} }; /*! \brief Strategy of scale transformation in Cartesian system. \details Scale scales a geometry up or down in all its dimensions. \see http://en.wikipedia.org/wiki/Scaling_%28geometry%29 \ingroup strategies \tparam Dimension1 number of dimensions to transform from \tparam Dimension2 number of dimensions to transform to */ template < typename CalculationType, std::size_t Dimension1, std::size_t Dimension2 > class scale_transformer { }; template class scale_transformer : public ublas_transformer { public : inline scale_transformer(CalculationType const& scale_x, CalculationType const& scale_y, CalculationType const& = 0) : ublas_transformer( scale_x, 0, 0, 0, scale_y, 0, 0, 0, 1) {} inline scale_transformer(CalculationType const& scale) : ublas_transformer( scale, 0, 0, 0, scale, 0, 0, 0, 1) {} }; template class scale_transformer : public ublas_transformer { public : inline scale_transformer(CalculationType const& scale_x, CalculationType const& scale_y, CalculationType const& scale_z) : ublas_transformer( scale_x, 0, 0, 0, 0, scale_y, 0, 0, 0, 0, scale_z, 0, 0, 0, 0, 1) {} inline scale_transformer(CalculationType const& scale) : ublas_transformer( scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, 1) {} }; #ifndef DOXYGEN_NO_DETAIL namespace detail { template struct as_radian {}; template <> struct as_radian { template static inline T get(T const& value) { return value; } }; template <> struct as_radian { template static inline T get(T const& value) { return value * math::d2r; } }; template < typename CalculationType, std::size_t Dimension1, std::size_t Dimension2 > class rad_rotate_transformer : public ublas_transformer { public : inline rad_rotate_transformer(CalculationType const& angle) : ublas_transformer( cos(angle), sin(angle), 0, -sin(angle), cos(angle), 0, 0, 0, 1) {} }; } // namespace detail #endif // DOXYGEN_NO_DETAIL /*! \brief Strategy for rotate transformation in Cartesian coordinate system. \details Rotate rotates a geometry of specified angle about a fixed point (e.g. origin). \see http://en.wikipedia.org/wiki/Rotation_%28mathematics%29 \ingroup strategies \tparam DegreeOrRadian degree/or/radian, type of rotation angle specification \note A single angle is needed to specify a rotation in 2D. Not yet in 3D, the 3D version requires special things to allow for rotation around X, Y, Z or arbitrary axis. \todo The 3D version will not compile. */ template < typename DegreeOrRadian, typename CalculationType, std::size_t Dimension1, std::size_t Dimension2 > class rotate_transformer : public detail::rad_rotate_transformer { public : inline rotate_transformer(CalculationType const& angle) : detail::rad_rotate_transformer < CalculationType, Dimension1, Dimension2 >(detail::as_radian::get(angle)) {} }; }} // namespace strategy::transform }} // namespace boost::geometry #endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP