2 // System.Drawing.Drawing2D.Matrix.cs
5 // Stefan Maierhofer <sm@cg.tuwien.ac.at>
7 // (C) Ximian, Inc. http://www.ximian.com
12 using System.Runtime.InteropServices;
14 namespace System.Drawing.Drawing2D
16 public sealed class Matrix : MarshalByRefObject, IDisposable
18 // initialize to identity
19 private float[] m = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
24 /* TODO: depends on System.Drawing.Drawing2D.Rectangle
25 public Matrix(Rectangle rect , Point[] plgpts)
31 /* TODO: depends on System.Drawing.Drawing2D.RectangleF
32 public Matrix(RectangleF rect , PointF[] pa)
37 public Matrix(float m11, float m12,
41 m[0] = m11; m[1] = m12;
42 m[2] = m21; m[3] = m22;
47 public float[] Elements
52 public bool IsIdentity
56 if ( (m[0] == 1.0f) && (m[1] == 0.0f) &&
57 (m[2] == 0.0f) && (m[3] == 1.0f) &&
58 (m[4] == 0.0f) && (m[5] == 0.0f) )
65 public bool IsInvertible
69 // matrix M is invertible if det(M) != 0
70 float det = m[0] * m[3] - m[2] * m[1];
71 if (det != 0.0f) return true;
89 return new Matrix(m[0], m[1], m[2], m[3], m[4], m[5]);
92 public void Dispose() { }
94 public override bool Equals(object obj)
98 float[] a = ((Matrix)obj).Elements;
99 if ( m[0] == a[0] && m[1] == a[1] &&
100 m[2] == a[2] && m[3] == a[3] &&
101 m[4] == a[4] && m[5] == a[5] )
114 [StructLayout(LayoutKind.Explicit)]
115 internal struct BitConverter
117 [FieldOffset(0)] public float f;
118 [FieldOffset(0)] public int i;
121 public override int GetHashCode()
124 // compiler is not smart
127 for (int i = 0; i < 6; i++)
137 float det = m[0] * m[3] - m[2] * m[1];
138 if (det != 0.0f) // if invertible
146 (-m[3] * m[4] + m[1] * m[5]) / det,
147 (m[2] * m[4] - m[0] * m[5]) / det
153 public void Multiply(Matrix matrix)
155 Multiply(matrix, MatrixOrder.Prepend);
158 public void Multiply(Matrix matrix, MatrixOrder order)
162 case MatrixOrder.Prepend:
163 // this = matrix * this
164 float[] p = matrix.Elements;
167 p[0] * m[0] + p[1] * m[2],
168 p[0] * m[1] + p[1] * m[3],
169 p[2] * m[0] + p[3] * m[2],
170 p[2] * m[1] + p[3] * m[3],
171 p[4] * m[0] + p[5] * m[2] + m[4],
172 p[4] * m[1] + p[5] * m[3] + m[5]
176 case MatrixOrder.Append:
177 // this = this * matrix
178 float[] a = matrix.Elements;
181 m[0] * a[0] + m[1] * a[2],
182 m[0] * a[1] + m[1] * a[3],
183 m[2] * a[0] + m[3] * a[2],
184 m[2] * a[1] + m[3] * a[3],
185 m[4] * a[0] + m[5] * a[2] + a[4],
186 m[4] * a[1] + m[5] * a[3] + a[5]
195 m[0] = 1.0f; m[1] = 0.0f;
196 m[2] = 0.0f; m[3] = 1.0f;
197 m[4] = 0.0f; m[5] = 0.0f;
200 public void Rotate(float angle)
202 Rotate(angle, MatrixOrder.Prepend);
205 public void Rotate(float angle, MatrixOrder order)
207 angle *= (float)(Math.PI / 180.0); // degrees to randians
208 float cos = (float)Math.Cos(angle);
209 float sin = (float)Math.Sin(angle);
212 case MatrixOrder.Prepend:
213 // this = rotation * this
216 cos * m[0] + sin * m[2],
217 cos * m[1] + sin * m[3],
218 -sin * m[0] + cos * m[2],
219 -sin * m[1] + cos * m[3],
225 case MatrixOrder.Append:
226 // this = this * rotation
229 m[0] * cos + m[1] * -sin,
230 m[0] * sin + m[1] * cos,
231 m[2] * cos + m[3] * -sin,
232 m[2] * sin + m[3] * cos,
233 m[4] * cos + m[5] * -sin,
234 m[4] * sin + m[5] * cos
241 public void RotateAt(float angle, PointF point)
243 RotateAt(angle, point, MatrixOrder.Prepend);
246 public void RotateAt(float angle, PointF point, MatrixOrder order)
248 angle *= (float)(Math.PI / 180.0); // degrees to randians
249 float cos = (float)Math.Cos(angle);
250 float sin = (float)Math.Sin(angle);
251 float e4 = -point.X * cos + point.Y * sin + point.X;
252 float e5 = -point.X * sin - point.Y * cos + point.Y;
255 case MatrixOrder.Prepend:
256 // this = rotation * this
259 cos * m[0] + sin * m[2],
260 cos * m[1] + sin * m[3],
261 -sin * m[0] + cos * m[2],
262 -sin * m[1] + cos * m[3],
263 e4 * m[0] + e5 * m[2] + m[4],
264 e4 * m[1] + e5 * m[3] + m[5]
268 case MatrixOrder.Append:
269 // this = this * rotation
272 m[0] * cos + m[1] * -sin,
273 m[0] * sin + m[1] * cos,
274 m[2] * cos + m[3] * -sin,
275 m[2] * sin + m[3] * cos,
276 m[4] * cos + m[5] * -sin + e4,
277 m[4] * sin + m[5] * cos + e5
284 public void Scale(float scaleX, float scaleY)
286 Scale(scaleX, scaleY, MatrixOrder.Prepend);
289 public void Scale(float scaleX, float scaleY, MatrixOrder order)
293 case MatrixOrder.Prepend:
294 // this = scale * this
295 m[0] *= scaleX; m[1] *= scaleX;
296 m[2] *= scaleY; m[3] *= scaleY;
298 case MatrixOrder.Append:
299 // this = this * scale
300 m[0] *= scaleX; m[1] *= scaleY;
301 m[2] *= scaleX; m[3] *= scaleY;
302 m[4] *= scaleX; m[5] *= scaleY;
307 public void Shear(float shearX, float shearY)
309 Shear(shearX, shearY, MatrixOrder.Prepend);
312 // LAMESPEC: quote from beta 2 sdk docs: "[To be supplied!]"
314 // assuming transformation matrix:
320 public void Shear(float shearX, float shearY, MatrixOrder order)
324 case MatrixOrder.Prepend:
325 // this = shear * this
328 m[0] + shearY * m[2],
329 m[1] + shearY * m[3],
330 shearX * m[0] + m[2],
331 shearX * m[1] + m[3],
337 case MatrixOrder.Append:
338 // this = this * shear
341 m[0] + m[1] * shearX,
342 m[0] * shearY + m[1],
343 m[2] + m[3] * shearX,
344 m[2] * shearY + m[3],
345 m[4] + m[5] * shearX ,
353 public void TransformPoints(Point[] pts)
355 for (int i = 0; i < pts.Length; i++)
357 float x = (float)pts[i].X;
358 float y = (float)pts[i].Y;
359 pts[i].X = (int)(x * m[0] + y * m[2] + m[4]);
360 pts[i].Y = (int)(x * m[1] + y * m[3] + m[5]);
364 public void TransformPoints(PointF[] pts)
366 for (int i = 0; i < pts.Length; i++)
370 pts[i].X = x * m[0] + y * m[2] + m[4];
371 pts[i].Y = x * m[1] + y * m[3] + m[5];
375 public void TransformVectors(Point[] pts)
377 for (int i = 0; i < pts.Length; i++)
379 float x = (float)pts[i].X;
380 float y = (float)pts[i].Y;
381 pts[i].X = (int)(x * m[0] + y * m[2]);
382 pts[i].Y = (int)(x * m[1] + y * m[3]);
386 public void TransformVectors(PointF[] pts)
388 for (int i = 0; i < pts.Length; i++)
392 pts[i].X = x * m[0] + y * m[2];
393 pts[i].Y = x * m[1] + y * m[3];
397 public void Translate(float offsetX, float offsetY)
399 Translate(offsetX, offsetY, MatrixOrder.Prepend);
402 public void Translate(float offsetX, float offsetY, MatrixOrder order)
406 case MatrixOrder.Prepend:
407 // this = translation * this
408 m[4] = offsetX * m[0] + offsetY * m[2] + m[4];
409 m[5] = offsetX * m[1] + offsetY * m[3] + m[5];
411 case MatrixOrder.Append:
412 // this = this * translation
419 // LAMESPEC: quote from beta 2 sdk docs: "[To be supplied!]"
421 public void VectorTransformPoints(Point[] pts)
426 // some simple test (TODO: remove)
428 public static void Main()
430 PointF[] p = {new PointF(1.0f, 2.0f)};
431 Console.WriteLine("(" + p[0].X + " " + p[0].Y + ")");
432 Matrix m = new Matrix();
434 m.Translate(1.0f, 1.0f);
438 m.TransformPoints(p);
439 Console.WriteLine("(" + p[0].X + " " + p[0].Y + ")");
441 m.TransformPoints(p);
442 Console.WriteLine("(" + p[0].X + " " + p[0].Y + ")");
444 Matrix a = new Matrix(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
445 Matrix b = new Matrix(2.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f);
447 Console.WriteLine("h(a) = " + a.GetHashCode());
448 Console.WriteLine("h(b) = " + b.GetHashCode());