// // Copyright 2005-2007 Adobe Systems Incorporated // // Distributed under 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_GIL_EXTENSION_NUMERIC_AFFINE_HPP #define BOOST_GIL_EXTENSION_NUMERIC_AFFINE_HPP #include namespace boost { namespace gil { //////////////////////////////////////////////////////////////////////////////////////// /// /// Simple matrix to do 2D affine transformations. It is actually 3x3 but the last column is [0 0 1] /// //////////////////////////////////////////////////////////////////////////////////////// template class matrix3x2 { public: matrix3x2() : a(1), b(0), c(0), d(1), e(0), f(0) {} matrix3x2(T A, T B, T C, T D, T E, T F) : a(A),b(B),c(C),d(D),e(E),f(F) {} matrix3x2(const matrix3x2& mat) : a(mat.a), b(mat.b), c(mat.c), d(mat.d), e(mat.e), f(mat.f) {} matrix3x2& operator=(const matrix3x2& m) { a=m.a; b=m.b; c=m.c; d=m.d; e=m.e; f=m.f; return *this; } matrix3x2& operator*=(const matrix3x2& m) { (*this) = (*this)*m; return *this; } static matrix3x2 get_rotate(T rads) { T c=std::cos(rads); T s=std::sin(rads); return matrix3x2(c,s,-s,c,0,0); } static matrix3x2 get_translate(point const& t) { return matrix3x2(1, 0, 0, 1, t.x, t.y); } static matrix3x2 get_translate(T x, T y) { return matrix3x2(1 ,0,0,1 ,x, y ); } static matrix3x2 get_scale(point const& s) { return matrix3x2(s.x, 0, 0, s.y, 0, 0); } static matrix3x2 get_scale(T x, T y) { return matrix3x2(x, 0,0,y, 0 ,0 ); } static matrix3x2 get_scale(T s) { return matrix3x2(s ,0,0,s ,0 ,0 ); } T a,b,c,d,e,f; }; template BOOST_FORCEINLINE matrix3x2 operator*(const matrix3x2& m1, const matrix3x2& m2) { return matrix3x2( m1.a * m2.a + m1.b * m2.c, m1.a * m2.b + m1.b * m2.d, m1.c * m2.a + m1.d * m2.c, m1.c * m2.b + m1.d * m2.d, m1.e * m2.a + m1.f * m2.c + m2.e, m1.e * m2.b + m1.f * m2.d + m2.f ); } template BOOST_FORCEINLINE point operator*(point const& p, matrix3x2 const& m) { return { m.a*p.x + m.c*p.y + m.e, m.b*p.x + m.d*p.y + m.f }; } //////////////////////////////////////////////////////////////////////////////////////// /// Define affine mapping that transforms the source coordinates by the affine transformation //////////////////////////////////////////////////////////////////////////////////////// /* template concept MappingFunctionConcept { typename mapping_traits::result_type; where PointNDConcept; template { where PointNDConcept } result_type transform(MapFn&, const Domain& src); }; */ template struct mapping_traits; template struct mapping_traits> { using result_type = point; }; template BOOST_FORCEINLINE point transform(matrix3x2 const& mat, point const& src) { return src * mat; } /// Returns the inverse of the given affine transformation matrix /// /// \warning Floating point arithmetic, use Boost.Rational if precision maters template boost::gil::matrix3x2 inverse(boost::gil::matrix3x2 m) { T const determinant = m.a * m.d - m.b * m.c; boost::gil::matrix3x2 res; res.a = m.d / determinant; res.b = -m.b / determinant; res.c = -m.c / determinant; res.d = m.a / determinant; res.e = (m.c * m.f - m.d * m.e) / determinant; res.f = (m.b * m.e - m.a * m.f) / determinant; return res; } /// \fn gil::matrix3x2 center_rotate /// \tparam T Data type for source image dimensions /// \tparam F Data type for angle through which image is to be rotated /// @param dims dimensions of source image /// @param rads angle through which image is to be rotated /// @return A transformation matrix for rotating the source image about its center /// \brief rotates an image from its center point /// using consecutive affine transformations. template boost::gil::matrix3x2 center_rotate(boost::gil::point dims,F rads) { const F PI = F(3.141592653589793238); const F c_theta = std::abs(std::cos(rads)); const F s_theta = std::abs(std::sin(rads)); // Bound checks for angle rads while(rads + PI < 0) { rads = rads + PI; } while(rads > PI) { rads = rads - PI; } // Basic Rotation Matrix boost::gil::matrix3x2 rotate = boost::gil::matrix3x2::get_rotate(rads); // Find distance for translating the image into view boost::gil::matrix3x2 translation(0,0,0,0,0,0); if(rads > 0) { translation.b = s_theta; } else { translation.c = s_theta; } if(std::abs(rads) > PI/2) { translation.a = c_theta; translation.d = c_theta; } // To bring the complete image into view boost::gil::matrix3x2 translate = boost::gil::matrix3x2::get_translate(-1 * dims * translation); // To fit inside the source dimensions boost::gil::matrix3x2 scale = boost::gil::matrix3x2::get_scale( s_theta * dims.y / dims.x + c_theta , s_theta * dims.x / dims.y + c_theta ); return scale * translate * rotate; } }} // namespace boost::gil #endif