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