1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2007 Novell, Inc. (http://www.novell.com)
23 // Chris Toshok (toshok@ximian.com)
27 using System.ComponentModel;
28 using System.Globalization;
29 using System.Windows.Markup;
30 using System.Windows.Media.Converters;
31 using System.Windows.Threading;
33 namespace System.Windows.Media {
36 [TypeConverter (typeof(MatrixConverter))]
37 [ValueSerializer (typeof (MatrixValueSerializer))]
38 public struct Matrix : IFormattable {
47 public Matrix (double m11,
58 this._offsetX = offsetX;
59 this._offsetY = offsetY;
62 public void Append (Matrix matrix)
71 _m11 = this._m11 * matrix.M11 + this._m12 * matrix.M21;
72 _m12 = this._m11 * matrix.M12 + this._m12 * matrix.M22;
73 _m21 = this._m21 * matrix.M11 + this._m22 * matrix.M21;
74 _m22 = this._m21 * matrix.M12 + this._m22 * matrix.M22;
76 _offsetX = this._offsetX * matrix.M11 + this._offsetY * matrix.M21 + matrix.OffsetX;
77 _offsetY = this._offsetX * matrix.M12 + this._offsetY * matrix.M22 + matrix.OffsetY;
83 this._offsetX = _offsetX;
84 this._offsetY = _offsetY;
87 public bool Equals (Matrix value)
89 return (_m11 == value.M11 &&
93 _offsetX == value.OffsetX &&
94 _offsetY == value.OffsetY);
97 public override bool Equals (object o)
102 return Equals ((Matrix)o);
105 public static bool Equals (Matrix matrix1,
108 return matrix1.Equals (matrix2);
111 public override int GetHashCode ()
115 var hashCode = _m11.GetHashCode ();
116 hashCode = (hashCode * 397) ^ _m12.GetHashCode ();
117 hashCode = (hashCode * 397) ^ _m21.GetHashCode ();
118 hashCode = (hashCode * 397) ^ _m22.GetHashCode ();
119 hashCode = (hashCode * 397) ^ _offsetX.GetHashCode ();
120 hashCode = (hashCode * 397) ^ _offsetY.GetHashCode ();
125 public void Invert ()
128 throw new InvalidOperationException ("Transform is not invertible.");
130 double d = Determinant;
132 /* 1/(ad-bc)[d -b; -c a] */
134 double _m11 = this._m22;
135 double _m12 = -this._m12;
136 double _m21 = -this._m21;
137 double _m22 = this._m11;
139 double _offsetX = this._m21 * this._offsetY - this._m22 * this._offsetX;
140 double _offsetY = this._m12 * this._offsetX - this._m11 * this._offsetY;
142 this._m11 = _m11 / d;
143 this._m12 = _m12 / d;
144 this._m21 = _m21 / d;
145 this._m22 = _m22 / d;
146 this._offsetX = _offsetX / d;
147 this._offsetY = _offsetY / d;
150 public static Matrix Multiply (Matrix trans1,
158 public static bool operator == (Matrix matrix1,
161 return matrix1.Equals (matrix2);
164 public static bool operator != (Matrix matrix1,
167 return !matrix1.Equals (matrix2);
170 public static Matrix operator * (Matrix trans1,
173 Matrix result = trans1;
174 result.Append (trans2);
178 public static Matrix Parse (string source)
181 throw new ArgumentNullException ("source");
183 if (source.Trim () == "Identity")
189 var tokenizer = new NumericListTokenizer (source, CultureInfo.InvariantCulture);
196 if (double.TryParse (tokenizer.GetNextToken (), NumberStyles.Float, CultureInfo.InvariantCulture, out m11)
197 && double.TryParse (tokenizer.GetNextToken (), NumberStyles.Float, CultureInfo.InvariantCulture, out m12)
198 && double.TryParse (tokenizer.GetNextToken (), NumberStyles.Float, CultureInfo.InvariantCulture, out m21)
199 && double.TryParse (tokenizer.GetNextToken (), NumberStyles.Float, CultureInfo.InvariantCulture, out m22)
200 && double.TryParse (tokenizer.GetNextToken (), NumberStyles.Float, CultureInfo.InvariantCulture, out offsetX)
201 && double.TryParse (tokenizer.GetNextToken (), NumberStyles.Float, CultureInfo.InvariantCulture, out offsetY))
203 if (!tokenizer.HasNoMoreTokens ())
205 throw new InvalidOperationException ("Invalid Matrix format: " + source);
207 value = new Matrix (m11, m12, m21, m22, offsetX, offsetY);
211 throw new FormatException (string.Format ("Invalid Matrix format: {0}", source));
217 public void Prepend (Matrix matrix)
226 _m11 = matrix.M11 * this._m11 + matrix.M12 * this._m21;
227 _m12 = matrix.M11 * this._m12 + matrix.M12 * this._m22;
228 _m21 = matrix.M21 * this._m11 + matrix.M22 * this._m21;
229 _m22 = matrix.M21 * this._m12 + matrix.M22 * this._m22;
231 _offsetX = matrix.OffsetX * this._m11 + matrix.OffsetY * this._m21 + this._offsetX;
232 _offsetY = matrix.OffsetX * this._m12 + matrix.OffsetY * this._m22 + this._offsetY;
238 this._offsetX = _offsetX;
239 this._offsetY = _offsetY;
242 public void Rotate (double angle)
244 // R_theta==[costheta -sintheta; sintheta costheta],
245 double theta = angle * Math.PI / 180;
247 Matrix r_theta = new Matrix (Math.Cos (theta), Math.Sin(theta),
248 -Math.Sin (theta), Math.Cos(theta),
254 public void RotateAt (double angle,
258 Translate (-centerX, -centerY);
260 Translate (centerX, centerY);
263 public void RotateAtPrepend (double angle,
267 Matrix m = Matrix.Identity;
268 m.RotateAt (angle, centerX, centerY);
272 public void RotatePrepend (double angle)
274 Matrix m = Matrix.Identity;
279 public void Scale (double scaleX,
282 Matrix scale = new Matrix (scaleX, 0,
289 public void ScaleAt (double scaleX,
294 Translate (-centerX, -centerY);
295 Scale (scaleX, scaleY);
296 Translate (centerX, centerY);
299 public void ScaleAtPrepend (double scaleX,
304 Matrix m = Matrix.Identity;
305 m.ScaleAt (scaleX, scaleY, centerX, centerY);
309 public void ScalePrepend (double scaleX,
312 Matrix m = Matrix.Identity;
313 m.Scale (scaleX, scaleY);
317 public void SetIdentity ()
321 _offsetX = _offsetY = 0.0;
324 public void Skew (double skewX,
327 Matrix skew_m = new Matrix (1, Math.Tan (skewY * Math.PI / 180),
328 Math.Tan (skewX * Math.PI / 180), 1,
333 public void SkewPrepend (double skewX,
336 Matrix m = Matrix.Identity;
337 m.Skew (skewX, skewY);
341 public override string ToString ()
343 return ToString (null);
346 public string ToString (IFormatProvider provider)
348 return ToString (null, provider);
351 string IFormattable.ToString (string format,
352 IFormatProvider provider)
354 return ToString (provider);
357 private string ToString (string format, IFormatProvider provider)
362 if (provider == null)
363 provider = CultureInfo.CurrentCulture;
366 format = string.Empty;
368 var separator = NumericListTokenizer.GetSeparator (provider);
370 var matrixFormat = string.Format (
371 "{{0:{0}}}{1}{{1:{0}}}{1}{{2:{0}}}{1}{{3:{0}}}{1}{{4:{0}}}{1}{{5:{0}}}",
373 return string.Format (provider, matrixFormat,
374 _m11, _m12, _m21, _m22, _offsetX, _offsetY);
377 public Point Transform (Point point)
379 return Point.Multiply (point, this);
382 public void Transform (Point[] points)
384 for (int i = 0; i < points.Length; i ++)
385 points[i] = Transform (points[i]);
388 public Vector Transform (Vector vector)
390 return Vector.Multiply (vector, this);
393 public void Transform (Vector[] vectors)
395 for (int i = 0; i < vectors.Length; i ++)
396 vectors[i] = Transform (vectors[i]);
399 public void Translate (double offsetX,
402 this._offsetX += offsetX;
403 this._offsetY += offsetY;
406 public void TranslatePrepend (double offsetX,
409 Matrix m = Matrix.Identity;
410 m.Translate (offsetX, offsetY);
414 public double Determinant {
415 get { return _m11 * _m22 - _m12 * _m21; }
418 public bool HasInverse {
419 get { return Determinant != 0; }
422 public static Matrix Identity {
423 get { return new Matrix (1.0, 0.0, 0.0, 1.0, 0.0, 0.0); }
426 public bool IsIdentity {
427 get { return Equals (Matrix.Identity); }
432 set { _m11 = value; }
436 set { _m12 = value; }
440 set { _m21 = value; }
444 set { _m22 = value; }
446 public double OffsetX {
447 get { return _offsetX; }
448 set { _offsetX = value; }
450 public double OffsetY {
451 get { return _offsetY; }
452 set { _offsetY = value; }