1 //
2 // System.Drawing.Drawing2D.Matrix.cs
3 //
4 // Authors:
5 //   Stefan Maierhofer <sm@cg.tuwien.ac.at>
6 //   Dennis Hayes (dennish@Raytek.com)
7 //   Duncan Mak (duncan@ximian.com)
8 //   Ravindra (rkumar@novell.com)
9 //
10 // (C) Ximian, Inc.  http://www.ximian.com
11 // Copyright (C) 2004, 2006 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32 
33 using System.Runtime.InteropServices;
34 
35 namespace System.Drawing.Drawing2D
36 {
37         public sealed class Matrix : MarshalByRefObject, IDisposable
38         {
39                 internal IntPtr nativeMatrix;
40 
41                 // constructors
Matrix(IntPtr ptr)42                 internal Matrix (IntPtr ptr)
43                 {
44                         nativeMatrix = ptr;
45                 }
46 
Matrix()47                 public Matrix ()
48                 {
49 			Status status = GDIPlus.GdipCreateMatrix (out nativeMatrix);
50 			GDIPlus.CheckStatus (status);
51                 }
52 
Matrix(Rectangle rect, Point[] plgpts)53                 public Matrix (Rectangle rect, Point[] plgpts)
54                 {
55 			if (plgpts == null)
56 				throw new ArgumentNullException ("plgpts");
57 			if (plgpts.Length != 3)
58 				throw new ArgumentException ("plgpts");
59 
60 			Status status = GDIPlus.GdipCreateMatrix3I (ref rect, plgpts, out nativeMatrix);
61 			GDIPlus.CheckStatus (status);
62                 }
63 
Matrix(RectangleF rect, PointF[] plgpts)64                 public Matrix (RectangleF rect, PointF[] plgpts)
65                 {
66 			if (plgpts == null)
67 				throw new ArgumentNullException ("plgpts");
68 			if (plgpts.Length != 3)
69 				throw new ArgumentException ("plgpts");
70 
71 			Status status = GDIPlus.GdipCreateMatrix3 (ref rect, plgpts, out nativeMatrix);
72 			GDIPlus.CheckStatus (status);
73                 }
74 
Matrix(float m11, float m12, float m21, float m22, float dx, float dy)75                 public Matrix (float m11, float m12, float m21, float m22, float dx, float dy)
76                 {
77 			Status status = GDIPlus.GdipCreateMatrix2 (m11, m12, m21, m22, dx, dy, out nativeMatrix);
78 			GDIPlus.CheckStatus (status);
79                 }
80 
81                 // properties
82                 public float[] Elements {
83                         get {
84 				float [] retval = new float [6];
85 				IntPtr tmp = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (float)) * 6);
86 				try {
87 					Status status = GDIPlus.GdipGetMatrixElements (nativeMatrix, tmp);
88 					GDIPlus.CheckStatus (status);
89 					Marshal.Copy (tmp, retval, 0, 6);
90 				}
91 				finally {
92 					Marshal.FreeHGlobal (tmp);
93 				}
94 				return retval;
95                         }
96                 }
97 
98                 public bool IsIdentity {
99                         get {
100                                 bool retval;
101 				Status status = GDIPlus.GdipIsMatrixIdentity (nativeMatrix, out retval);
102 				GDIPlus.CheckStatus (status);
103                                 return retval;
104                         }
105                 }
106 
107                 public bool IsInvertible {
108                         get {
109                                 bool retval;
110 				Status status = GDIPlus.GdipIsMatrixInvertible (nativeMatrix, out retval);
111 				GDIPlus.CheckStatus (status);
112                                 return retval;
113                         }
114                 }
115 
116                 public float OffsetX {
117                         get {
118                                 return this.Elements [4];
119                         }
120                 }
121 
122                 public float OffsetY {
123                         get {
124                                 return this.Elements [5];
125                         }
126                 }
127 
Clone()128                 public Matrix Clone()
129                 {
130                         IntPtr retval;
131                         Status status = GDIPlus.GdipCloneMatrix (nativeMatrix, out retval);
132 			GDIPlus.CheckStatus (status);
133                         return new Matrix (retval);
134                 }
135 
136 
Dispose()137                 public void Dispose ()
138                 {
139 			if (nativeMatrix != IntPtr.Zero) {
140 				Status status = GDIPlus.GdipDeleteMatrix (nativeMatrix);
141 				GDIPlus.CheckStatus (status);
142 				nativeMatrix = IntPtr.Zero;
143 			}
144 
145 			GC.SuppressFinalize (this);
146                 }
147 
Equals(object obj)148                 public override bool Equals (object obj)
149                 {
150                         Matrix m = obj as Matrix;
151 
152                         if (m != null) {
153                                 bool retval;
154 				Status status = GDIPlus.GdipIsMatrixEqual (nativeMatrix, m.nativeMatrix, out retval);
155 				GDIPlus.CheckStatus (status);
156                                 return retval;
157 
158                         } else
159                                 return false;
160                 }
161 
~Matrix()162                 ~Matrix()
163                 {
164                         Dispose ();
165                 }
166 
GetHashCode()167                 public override int GetHashCode ()
168                 {
169                         return base.GetHashCode ();
170                 }
171 
Invert()172                 public void Invert ()
173                 {
174 			Status status = GDIPlus.GdipInvertMatrix (nativeMatrix);
175 			GDIPlus.CheckStatus (status);
176                 }
177 
Multiply(Matrix matrix)178                 public void Multiply (Matrix matrix)
179                 {
180                         Multiply (matrix, MatrixOrder.Prepend);
181                 }
182 
Multiply(Matrix matrix, MatrixOrder order)183 		public void Multiply (Matrix matrix, MatrixOrder order)
184 		{
185 			if (matrix == null)
186 				throw new ArgumentNullException ("matrix");
187 
188 			Status status = GDIPlus.GdipMultiplyMatrix (nativeMatrix, matrix.nativeMatrix, order);
189 			GDIPlus.CheckStatus (status);
190                 }
191 
Reset()192                 public void Reset()
193                 {
194 			Status status = GDIPlus.GdipSetMatrixElements (nativeMatrix, 1, 0, 0, 1, 0, 0);
195 			GDIPlus.CheckStatus (status);
196                 }
197 
Rotate(float angle)198                 public void Rotate (float angle)
199                 {
200                         Rotate (angle, MatrixOrder.Prepend);
201                 }
202 
Rotate(float angle, MatrixOrder order)203                 public void Rotate (float angle, MatrixOrder order)
204                 {
205 			Status status = GDIPlus.GdipRotateMatrix (nativeMatrix, angle, order);
206 			GDIPlus.CheckStatus (status);
207                 }
208 
RotateAt(float angle, PointF point)209                 public void RotateAt (float angle, PointF point)
210                 {
211                         RotateAt (angle, point, MatrixOrder.Prepend);
212                 }
213 
RotateAt(float angle, PointF point, MatrixOrder order)214                 public void RotateAt (float angle, PointF point, MatrixOrder order)
215                 {
216 			if ((order < MatrixOrder.Prepend) || (order > MatrixOrder.Append))
217 				throw new ArgumentException ("order");
218 
219                         angle *= (float) (Math.PI / 180.0);  // degrees to radians
220                         float cos = (float) Math.Cos (angle);
221                         float sin = (float) Math.Sin (angle);
222                         float e4 = -point.X * cos + point.Y * sin + point.X;
223                         float e5 = -point.X * sin - point.Y * cos + point.Y;
224                         float[] m = this.Elements;
225 
226 			Status status;
227 
228                         if (order == MatrixOrder.Prepend)
229 				status = GDIPlus.GdipSetMatrixElements (nativeMatrix,
230 								cos * m[0] + sin * m[2],
231 								cos * m[1] + sin * m[3],
232 								-sin * m[0] + cos * m[2],
233 								-sin * m[1] + cos * m[3],
234 								e4 * m[0] + e5 * m[2] + m[4],
235 								e4 * m[1] + e5 * m[3] + m[5]);
236                         else
237 				status = GDIPlus.GdipSetMatrixElements (nativeMatrix,
238 								m[0] * cos + m[1] * -sin,
239 								m[0] * sin + m[1] * cos,
240 								m[2] * cos + m[3] * -sin,
241 								m[2] * sin + m[3] * cos,
242 								m[4] * cos + m[5] * -sin + e4,
243 								m[4] * sin + m[5] * cos + e5);
244 			GDIPlus.CheckStatus (status);
245                 }
246 
Scale(float scaleX, float scaleY)247                 public void Scale (float scaleX, float scaleY)
248                 {
249                         Scale (scaleX, scaleY, MatrixOrder.Prepend);
250                 }
251 
Scale(float scaleX, float scaleY, MatrixOrder order)252                 public void Scale (float scaleX, float scaleY, MatrixOrder order)
253                 {
254 			Status status = GDIPlus.GdipScaleMatrix (nativeMatrix, scaleX, scaleY, order);
255 			GDIPlus.CheckStatus (status);
256                 }
257 
Shear(float shearX, float shearY)258                 public void Shear (float shearX, float shearY)
259                 {
260                         Shear (shearX, shearY, MatrixOrder.Prepend);
261                 }
262 
Shear(float shearX, float shearY, MatrixOrder order)263                 public void Shear (float shearX, float shearY, MatrixOrder order)
264                 {
265 			Status status = GDIPlus.GdipShearMatrix (nativeMatrix, shearX, shearY, order);
266 			GDIPlus.CheckStatus (status);
267                 }
268 
TransformPoints(Point[] pts)269                 public void TransformPoints (Point[] pts)
270                 {
271 			if (pts == null)
272 				throw new ArgumentNullException ("pts");
273 
274 			Status status = GDIPlus.GdipTransformMatrixPointsI (nativeMatrix, pts, pts.Length);
275 			GDIPlus.CheckStatus (status);
276                 }
277 
TransformPoints(PointF[] pts)278                 public void TransformPoints (PointF[] pts)
279                 {
280 			if (pts == null)
281 				throw new ArgumentNullException ("pts");
282 
283 			Status status = GDIPlus.GdipTransformMatrixPoints (nativeMatrix, pts, pts.Length);
284 			GDIPlus.CheckStatus (status);
285                 }
286 
TransformVectors(Point[] pts)287                 public void TransformVectors (Point[] pts)
288                 {
289 			if (pts == null)
290 				throw new ArgumentNullException ("pts");
291 
292 			Status status = GDIPlus.GdipVectorTransformMatrixPointsI (nativeMatrix, pts, pts.Length);
293 			GDIPlus.CheckStatus (status);
294                 }
295 
TransformVectors(PointF[] pts)296                 public void TransformVectors (PointF[] pts)
297                 {
298 			if (pts == null)
299 				throw new ArgumentNullException ("pts");
300 
301 			Status status = GDIPlus.GdipVectorTransformMatrixPoints (nativeMatrix, pts, pts.Length);
302 			GDIPlus.CheckStatus (status);
303                 }
304 
Translate(float offsetX, float offsetY)305                 public void Translate (float offsetX, float offsetY)
306                 {
307                         Translate (offsetX, offsetY, MatrixOrder.Prepend);
308                 }
309 
Translate(float offsetX, float offsetY, MatrixOrder order)310                 public void Translate (float offsetX, float offsetY, MatrixOrder order)
311                 {
312 			Status status = GDIPlus.GdipTranslateMatrix (nativeMatrix, offsetX, offsetY, order);
313 			GDIPlus.CheckStatus (status);
314                 }
315 
VectorTransformPoints(Point[] pts)316                 public void VectorTransformPoints (Point[] pts)
317                 {
318                         TransformVectors (pts);
319                 }
320 
321                 internal IntPtr NativeObject
322                 {
323 			get{
324 				return nativeMatrix;
325 			}
326 			set	{
327 				nativeMatrix = value;
328 			}
329 		}
330         }
331 }
332