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