2 // System.Drawing.Drawing2D.Matrix.cs
5 // Stefan Maierhofer <sm@cg.tuwien.ac.at>
7 // (C) Ximian, Inc. http://www.ximian.com
13 namespace System.Drawing.Drawing2D
15 public sealed class Matrix : MarshalByRefObject, IDisposable
17 // initialize to identity
18 private float[] m = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
23 /* TODO: depends on System.Drawing.Drawing2D.Rectangle
24 public Matrix(Rectangle rect , Point[] plgpts)
30 /* TODO: depends on System.Drawing.Drawing2D.RectangleF
31 public Matrix(RectangleF rect , PointF[] pa)
36 public Matrix(float m11, float m12,
40 m[0] = m11; m[1] = m12;
41 m[2] = m21; m[3] = m22;
46 public float[] Elements
51 public bool IsIdentity
55 if ( (m[0] == 1.0f) && (m[1] == 0.0f) &&
56 (m[2] == 0.0f) && (m[3] == 1.0f) &&
57 (m[4] == 0.0f) && (m[5] == 0.0f) )
64 public bool IsInvertible
68 // matrix M is invertible if det(M) != 0
69 float det = m[0] * m[3] - m[2] * m[1];
70 if (det != 0.0f) return true;
88 return new Matrix(m[0], m[1], m[2], m[3], m[4], m[5]);
91 public void Dispose() { }
93 public override bool Equals(object obj)
97 float[] a = ((Matrix)obj).Elements;
98 if ( m[0] == a[0] && m[1] == a[1] &&
99 m[2] == a[2] && m[3] == a[3] &&
100 m[4] == a[4] && m[5] == a[5] )
113 public override int GetHashCode()
115 // TODO: find a better hash function than det(M)
116 return (int)(m[0] * m[3] - m[2] * m[1]);
121 float det = m[0] * m[3] - m[2] * m[1];
122 if (det != 0.0f) // if invertible
130 (-m[3] * m[4] + m[1] * m[5]) / det,
131 (m[2] * m[4] - m[0] * m[5]) / det
137 public void Multiply(Matrix matrix)
139 Multiply(matrix, MatrixOrder.Prepend);
142 public void Multiply(Matrix matrix, MatrixOrder order)
146 case MatrixOrder.Prepend:
147 // this = matrix * this
148 float[] p = matrix.Elements;
151 p[0] * m[0] + p[1] * m[2],
152 p[0] * m[1] + p[1] * m[3],
153 p[2] * m[0] + p[3] * m[2],
154 p[2] * m[1] + p[3] * m[3],
155 p[4] * m[0] + p[5] * m[2] + m[4],
156 p[4] * m[1] + p[5] * m[3] + m[5]
160 case MatrixOrder.Append:
161 // this = this * matrix
162 float[] a = matrix.Elements;
165 m[0] * a[0] + m[1] * a[2],
166 m[0] * a[1] + m[1] * a[3],
167 m[2] * a[0] + m[3] * a[2],
168 m[2] * a[1] + m[3] * a[3],
169 m[4] * a[0] + m[5] * a[2] + a[4],
170 m[4] * a[1] + m[5] * a[3] + a[5]
179 m[0] = 1.0f; m[1] = 0.0f;
180 m[2] = 0.0f; m[3] = 1.0f;
181 m[4] = 0.0f; m[5] = 0.0f;
184 public void Rotate(float angle)
186 Rotate(angle, MatrixOrder.Prepend);
189 public void Rotate(float angle, MatrixOrder order)
191 angle *= (float)(Math.PI / 180.0); // degrees to randians
192 float cos = (float)Math.Cos(angle);
193 float sin = (float)Math.Sin(angle);
196 case MatrixOrder.Prepend:
197 // this = rotation * this
200 cos * m[0] + sin * m[2],
201 cos * m[1] + sin * m[3],
202 -sin * m[0] + cos * m[2],
203 -sin * m[1] + cos * m[3],
209 case MatrixOrder.Append:
210 // this = this * rotation
213 m[0] * cos + m[1] * -sin,
214 m[0] * sin + m[1] * cos,
215 m[2] * cos + m[3] * -sin,
216 m[2] * sin + m[3] * cos,
217 m[4] * cos + m[5] * -sin,
218 m[4] * sin + m[5] * cos
225 public void RotateAt(float angle, PointF point)
227 RotateAt(angle, point, MatrixOrder.Prepend);
230 public void RotateAt(float angle, PointF point, MatrixOrder order)
232 angle *= (float)(Math.PI / 180.0); // degrees to randians
233 float cos = (float)Math.Cos(angle);
234 float sin = (float)Math.Sin(angle);
235 float e4 = -point.X * cos + point.Y * sin + point.X;
236 float e5 = -point.X * sin - point.Y * cos + point.Y;
239 case MatrixOrder.Prepend:
240 // this = rotation * this
243 cos * m[0] + sin * m[2],
244 cos * m[1] + sin * m[3],
245 -sin * m[0] + cos * m[2],
246 -sin * m[1] + cos * m[3],
247 e4 * m[0] + e5 * m[2] + m[4],
248 e4 * m[1] + e5 * m[3] + m[5]
252 case MatrixOrder.Append:
253 // this = this * rotation
256 m[0] * cos + m[1] * -sin,
257 m[0] * sin + m[1] * cos,
258 m[2] * cos + m[3] * -sin,
259 m[2] * sin + m[3] * cos,
260 m[4] * cos + m[5] * -sin + e4,
261 m[4] * sin + m[5] * cos + e5
268 public void Scale(float scaleX, float scaleY)
270 Scale(scaleX, scaleY, MatrixOrder.Prepend);
273 public void Scale(float scaleX, float scaleY, MatrixOrder order)
277 case MatrixOrder.Prepend:
278 // this = scale * this
279 m[0] *= scaleX; m[1] *= scaleX;
280 m[2] *= scaleY; m[3] *= scaleY;
282 case MatrixOrder.Append:
283 // this = this * scale
284 m[0] *= scaleX; m[1] *= scaleY;
285 m[2] *= scaleX; m[3] *= scaleY;
286 m[4] *= scaleX; m[5] *= scaleY;
291 public void Shear(float shearX, float shearY)
293 Shear(shearX, shearY, MatrixOrder.Prepend);
296 // LAMESPEC: quote from beta 2 sdk docs: "[To be supplied!]"
298 // assuming transformation matrix:
304 public void Shear(float shearX, float shearY, MatrixOrder order)
308 case MatrixOrder.Prepend:
309 // this = shear * this
312 m[0] + shearY * m[2],
313 m[1] + shearY * m[3],
314 shearX * m[0] + m[2],
315 shearX * m[1] + m[3],
321 case MatrixOrder.Append:
322 // this = this * shear
325 m[0] + m[1] * shearX,
326 m[0] * shearY + m[1],
327 m[2] + m[3] * shearX,
328 m[2] * shearY + m[3],
329 m[4] + m[5] * shearX ,
337 public void TransformPoints(Point[] pts)
339 for (int i = 0; i < pts.Length; i++)
341 float x = (float)pts[i].X;
342 float y = (float)pts[i].Y;
343 pts[i].X = (int)(x * m[0] + y * m[2] + m[4]);
344 pts[i].Y = (int)(x * m[1] + y * m[3] + m[5]);
348 public void TransformPoints(PointF[] pts)
350 for (int i = 0; i < pts.Length; i++)
354 pts[i].X = x * m[0] + y * m[2] + m[4];
355 pts[i].Y = x * m[1] + y * m[3] + m[5];
359 public void TransformVectors(Point[] pts)
361 for (int i = 0; i < pts.Length; i++)
363 float x = (float)pts[i].X;
364 float y = (float)pts[i].Y;
365 pts[i].X = (int)(x * m[0] + y * m[2]);
366 pts[i].Y = (int)(x * m[1] + y * m[3]);
370 public void TransformVectors(PointF[] pts)
372 for (int i = 0; i < pts.Length; i++)
376 pts[i].X = x * m[0] + y * m[2];
377 pts[i].Y = x * m[1] + y * m[3];
381 public void Translate(float offsetX, float offsetY)
383 Translate(offsetX, offsetY, MatrixOrder.Prepend);
386 public void Translate(float offsetX, float offsetY, MatrixOrder order)
390 case MatrixOrder.Prepend:
391 // this = translation * this
392 m[4] = offsetX * m[0] + offsetY * m[2] + m[4];
393 m[5] = offsetX * m[1] + offsetY * m[3] + m[5];
395 case MatrixOrder.Append:
396 // this = this * translation
403 // LAMESPEC: quote from beta 2 sdk docs: "[To be supplied!]"
404 public void VectorTransformPoints(Point[] pts)
409 /* some simple test (TODO: remove)
410 public static void Main()
412 PointF[] p = {new PointF(1.0f, 2.0f)};
413 Console.WriteLine("(" + p[0].X + " " + p[0].Y + ")");
414 Matrix m = new Matrix();
416 m.Translate(1.0f, 1.0f);
420 m.TransformPoints(p);
421 Console.WriteLine("(" + p[0].X + " " + p[0].Y + ")");
423 m.TransformPoints(p);
424 Console.WriteLine("(" + p[0].X + " " + p[0].Y + ")");