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