2 // System.Drawing.Drawing2D.Matrix.cs
\r
5 // Stefan Maierhofer <sm@cg.tuwien.ac.at>
\r
6 // Dennis Hayes (dennish@Raytek.com)
\r
8 // (C) Ximian, Inc. http://www.ximian.com
\r
12 using System.Drawing;
\r
13 using System.Runtime.InteropServices;
\r
15 namespace System.Drawing.Drawing2D
\r
17 public sealed class Matrix : MarshalByRefObject, IDisposable
\r
19 // initialize to identity
\r
20 private float[] m = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
\r
25 /* TODO: depends on System.Drawing.Drawing2D.Rectangle
\r
26 public Matrix(Rectangle rect , Point[] plgpts)
\r
32 /* TODO: depends on System.Drawing.Drawing2D.RectangleF
\r
33 public Matrix(RectangleF rect , PointF[] pa)
\r
38 public Matrix(float m11, float m12,
\r
39 float m21, float m22,
\r
42 m[0] = m11; m[1] = m12;
\r
43 m[2] = m21; m[3] = m22;
\r
44 m[4] = dx; m[5] = dy;
\r
48 public float[] Elements
\r
53 public bool IsIdentity
\r
57 if ( (m[0] == 1.0f) && (m[1] == 0.0f) &&
\r
58 (m[2] == 0.0f) && (m[3] == 1.0f) &&
\r
59 (m[4] == 0.0f) && (m[5] == 0.0f) )
\r
66 public bool IsInvertible
\r
70 // matrix M is invertible if det(M) != 0
\r
71 float det = m[0] * m[3] - m[2] * m[1];
\r
72 if (det != 0.0f) return true;
\r
77 public float OffsetX
\r
79 get { return m[4]; }
\r
82 public float OffsetY
\r
84 get { return m[5]; }
\r
88 public Matrix Clone()
\r
90 return new Matrix(m[0], m[1], m[2], m[3], m[4], m[5]);
\r
93 public void Dispose() { }
\r
95 public override bool Equals(object obj)
\r
99 float[] a = ((Matrix)obj).Elements;
\r
100 if ( m[0] == a[0] && m[1] == a[1] &&
\r
101 m[2] == a[2] && m[3] == a[3] &&
\r
102 m[4] == a[4] && m[5] == a[5] )
\r
115 [StructLayout(LayoutKind.Explicit)]
\r
116 internal struct BitConverter
\r
118 [FieldOffset(0)] public float f;
\r
119 [FieldOffset(0)] public int i;
\r
122 public override int GetHashCode()
\r
125 // compiler is not smart
\r
128 for (int i = 0; i < 6; i++)
\r
136 public void Invert()
\r
138 float det = m[0] * m[3] - m[2] * m[1];
\r
139 if (det != 0.0f) // if invertible
\r
147 (-m[3] * m[4] + m[1] * m[5]) / det,
\r
148 (m[2] * m[4] - m[0] * m[5]) / det
\r
154 public void Multiply(Matrix matrix)
\r
156 Multiply(matrix, MatrixOrder.Prepend);
\r
159 public void Multiply(Matrix matrix, MatrixOrder order)
\r
163 case MatrixOrder.Prepend:
\r
164 // this = matrix * this
\r
165 float[] p = matrix.Elements;
\r
168 p[0] * m[0] + p[1] * m[2],
\r
169 p[0] * m[1] + p[1] * m[3],
\r
170 p[2] * m[0] + p[3] * m[2],
\r
171 p[2] * m[1] + p[3] * m[3],
\r
172 p[4] * m[0] + p[5] * m[2] + m[4],
\r
173 p[4] * m[1] + p[5] * m[3] + m[5]
\r
177 case MatrixOrder.Append:
\r
178 // this = this * matrix
\r
179 float[] a = matrix.Elements;
\r
182 m[0] * a[0] + m[1] * a[2],
\r
183 m[0] * a[1] + m[1] * a[3],
\r
184 m[2] * a[0] + m[3] * a[2],
\r
185 m[2] * a[1] + m[3] * a[3],
\r
186 m[4] * a[0] + m[5] * a[2] + a[4],
\r
187 m[4] * a[1] + m[5] * a[3] + a[5]
\r
194 public void Reset()
\r
196 m[0] = 1.0f; m[1] = 0.0f;
\r
197 m[2] = 0.0f; m[3] = 1.0f;
\r
198 m[4] = 0.0f; m[5] = 0.0f;
\r
201 public void Rotate(float angle)
\r
203 Rotate(angle, MatrixOrder.Prepend);
\r
206 public void Rotate(float angle, MatrixOrder order)
\r
208 angle *= (float)(Math.PI / 180.0); // degrees to randians
\r
209 float cos = (float)Math.Cos(angle);
\r
210 float sin = (float)Math.Sin(angle);
\r
213 case MatrixOrder.Prepend:
\r
214 // this = rotation * this
\r
217 cos * m[0] + sin * m[2],
\r
218 cos * m[1] + sin * m[3],
\r
219 -sin * m[0] + cos * m[2],
\r
220 -sin * m[1] + cos * m[3],
\r
226 case MatrixOrder.Append:
\r
227 // this = this * rotation
\r
230 m[0] * cos + m[1] * -sin,
\r
231 m[0] * sin + m[1] * cos,
\r
232 m[2] * cos + m[3] * -sin,
\r
233 m[2] * sin + m[3] * cos,
\r
234 m[4] * cos + m[5] * -sin,
\r
235 m[4] * sin + m[5] * cos
\r
242 public void RotateAt(float angle, PointF point)
\r
244 RotateAt(angle, point, MatrixOrder.Prepend);
\r
247 public void RotateAt(float angle, PointF point, MatrixOrder order)
\r
249 angle *= (float)(Math.PI / 180.0); // degrees to randians
\r
250 float cos = (float)Math.Cos(angle);
\r
251 float sin = (float)Math.Sin(angle);
\r
252 float e4 = -point.X * cos + point.Y * sin + point.X;
\r
253 float e5 = -point.X * sin - point.Y * cos + point.Y;
\r
256 case MatrixOrder.Prepend:
\r
257 // this = rotation * this
\r
260 cos * m[0] + sin * m[2],
\r
261 cos * m[1] + sin * m[3],
\r
262 -sin * m[0] + cos * m[2],
\r
263 -sin * m[1] + cos * m[3],
\r
264 e4 * m[0] + e5 * m[2] + m[4],
\r
265 e4 * m[1] + e5 * m[3] + m[5]
\r
269 case MatrixOrder.Append:
\r
270 // this = this * rotation
\r
273 m[0] * cos + m[1] * -sin,
\r
274 m[0] * sin + m[1] * cos,
\r
275 m[2] * cos + m[3] * -sin,
\r
276 m[2] * sin + m[3] * cos,
\r
277 m[4] * cos + m[5] * -sin + e4,
\r
278 m[4] * sin + m[5] * cos + e5
\r
285 public void Scale(float scaleX, float scaleY)
\r
287 Scale(scaleX, scaleY, MatrixOrder.Prepend);
\r
290 public void Scale(float scaleX, float scaleY, MatrixOrder order)
\r
294 case MatrixOrder.Prepend:
\r
295 // this = scale * this
\r
296 m[0] *= scaleX; m[1] *= scaleX;
\r
297 m[2] *= scaleY; m[3] *= scaleY;
\r
299 case MatrixOrder.Append:
\r
300 // this = this * scale
\r
301 m[0] *= scaleX; m[1] *= scaleY;
\r
302 m[2] *= scaleX; m[3] *= scaleY;
\r
303 m[4] *= scaleX; m[5] *= scaleY;
\r
308 public void Shear(float shearX, float shearY)
\r
310 Shear(shearX, shearY, MatrixOrder.Prepend);
\r
313 // LAMESPEC: quote from beta 2 sdk docs: "[To be supplied!]"
\r
315 // assuming transformation matrix:
\r
321 public void Shear(float shearX, float shearY, MatrixOrder order)
\r
325 case MatrixOrder.Prepend:
\r
326 // this = shear * this
\r
329 m[0] + shearY * m[2],
\r
330 m[1] + shearY * m[3],
\r
331 shearX * m[0] + m[2],
\r
332 shearX * m[1] + m[3],
\r
338 case MatrixOrder.Append:
\r
339 // this = this * shear
\r
342 m[0] + m[1] * shearX,
\r
343 m[0] * shearY + m[1],
\r
344 m[2] + m[3] * shearX,
\r
345 m[2] * shearY + m[3],
\r
346 m[4] + m[5] * shearX ,
\r
347 m[4] * shearY + m[5]
\r
354 public void TransformPoints(Point[] pts)
\r
356 for (int i = 0; i < pts.Length; i++)
\r
358 float x = (float)pts[i].X;
\r
359 float y = (float)pts[i].Y;
\r
360 pts[i].X = (int)(x * m[0] + y * m[2] + m[4]);
\r
361 pts[i].Y = (int)(x * m[1] + y * m[3] + m[5]);
\r
365 public void TransformPoints(PointF[] pts)
\r
367 for (int i = 0; i < pts.Length; i++)
\r
369 float x = pts[i].X;
\r
370 float y = pts[i].Y;
\r
371 pts[i].X = x * m[0] + y * m[2] + m[4];
\r
372 pts[i].Y = x * m[1] + y * m[3] + m[5];
\r
376 public void TransformVectors(Point[] pts)
\r
378 for (int i = 0; i < pts.Length; i++)
\r
380 float x = (float)pts[i].X;
\r
381 float y = (float)pts[i].Y;
\r
382 pts[i].X = (int)(x * m[0] + y * m[2]);
\r
383 pts[i].Y = (int)(x * m[1] + y * m[3]);
\r
387 public void TransformVectors(PointF[] pts)
\r
389 for (int i = 0; i < pts.Length; i++)
\r
391 float x = pts[i].X;
\r
392 float y = pts[i].Y;
\r
393 pts[i].X = x * m[0] + y * m[2];
\r
394 pts[i].Y = x * m[1] + y * m[3];
\r
398 public void Translate(float offsetX, float offsetY)
\r
400 Translate(offsetX, offsetY, MatrixOrder.Prepend);
\r
403 public void Translate(float offsetX, float offsetY, MatrixOrder order)
\r
407 case MatrixOrder.Prepend:
\r
408 // this = translation * this
\r
409 m[4] = offsetX * m[0] + offsetY * m[2] + m[4];
\r
410 m[5] = offsetX * m[1] + offsetY * m[3] + m[5];
\r
412 case MatrixOrder.Append:
\r
413 // this = this * translation
\r
420 // LAMESPEC: quote from beta 2 sdk docs: "[To be supplied!]"
\r
422 public void VectorTransformPoints(Point[] pts)
\r
427 // some simple test (TODO: remove)
\r
429 public static void Main()
\r
431 PointF[] p = {new PointF(1.0f, 2.0f)};
\r
432 Console.WriteLine("(" + p[0].X + " " + p[0].Y + ")");
\r
433 Matrix m = new Matrix();
\r
435 m.Translate(1.0f, 1.0f);
\r
436 m.Scale(2.0f, 2.0f);
\r
439 m.TransformPoints(p);
\r
440 Console.WriteLine("(" + p[0].X + " " + p[0].Y + ")");
\r
442 m.TransformPoints(p);
\r
443 Console.WriteLine("(" + p[0].X + " " + p[0].Y + ")");
\r
445 Matrix a = new Matrix(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
\r
446 Matrix b = new Matrix(2.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f);
\r
448 Console.WriteLine("h(a) = " + a.GetHashCode());
\r
449 Console.WriteLine("h(b) = " + b.GetHashCode());
\r