1 /* === S Y N F I G ========================================================= */ 2 /*! \file transformation.h 3 ** \brief Affine Transformation 4 ** 5 ** $Id$ 6 ** 7 ** \legal 8 ** ......... ... 2013 Ivan Mahonin 9 ** 10 ** This package is free software; you can redistribute it and/or 11 ** modify it under the terms of the GNU General Public License as 12 ** published by the Free Software Foundation; either version 2 of 13 ** the License, or (at your option) any later version. 14 ** 15 ** This package is distributed in the hope that it will be useful, 16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 ** General Public License for more details. 19 ** \endlegal 20 */ 21 /* ========================================================================= */ 22 23 /* === S T A R T =========================================================== */ 24 25 #ifndef __SYNFIG_TRANSFORMATION_H 26 #define __SYNFIG_TRANSFORMATION_H 27 28 /* === H E A D E R S ======================================================= */ 29 30 #include "vector.h" 31 #include "matrix.h" 32 #include "rect.h" 33 34 /* === M A C R O S ========================================================= */ 35 36 /* === T Y P E D E F S ===================================================== */ 37 38 /* === C L A S S E S & S T R U C T S ======================================= */ 39 40 namespace synfig { 41 42 /*! \class Transformation 43 ** \todo writeme 44 */ 45 class Transformation 46 { 47 public: 48 Vector offset; 49 Angle angle; 50 Angle skew_angle; 51 Vector scale; 52 Transformation()53 Transformation(): 54 offset(0.0, 0.0), 55 angle(Angle::rad(0.0)), 56 skew_angle(Angle::rad(0.0)), 57 scale(1.0, 1.0) 58 { } 59 60 Transformation( 61 const Vector &offset, 62 const Angle &angle = Angle::rad(0.0), 63 const Angle &skew_angle = Angle::rad(0.0), 64 const Vector &scale = Vector(1.0, 1.0) 65 ): offset(offset)66 offset(offset), 67 angle(angle), 68 skew_angle(skew_angle), 69 scale(scale) 70 { } 71 is_valid()72 bool is_valid()const 73 { 74 return offset.is_valid() 75 && !std::isnan(Angle::rad(angle).get()) 76 && !std::isnan(Angle::rad(skew_angle).get()) 77 && scale.is_valid(); 78 } 79 80 bool 81 operator<(const Transformation &rhs)const 82 { 83 return offset<rhs.offset ? true : rhs.offset<offset ? false 84 : angle<rhs.angle ? true : rhs.angle<angle ? false 85 : skew_angle<rhs.skew_angle ? true : rhs.skew_angle<skew_angle ? false 86 : scale<rhs.scale; 87 } 88 89 bool 90 operator==(const Transformation &rhs)const 91 { 92 return offset==rhs.offset 93 && angle==rhs.angle 94 && skew_angle==rhs.skew_angle 95 && scale==rhs.scale; 96 } 97 98 bool 99 operator!=(const Transformation &rhs)const 100 { 101 return offset!=rhs.offset 102 || angle!=rhs.angle 103 || skew_angle!=rhs.skew_angle 104 || scale!=rhs.scale; 105 } 106 is_equal_to(const Transformation & rhs)107 bool is_equal_to(const Transformation& rhs)const 108 { 109 static const Angle::rad epsilon_angle(0.0000000000001); 110 Angle::rad a = angle - rhs.angle; 111 Angle::rad sa = skew_angle - rhs.skew_angle; 112 return offset.is_equal_to(rhs.offset) 113 && a < epsilon_angle && a > -epsilon_angle 114 && sa < epsilon_angle && sa > -epsilon_angle 115 && scale.is_equal_to(rhs.scale); 116 } 117 is_identity()118 bool is_identity()const 119 { 120 return is_equal_to(Transformation()); 121 } 122 get_matrix()123 Matrix get_matrix() const 124 { 125 if (is_identity()) return Matrix(); 126 Vector axis_x(scale[0], angle); 127 Vector axis_y(scale[1], angle + skew_angle + Angle::deg(90.0)); 128 return Matrix(axis_x, axis_y, offset); 129 } 130 set_matrix(const Matrix & matrix)131 void set_matrix(const Matrix &matrix) 132 { 133 if (matrix.is_identity()) *this = Transformation(); 134 Vector axis_x(matrix.get_axis_x()); 135 Vector axis_y(matrix.get_axis_y()); 136 angle = axis_x.angle(); 137 skew_angle = axis_y.angle() - angle - Angle::deg(90.0); 138 scale[0] = axis_x.mag(); 139 scale[1] = axis_y.mag(); 140 offset = matrix.get_offset(); 141 } 142 Transformation(const Matrix & matrix)143 explicit Transformation(const Matrix &matrix) 144 { set_matrix(matrix); } 145 get_inverted_matrix()146 Matrix get_inverted_matrix() const 147 { return get_matrix().invert(); } 148 get_back_transformation()149 Transformation get_back_transformation() const 150 { return Transformation(get_inverted_matrix()); } 151 transform_bounds(const Matrix & matrix,const Rect & bounds)152 static Rect transform_bounds(const Matrix &matrix, const Rect &bounds) 153 { 154 if (std::isnan(bounds.minx) || std::isinf(bounds.minx) 155 || std::isnan(bounds.maxx) || std::isinf(bounds.maxx) 156 || std::isnan(bounds.miny) || std::isinf(bounds.miny) 157 || std::isnan(bounds.maxy) || std::isinf(bounds.maxy)) 158 return Rect::infinite(); 159 160 Rect transformed_bounds( 161 matrix.get_transformed( 162 Vector(bounds.minx, bounds.miny) )); 163 transformed_bounds.expand( 164 matrix.get_transformed( 165 Vector(bounds.minx, bounds.maxy) )); 166 transformed_bounds.expand( 167 matrix.get_transformed( 168 Vector(bounds.maxx, bounds.miny) )); 169 transformed_bounds.expand( 170 matrix.get_transformed( 171 Vector(bounds.maxx, bounds.maxy) )); 172 return transformed_bounds; 173 } 174 175 Vector transform(const Vector &v, bool translate = true) const 176 { return get_matrix().get_transformed(v, translate); } transform(const Transformation & transformation)177 Transformation transform(const Transformation &transformation) const 178 { return Transformation( transformation.get_matrix()*get_matrix() ); } transform(const Matrix & matrix)179 Matrix transform(const Matrix &matrix) const 180 { return matrix*get_matrix(); } transform_bounds(const Rect & bounds)181 Rect transform_bounds(const Rect &bounds) const 182 { return transform_bounds(get_matrix(), bounds); } 183 184 Vector back_transform(const Vector &v, bool translate = true) const 185 { return get_inverted_matrix().get_transformed(v, translate); } back_transform(const Transformation & transformation)186 Transformation back_transform(const Transformation &transformation) const 187 { return Transformation( transformation.get_matrix()*get_inverted_matrix() ); } back_transform(const Matrix & matrix)188 Matrix back_transform(const Matrix &matrix) const 189 { return matrix*get_inverted_matrix(); } back_transform_bounds(const Rect & bounds)190 Rect back_transform_bounds(const Rect &bounds) const 191 { return transform_bounds(get_inverted_matrix(), bounds); } 192 identity()193 static const Transformation identity() { return Transformation(); } 194 }; 195 196 }; // END of namespace synfig 197 198 /* === E N D =============================================================== */ 199 200 #endif 201