[amd64] Save missing register
[mono.git] / mcs / class / WindowsBase / System.Windows.Media / Matrix.cs
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:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
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.
19 //
20 // Copyright (c) 2007 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Chris Toshok (toshok@ximian.com)
24 //
25
26 using System;
27 using System.ComponentModel;
28 using System.Globalization;
29 using System.Windows.Markup;
30 using System.Windows.Media.Converters;
31 using System.Windows.Threading;
32
33 namespace System.Windows.Media {
34
35         [Serializable] 
36         [TypeConverter (typeof(MatrixConverter))] 
37         [ValueSerializer (typeof (MatrixValueSerializer))]
38         public struct Matrix : IFormattable {
39
40                 double _m11;
41                 double _m12;
42                 double _m21;
43                 double _m22;
44                 double _offsetX;
45                 double _offsetY;
46
47                 public Matrix (double m11,
48                                double m12,
49                                double m21,
50                                double m22,
51                                double offsetX,
52                                double offsetY)
53                 {
54                         this._m11 = m11;
55                         this._m12 = m12;
56                         this._m21 = m21;
57                         this._m22 = m22;
58                         this._offsetX = offsetX;
59                         this._offsetY = offsetY;
60                 }
61
62                 public void Append (Matrix matrix)
63                 {
64                         double _m11;
65                         double _m21;
66                         double _m12;
67                         double _m22;
68                         double _offsetX;
69                         double _offsetY;
70
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;
75
76                         _offsetX = this._offsetX * matrix.M11 + this._offsetY * matrix.M21 + matrix.OffsetX;
77                         _offsetY = this._offsetX * matrix.M12 + this._offsetY * matrix.M22 + matrix.OffsetY;
78
79                         this._m11 = _m11;
80                         this._m12 = _m12;
81                         this._m21 = _m21;
82                         this._m22 = _m22;
83                         this._offsetX = _offsetX;
84                         this._offsetY = _offsetY;
85                 }
86
87                 public bool Equals (Matrix value)
88                 {
89                         return (_m11 == value.M11 &&
90                                 _m12 == value.M12 &&
91                                 _m21 == value.M21 &&
92                                 _m22 == value.M22 &&
93                                 _offsetX == value.OffsetX &&
94                                 _offsetY == value.OffsetY);
95                 }
96
97                 public override bool Equals (object o)
98                 {
99                         if (!(o is Matrix))
100                                 return false;
101
102                         return Equals ((Matrix)o);
103                 }
104
105                 public static bool Equals (Matrix matrix1,
106                                            Matrix matrix2)
107                 {
108                         return matrix1.Equals (matrix2);
109                 }
110
111                 public override int GetHashCode ()
112                 {
113                         unchecked
114                         {
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 ();
121                                 return hashCode;
122                         }
123                 }
124
125                 public void Invert ()
126                 {
127                         if (!HasInverse)
128                                 throw new InvalidOperationException ("Transform is not invertible.");
129
130                         double d = Determinant;
131
132                         /* 1/(ad-bc)[d -b; -c a] */
133
134                         double _m11 = this._m22;
135                         double _m12 = -this._m12;
136                         double _m21 = -this._m21;
137                         double _m22 = this._m11;
138
139                         double _offsetX = this._m21 * this._offsetY - this._m22 * this._offsetX;
140                         double _offsetY = this._m12 * this._offsetX - this._m11 * this._offsetY;
141
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;
148                 }
149
150                 public static Matrix Multiply (Matrix trans1,
151                                                Matrix trans2)
152                 {
153                         Matrix m = trans1;
154                         m.Append (trans2);
155                         return m;
156                 }
157
158                 public static bool operator == (Matrix matrix1,
159                                                 Matrix matrix2)
160                 {
161                         return matrix1.Equals (matrix2);
162                 }
163
164                 public static bool operator != (Matrix matrix1,
165                                                 Matrix matrix2)
166                 {
167                         return !matrix1.Equals (matrix2);
168                 }
169
170                 public static Matrix operator * (Matrix trans1,
171                                                  Matrix trans2)
172                 {
173                         Matrix result = trans1;
174                         result.Append (trans2);
175                         return result;
176                 }
177
178                 public static Matrix Parse (string source)
179                 {
180                         if (source == null)
181                                 throw new ArgumentNullException ("source");
182                         Matrix value;
183                         if (source.Trim () == "Identity")
184                         {
185                                 value = Identity;
186                         }
187                         else
188                         {
189                                 var parts = source.Split (',');
190                                 if (parts.Length != 6)
191                                         throw new FormatException (string.Format ("Invalid Matrix format: {0}", source));
192                                 double m11;
193                                 double m12;
194                                 double m21;
195                                 double m22;
196                                 double offsetX;
197                                 double offsetY;
198                                 if (double.TryParse (parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out m11)
199                                     && double.TryParse (parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out m12)
200                                     && double.TryParse (parts[2], NumberStyles.Float, CultureInfo.InvariantCulture, out m21)
201                                     && double.TryParse (parts[3], NumberStyles.Float, CultureInfo.InvariantCulture, out m22)
202                                     && double.TryParse (parts[4], NumberStyles.Float, CultureInfo.InvariantCulture, out offsetX)
203                                     && double.TryParse (parts[5], NumberStyles.Float, CultureInfo.InvariantCulture, out offsetY))
204                                 {
205                                         value = new Matrix (m11, m12, m21, m22, offsetX, offsetY);
206                                 }
207                                 else
208                                 {
209                                         throw new FormatException (string.Format ("Invalid Matrix format: {0}", source));
210                                 }
211                         }
212                         return value;
213                 }
214
215                 public void Prepend (Matrix matrix)
216                 {
217                         double _m11;
218                         double _m21;
219                         double _m12;
220                         double _m22;
221                         double _offsetX;
222                         double _offsetY;
223
224                         _m11 = matrix.M11 * this._m11 + matrix.M12 * this._m21;
225                         _m12 = matrix.M11 * this._m12 + matrix.M12 * this._m22;
226                         _m21 = matrix.M21 * this._m11 + matrix.M22 * this._m21;
227                         _m22 = matrix.M21 * this._m12 + matrix.M22 * this._m22;
228
229                         _offsetX = matrix.OffsetX * this._m11 + matrix.OffsetY * this._m21 + this._offsetX;
230                         _offsetY = matrix.OffsetX * this._m12 + matrix.OffsetY * this._m22 + this._offsetY;
231
232                         this._m11 = _m11;
233                         this._m12 = _m12;
234                         this._m21 = _m21;
235                         this._m22 = _m22;
236                         this._offsetX = _offsetX;
237                         this._offsetY = _offsetY;
238                 }
239
240                 public void Rotate (double angle)
241                 {
242                         // R_theta==[costheta -sintheta; sintheta costheta],    
243                         double theta = angle * Math.PI / 180;
244
245                         Matrix r_theta = new Matrix (Math.Cos (theta), Math.Sin(theta),
246                                                      -Math.Sin (theta), Math.Cos(theta),
247                                                      0, 0);
248
249                         Append (r_theta);
250                 }
251
252                 public void RotateAt (double angle,
253                                       double centerX,
254                                       double centerY)
255                 {
256                         Translate (-centerX, -centerY);
257                         Rotate (angle);
258                         Translate (centerX, centerY);
259                 }
260
261                 public void RotateAtPrepend (double angle,
262                                              double centerX,
263                                              double centerY)
264                 {
265                         Matrix m = Matrix.Identity;
266                         m.RotateAt (angle, centerX, centerY);
267                         Prepend (m);
268                 }
269
270                 public void RotatePrepend (double angle)
271                 {
272                         Matrix m = Matrix.Identity;
273                         m.Rotate (angle);
274                         Prepend (m);
275                 }
276
277                 public void Scale (double scaleX,
278                                    double scaleY)
279                 {
280                         Matrix scale = new Matrix (scaleX, 0,
281                                                    0, scaleY,
282                                                    0, 0);
283
284                         Append (scale);
285                 }
286
287                 public void ScaleAt (double scaleX,
288                                      double scaleY,
289                                      double centerX,
290                                      double centerY)
291                 {
292                         Translate (-centerX, -centerY);
293                         Scale (scaleX, scaleY);
294                         Translate (centerX, centerY);
295                 }
296
297                 public void ScaleAtPrepend (double scaleX,
298                                             double scaleY,
299                                             double centerX,
300                                             double centerY)
301                 {
302                         Matrix m = Matrix.Identity;
303                         m.ScaleAt (scaleX, scaleY, centerX, centerY);
304                         Prepend (m);
305                 }
306
307                 public void ScalePrepend (double scaleX,
308                                           double scaleY)
309                 {
310                         Matrix m = Matrix.Identity;
311                         m.Scale (scaleX, scaleY);
312                         Prepend (m);
313                 }
314
315                 public void SetIdentity ()
316                 {
317                         _m11 = _m22 = 1.0;
318                         _m12 = _m21 = 0.0;
319                         _offsetX = _offsetY = 0.0;
320                 }
321
322                 public void Skew (double skewX,
323                                   double skewY)
324                 {
325                         Matrix skew_m = new Matrix (1, Math.Tan (skewY * Math.PI / 180),
326                                                     Math.Tan (skewX * Math.PI / 180), 1,
327                                                     0, 0);
328                         Append (skew_m);
329                 }
330
331                 public void SkewPrepend (double skewX,
332                                          double skewY)
333                 {
334                         Matrix m = Matrix.Identity;
335                         m.Skew (skewX, skewY);
336                         Prepend (m);
337                 }
338
339                 string IFormattable.ToString (string format,
340                                               IFormatProvider provider)
341                 {
342                         return ToString (provider);
343                 }
344
345                 public override string ToString ()
346                 {
347                         return ToString (null);
348                 }
349
350                 public string ToString (IFormatProvider provider)
351                 {
352                         return IsIdentity
353                                 ? "Identity"
354                                 : string.Concat (_m11, ",", _m12, ",", _m21, ",", _m22, ",", _offsetX, ",", _offsetY);
355                 }
356
357                 public Point Transform (Point point)
358                 {
359                         return Point.Multiply (point, this);
360                 }
361
362                 public void Transform (Point[] points)
363                 {
364                         for (int i = 0; i < points.Length; i ++)
365                                 points[i] = Transform (points[i]);
366                 }
367
368                 public Vector Transform (Vector vector)
369                 {
370                         return Vector.Multiply (vector, this);
371                 }
372
373                 public void Transform (Vector[] vectors)
374                 {
375                         for (int i = 0; i < vectors.Length; i ++)
376                                 vectors[i] = Transform (vectors[i]);
377                 }
378
379                 public void Translate (double offsetX,
380                                        double offsetY)
381                 {
382                         this._offsetX += offsetX;
383                         this._offsetY += offsetY;
384                 }
385
386                 public void TranslatePrepend (double offsetX,
387                                               double offsetY)
388                 {
389                         Matrix m = Matrix.Identity;
390                         m.Translate (offsetX, offsetY);
391                         Prepend (m);
392                 }
393
394                 public double Determinant {
395                         get { return _m11 * _m22 - _m12 * _m21; }
396                 }
397
398                 public bool HasInverse {
399                         get { return Determinant != 0; }
400                 }
401
402                 public static Matrix Identity {
403                         get { return new Matrix (1.0, 0.0, 0.0, 1.0, 0.0, 0.0); }
404                 }
405
406                 public bool IsIdentity {
407                         get { return Equals (Matrix.Identity); }
408                 }
409
410                 public double M11 { 
411                         get { return _m11; }
412                         set { _m11 = value; }
413                 }
414                 public double M12 { 
415                         get { return _m12; }
416                         set { _m12 = value; }
417                 }
418                 public double M21 { 
419                         get { return _m21; }
420                         set { _m21 = value; }
421                 }
422                 public double M22 { 
423                         get { return _m22; }
424                         set { _m22 = value; }
425                 }
426                 public double OffsetX { 
427                         get { return _offsetX; }
428                         set { _offsetX = value; }
429                 }
430                 public double OffsetY { 
431                         get { return _offsetY; }
432                         set { _offsetY = value; }
433                 }
434         }
435
436 }