1 /**
2  * @file gdiplusmatrix.h
3  * Copyright 2012, 2013 MinGW.org project
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 /* Created by Markus Koenig <markus@stber-koenig.de> */
25 #ifndef __GDIPLUS_MATRIX_H
26 #define __GDIPLUS_MATRIX_H
27 #pragma GCC system_header
28 #include <_mingw.h>
29 
30 /*
31  * GDI+ Matrix class
32  */
33 
34 #ifndef __cplusplus
35 #error "A C++ compiler is required to include gdiplusmatrix.h."
36 #endif
37 
38 #define GDIP_MATRIX_PI \
39 	3.1415926535897932384626433832795028841971693993751058209749445923078164
40 
41 class Matrix: public GdiplusBase
42 {
43 	friend class Graphics;
44 	friend class GraphicsPath;
45 	friend class LinearGradientBrush;
46 	friend class PathGradientBrush;
47 	friend class Pen;
48 	friend class Region;
49 	friend class TextureBrush;
50 
51 public:
Matrix()52 	Matrix(): nativeMatrix(NULL), lastStatus(Ok)
53 	{
54 		lastStatus = DllExports::GdipCreateMatrix(&nativeMatrix);
55 	}
Matrix(REAL m11,REAL m12,REAL m21,REAL m22,REAL dx,REAL dy)56 	Matrix(REAL m11, REAL m12, REAL m21, REAL m22, REAL dx, REAL dy):
57 			nativeMatrix(NULL), lastStatus(Ok)
58 	{
59 		lastStatus = DllExports::GdipCreateMatrix2(
60 				m11, m12, m21, m22, dx, dy,
61 				&nativeMatrix);
62 	}
Matrix(const RectF & rect,const PointF * dstplg)63 	Matrix(const RectF& rect, const PointF *dstplg):
64 			nativeMatrix(NULL), lastStatus(Ok)
65 	{
66 		lastStatus = DllExports::GdipCreateMatrix3(
67 				&rect, dstplg, &nativeMatrix);
68 	}
Matrix(const Rect & rect,const Point * dstplg)69 	Matrix(const Rect& rect, const Point *dstplg):
70 			nativeMatrix(NULL), lastStatus(Ok)
71 	{
72 		lastStatus = DllExports::GdipCreateMatrix3I(
73 				&rect, dstplg, &nativeMatrix);
74 	}
~Matrix()75 	~Matrix()
76 	{
77 		DllExports::GdipDeleteMatrix(nativeMatrix);
78 	}
Clone()79 	Matrix* Clone() const
80 	{
81 		GpMatrix *cloneMatrix = NULL;
82 		Status status = updateStatus(DllExports::GdipCloneMatrix(
83 				nativeMatrix, &cloneMatrix));
84 		if (status == Ok) {
85 			Matrix *result = new Matrix(cloneMatrix, lastStatus);
86 			if (!result) {
87 				DllExports::GdipDeleteMatrix(cloneMatrix);
88 				lastStatus = OutOfMemory;
89 			}
90 			return result;
91 		} else {
92 			return NULL;
93 		}
94 	}
95 
Equals(const Matrix * matrix)96 	BOOL Equals(const Matrix *matrix) const
97 	{
98 		BOOL result;
99 		updateStatus(DllExports::GdipIsMatrixEqual(
100 				nativeMatrix,
101 				matrix ? matrix->nativeMatrix : NULL, &result));
102 		return result;
103 	}
GetElements(REAL * m)104 	Status GetElements(REAL *m) const
105 	{
106 		return updateStatus(DllExports::GdipGetMatrixElements(
107 				nativeMatrix, m));
108 	}
GetLastStatus()109 	Status GetLastStatus() const
110 	{
111 		Status result = lastStatus;
112 		lastStatus = Ok;
113 		return result;
114 	}
Invert()115 	Status Invert()
116 	{
117 		return updateStatus(DllExports::GdipInvertMatrix(nativeMatrix));
118 	}
IsIdentity()119 	BOOL IsIdentity() const
120 	{
121 		BOOL result;
122 		updateStatus(DllExports::GdipIsMatrixIdentity(
123 				nativeMatrix, &result));
124 		return result;
125 	}
IsInvertible()126 	BOOL IsInvertible() const
127 	{
128 		BOOL result;
129 		updateStatus(DllExports::GdipIsMatrixInvertible(
130 				nativeMatrix, &result));
131 		return result;
132 	}
133 	Status Multiply(const Matrix *matrix,
134 			MatrixOrder order = MatrixOrderPrepend)
135 	{
136 		return updateStatus(DllExports::GdipMultiplyMatrix(
137 				nativeMatrix,
138 				matrix ? matrix->nativeMatrix : NULL, order));
139 	}
OffsetX()140 	REAL OffsetX() const
141 	{
142 		REAL m[6];
143 		updateStatus(DllExports::GdipGetMatrixElements(nativeMatrix, m));
144 		return m[4];
145 	}
OffsetY()146 	REAL OffsetY() const
147 	{
148 		REAL m[6];
149 		updateStatus(DllExports::GdipGetMatrixElements(nativeMatrix, m));
150 		return m[5];
151 	}
Reset()152 	Status Reset()
153 	{
154 		return updateStatus(DllExports::GdipSetMatrixElements(
155 				nativeMatrix,
156 				1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f));
157 	}
158 	Status Rotate(REAL angle, MatrixOrder order = MatrixOrderPrepend)
159 	{
160 		return updateStatus(DllExports::GdipRotateMatrix(
161 				nativeMatrix, angle, order));
162 	}
163 	Status RotateAt(REAL angle, const PointF& center,
164 			MatrixOrder order = MatrixOrderPrepend)
165 	{
166 		REAL angleRadian = angle * GDIP_MATRIX_PI / 180.0f;
167 		REAL cosAngle = ::cos(angleRadian);
168 		REAL sinAngle = ::sin(angleRadian);
169 		REAL x = center.X;
170 		REAL y = center.Y;
171 
172 		Matrix matrix2(cosAngle, sinAngle, -sinAngle, cosAngle,
173 				x * (1.0f-cosAngle) + y * sinAngle,
174 				-x * sinAngle + y * (1.0f-cosAngle));
175 		Status status = matrix2.GetLastStatus();
176 		if (status == Ok) {
177 			return Multiply(&matrix2, order);
178 		} else {
179 			return lastStatus = status;
180 		}
181 	}
182 	Status Scale(REAL scaleX, REAL scaleY,
183 			MatrixOrder order = MatrixOrderPrepend)
184 	{
185 		return updateStatus(DllExports::GdipScaleMatrix(
186 				nativeMatrix, scaleX, scaleY, order));
187 	}
SetElements(REAL m11,REAL m12,REAL m21,REAL m22,REAL dx,REAL dy)188 	Status SetElements(REAL m11, REAL m12, REAL m21, REAL m22,
189 			REAL dx, REAL dy)
190 	{
191 		return updateStatus(DllExports::GdipSetMatrixElements(
192 				nativeMatrix, m11, m12, m21, m22, dx, dy));
193 	}
194 	Status Shear(REAL shearX, REAL shearY,
195 			MatrixOrder order = MatrixOrderPrepend)
196 	{
197 		return updateStatus(DllExports::GdipShearMatrix(
198 				nativeMatrix, shearX, shearY, order));
199 	}
200 	Status TransformPoints(PointF *pts, INT count = 1) const
201 	{
202 		return updateStatus(DllExports::GdipTransformMatrixPoints(
203 				nativeMatrix, pts, count));
204 	}
205 	Status TransformPoints(Point *pts, INT count = 1) const
206 	{
207 		return updateStatus(DllExports::GdipTransformMatrixPointsI(
208 				nativeMatrix, pts, count));
209 	}
210 	Status TransformVectors(PointF *pts, INT count = 1) const
211 	{
212 		return updateStatus(DllExports::GdipVectorTransformMatrixPoints(
213 				nativeMatrix, pts, count));
214 	}
215 	Status TransformVectors(Point *pts, INT count = 1) const
216 	{
217 		return updateStatus(DllExports::GdipVectorTransformMatrixPointsI(
218 				nativeMatrix, pts, count));
219 	}
220 	Status Translate(REAL offsetX, REAL offsetY,
221 			MatrixOrder order = MatrixOrderPrepend)
222 	{
223 		return updateStatus(DllExports::GdipTranslateMatrix(
224 				nativeMatrix, offsetX, offsetY, order));
225 	}
226 
227 private:
Matrix(GpMatrix * matrix,Status status)228 	Matrix(GpMatrix *matrix, Status status):
229 		nativeMatrix(matrix), lastStatus(status) {}
230 	Matrix(const Matrix&);
231 	Matrix& operator=(const Matrix&);
232 
updateStatus(Status newStatus)233 	Status updateStatus(Status newStatus) const
234 	{
235 		if (newStatus != Ok) lastStatus = newStatus;
236 		return newStatus;
237 	}
238 
239 	GpMatrix *nativeMatrix;
240 	mutable Status lastStatus;
241 };
242 
243 #undef GDIP_MATRIX_PI
244 
245 #endif /* __GDIPLUS_MATRIX_H */
246