1 // This file is part of VSTGUI. It is subject to the license terms
2 // in the LICENSE file found in the top-level directory of this
3 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
4 
5 #ifndef __cgraphicstransform__
6 #define __cgraphicstransform__
7 
8 #include "cpoint.h"
9 #include "crect.h"
10 
11 #ifndef M_PI
12 #define M_PI        3.14159265358979323846264338327950288
13 #endif
14 
15 namespace VSTGUI {
16 
radians(double degrees)17 static inline double radians (double degrees) { return degrees * M_PI / 180; }
18 
19 //-----------------------------------------------------------------------------
20 /// @brief Graphics Transform Matrix
21 /// @ingroup new_in_4_0
22 //-----------------------------------------------------------------------------
23 struct CGraphicsTransform
24 {
25 	double m11 {1.};
26 	double m12 {0.};
27 	double m21 {0.};
28 	double m22 {1.};
29 	double dx {0.};
30 	double dy {0.};
31 
32 	CGraphicsTransform () = default;
CGraphicsTransformCGraphicsTransform33 	CGraphicsTransform (double _m11, double _m12, double _m21, double _m22, double _dx, double _dy)
34 	: m11 (_m11), m12 (_m12), m21 (_m21), m22 (_m22), dx (_dx), dy (_dy)
35 	{}
36 
translateCGraphicsTransform37 	CGraphicsTransform& translate (double x, double y)
38 	{
39 		*this = CGraphicsTransform (1, 0, 0, 1, x, y) * this;
40 		return *this;
41 	}
42 
translateCGraphicsTransform43 	CGraphicsTransform& translate (const CPoint& p)
44 	{
45 		return translate (p.x, p.y);
46 	}
47 
scaleCGraphicsTransform48 	CGraphicsTransform& scale (double x, double y)
49 	{
50 		*this = CGraphicsTransform (x, 0., 0., y, 0., 0.) * this;
51 		return *this;
52 	}
53 
scaleCGraphicsTransform54 	CGraphicsTransform& scale (const CPoint& p)
55 	{
56 		return scale (p.x, p.y);
57 	}
58 
rotateCGraphicsTransform59 	CGraphicsTransform& rotate (double angle)
60 	{
61 		angle = radians (angle);
62 		*this = CGraphicsTransform (cos (angle), -sin (angle), sin (angle), cos (angle), 0, 0) * this;
63 		return *this;
64 	}
65 
rotateCGraphicsTransform66 	CGraphicsTransform& rotate (double angle, const CPoint& center)
67 	{
68 		return translate (-center.x, -center.y).rotate (angle).translate (center.x, center.y);
69 	}
70 
skewXCGraphicsTransform71 	CGraphicsTransform& skewX (double angle)
72 	{
73 		*this = CGraphicsTransform (1, std::tan (radians (angle)), 0, 1, 0, 0) * *this;
74 		return *this;
75 	}
76 
skewYCGraphicsTransform77 	CGraphicsTransform& skewY (double angle)
78 	{
79 		*this = CGraphicsTransform (1, 0, std::tan (radians (angle)), 1, 0, 0) * *this;
80 		return *this;
81 	}
82 
isInvariantCGraphicsTransform83 	bool isInvariant () const
84 	{
85 		return *this == CGraphicsTransform ();
86 	}
87 
transformCGraphicsTransform88 	void transform (CCoord& x, CCoord& y) const
89 	{
90 		CCoord x2 = m11*x + m12*y + dx;
91 		CCoord y2 = m21*x + m22*y + dy;
92 		x = x2;
93 		y = y2;
94 	}
95 
transformCGraphicsTransform96 	void transform (CCoord& left, CCoord& right, CCoord& top, CCoord& bottom) const
97 	{
98 		transform (left, top);
99 		transform (right, bottom);
100 	}
101 
transformCGraphicsTransform102 	CPoint& transform (CPoint& p) const
103 	{
104 		transform (p.x, p.y);
105 		return p;
106 	}
107 
transformCGraphicsTransform108 	CRect& transform (CRect& r) const
109 	{
110 		transform (r.left, r.right, r.top, r.bottom);
111 		return r;
112 	}
113 
inverseCGraphicsTransform114 	CGraphicsTransform inverse () const
115 	{
116 		CGraphicsTransform result;
117 		const double denominator = m11 * m22 - m12 * m21;
118 		if (denominator != 0)
119 		{
120 			result.m11 = m22 / denominator;
121 			result.m12 = -m12 / denominator;
122 			result.m21 = -m21 / denominator;
123 			result.m22 = m11 / denominator;
124 			result.dx = ((m12 * dy) - (m22 * dx)) / denominator;
125 			result.dy = ((m21 * dx) - (m11 * dy)) / denominator;
126 		}
127 		return result;
128 	}
129 
130 	CGraphicsTransform operator* (const CGraphicsTransform& t) const
131 	{
132 		CGraphicsTransform result;
133 		result.m11 = (m11 * t.m11) + (m12 * t.m21);
134 		result.m21 = (m21 * t.m11) + (m22 * t.m21);
135 		result.dx = (m11 * t.dx) + (m12 * t.dy) + dx;
136 		result.m12 = (m11 * t.m12) + (m12 * t.m22);
137 		result.m22 = (m21 * t.m12) + (m22 * t.m22);
138 		result.dy = (m21 * t.dx) + (m22 * t.dy) + dy;
139 		return result;
140 	}
141 
142 	CGraphicsTransform operator* (const CGraphicsTransform* t) const { return *this * *t; }
143 
144 	bool operator== (const CGraphicsTransform& t) const
145 	{
146 		return m11 == t.m11 && m12 == t.m12 && m21 == t.m21 && m22 == t.m22 && dx == t.dx && dy == t.dy;
147 	}
148 
149 	bool operator!= (const CGraphicsTransform& t) const
150 	{
151 		return m11 != t.m11 || m12 != t.m12 || m21 != t.m21 || m22 != t.m22 || dx != t.dx || dy != t.dy;
152 	}
153 };
154 
155 
156 }
157 
158 #endif // __cgraphicstransform__
159