1/*
2 * gdiplusmatrix.h
3 *
4 * GDI+ Matrix class
5 *
6 * This file is part of the w32api package.
7 *
8 * Contributors:
9 *   Created by Markus Koenig <markus@stber-koenig.de>
10 *
11 * THIS SOFTWARE IS NOT COPYRIGHTED
12 *
13 * This source code is offered for use in the public domain. You may
14 * use, modify or distribute it freely.
15 *
16 * This code is distributed in the hope that it will be useful but
17 * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
18 * DISCLAIMED. This includes but is not limited to warranties of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 */
22
23#ifndef __GDIPLUS_MATRIX_H
24#define __GDIPLUS_MATRIX_H
25#if __GNUC__ >=3
26#pragma GCC system_header
27#endif
28
29#ifndef __cplusplus
30#error "A C++ compiler is required to include gdiplusmatrix.h."
31#endif
32
33#define GDIP_MATRIX_PI \
34	3.1415926535897932384626433832795028841971693993751058209749445923078164
35
36class Matrix: public GdiplusBase
37{
38	friend class Graphics;
39	friend class GraphicsPath;
40	friend class LinearGradientBrush;
41	friend class PathGradientBrush;
42	friend class Pen;
43	friend class Region;
44	friend class TextureBrush;
45
46public:
47	Matrix(): nativeMatrix(NULL), lastStatus(Ok)
48	{
49		lastStatus = DllExports::GdipCreateMatrix(&nativeMatrix);
50	}
51	Matrix(REAL m11, REAL m12, REAL m21, REAL m22, REAL dx, REAL dy):
52			nativeMatrix(NULL), lastStatus(Ok)
53	{
54		lastStatus = DllExports::GdipCreateMatrix2(
55				m11, m12, m21, m22, dx, dy,
56				&nativeMatrix);
57	}
58	Matrix(const RectF& rect, const PointF *dstplg):
59			nativeMatrix(NULL), lastStatus(Ok)
60	{
61		lastStatus = DllExports::GdipCreateMatrix3(
62				&rect, dstplg, &nativeMatrix);
63	}
64	Matrix(const Rect& rect, const Point *dstplg):
65			nativeMatrix(NULL), lastStatus(Ok)
66	{
67		lastStatus = DllExports::GdipCreateMatrix3I(
68				&rect, dstplg, &nativeMatrix);
69	}
70	~Matrix()
71	{
72		DllExports::GdipDeleteMatrix(nativeMatrix);
73	}
74	Matrix* Clone() const
75	{
76		GpMatrix *cloneMatrix = NULL;
77		Status status = updateStatus(DllExports::GdipCloneMatrix(
78				nativeMatrix, &cloneMatrix));
79		if (status == Ok) {
80			Matrix *result = new Matrix(cloneMatrix, lastStatus);
81			if (!result) {
82				DllExports::GdipDeleteMatrix(cloneMatrix);
83				lastStatus = OutOfMemory;
84			}
85			return result;
86		} else {
87			return NULL;
88		}
89	}
90
91	BOOL Equals(const Matrix *matrix) const
92	{
93		BOOL result;
94		updateStatus(DllExports::GdipIsMatrixEqual(
95				nativeMatrix,
96				matrix ? matrix->nativeMatrix : NULL, &result));
97		return result;
98	}
99	Status GetElements(REAL *m) const
100	{
101		return updateStatus(DllExports::GdipGetMatrixElements(
102				nativeMatrix, m));
103	}
104	Status GetLastStatus() const
105	{
106		Status result = lastStatus;
107		lastStatus = Ok;
108		return result;
109	}
110	Status Invert()
111	{
112		return updateStatus(DllExports::GdipInvertMatrix(nativeMatrix));
113	}
114	BOOL IsIdentity() const
115	{
116		BOOL result;
117		updateStatus(DllExports::GdipIsMatrixIdentity(
118				nativeMatrix, &result));
119		return result;
120	}
121	BOOL IsInvertible() const
122	{
123		BOOL result;
124		updateStatus(DllExports::GdipIsMatrixInvertible(
125				nativeMatrix, &result));
126		return result;
127	}
128	Status Multiply(const Matrix *matrix,
129			MatrixOrder order = MatrixOrderPrepend)
130	{
131		return updateStatus(DllExports::GdipMultiplyMatrix(
132				nativeMatrix,
133				matrix ? matrix->nativeMatrix : NULL, order));
134	}
135	REAL OffsetX() const
136	{
137		REAL m[6];
138		updateStatus(DllExports::GdipGetMatrixElements(nativeMatrix, m));
139		return m[4];
140	}
141	REAL OffsetY() const
142	{
143		REAL m[6];
144		updateStatus(DllExports::GdipGetMatrixElements(nativeMatrix, m));
145		return m[5];
146	}
147	Status Reset()
148	{
149		return updateStatus(DllExports::GdipSetMatrixElements(
150				nativeMatrix,
151				1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f));
152	}
153	Status Rotate(REAL angle, MatrixOrder order = MatrixOrderPrepend)
154	{
155		return updateStatus(DllExports::GdipRotateMatrix(
156				nativeMatrix, angle, order));
157	}
158	Status RotateAt(REAL angle, const PointF& center,
159			MatrixOrder order = MatrixOrderPrepend)
160	{
161		REAL angleRadian = angle * GDIP_MATRIX_PI / 180.0f;
162		REAL cosAngle = ::cos(angleRadian);
163		REAL sinAngle = ::sin(angleRadian);
164		REAL x = center.X;
165		REAL y = center.Y;
166
167		Matrix matrix2(cosAngle, sinAngle, -sinAngle, cosAngle,
168				x * (1.0f-cosAngle) + y * sinAngle,
169				-x * sinAngle + y * (1.0f-cosAngle));
170		Status status = matrix2.GetLastStatus();
171		if (status == Ok) {
172			return Multiply(&matrix2, order);
173		} else {
174			return lastStatus = status;
175		}
176	}
177	Status Scale(REAL scaleX, REAL scaleY,
178			MatrixOrder order = MatrixOrderPrepend)
179	{
180		return updateStatus(DllExports::GdipScaleMatrix(
181				nativeMatrix, scaleX, scaleY, order));
182	}
183	Status SetElements(REAL m11, REAL m12, REAL m21, REAL m22,
184			REAL dx, REAL dy)
185	{
186		return updateStatus(DllExports::GdipSetMatrixElements(
187				nativeMatrix, m11, m12, m21, m22, dx, dy));
188	}
189	Status Shear(REAL shearX, REAL shearY,
190			MatrixOrder order = MatrixOrderPrepend)
191	{
192		return updateStatus(DllExports::GdipShearMatrix(
193				nativeMatrix, shearX, shearY, order));
194	}
195	Status TransformPoints(PointF *pts, INT count = 1) const
196	{
197		return updateStatus(DllExports::GdipTransformMatrixPoints(
198				nativeMatrix, pts, count));
199	}
200	Status TransformPoints(Point *pts, INT count = 1) const
201	{
202		return updateStatus(DllExports::GdipTransformMatrixPointsI(
203				nativeMatrix, pts, count));
204	}
205	Status TransformVectors(PointF *pts, INT count = 1) const
206	{
207		return updateStatus(DllExports::GdipVectorTransformMatrixPoints(
208				nativeMatrix, pts, count));
209	}
210	Status TransformVectors(Point *pts, INT count = 1) const
211	{
212		return updateStatus(DllExports::GdipVectorTransformMatrixPointsI(
213				nativeMatrix, pts, count));
214	}
215	Status Translate(REAL offsetX, REAL offsetY,
216			MatrixOrder order = MatrixOrderPrepend)
217	{
218		return updateStatus(DllExports::GdipTranslateMatrix(
219				nativeMatrix, offsetX, offsetY, order));
220	}
221
222private:
223	Matrix(GpMatrix *matrix, Status status):
224		nativeMatrix(matrix), lastStatus(status) {}
225	Matrix(const Matrix&);
226	Matrix& operator=(const Matrix&);
227
228	Status updateStatus(Status newStatus) const
229	{
230		if (newStatus != Ok) lastStatus = newStatus;
231		return newStatus;
232	}
233
234	GpMatrix *nativeMatrix;
235	mutable Status lastStatus;
236};
237
238#undef GDIP_MATRIX_PI
239
240#endif /* __GDIPLUS_MATRIX_H */
241