Matrix.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / System / Windows / Media / Matrix.cs / 1305600 / Matrix.cs

                            //------------------------------------------------------------------------------ 
//  Microsoft Avalon
//  Copyright (c) Microsoft Corporation, 2001, 2002
//
//  File: Matrix.cs 
//-----------------------------------------------------------------------------
using System; 
using System.Diagnostics; 
using System.ComponentModel;
using System.ComponentModel.Design.Serialization; 
using System.Reflection;
using MS.Internal;
using System.Text;
using System.Collections; 
using System.Globalization;
using System.Windows; 
using System.Windows.Media; 
using System.Runtime.InteropServices;
using System.Security; 
using System.Security.Permissions;
using SR=MS.Internal.WindowsBase.SR;
using SRID=MS.Internal.WindowsBase.SRID;
 
// IMPORTANT
// 
// Rules for using matrix types. 
//
//    internal enum MatrixTypes 
//    {
//        TRANSFORM_IS_IDENTITY    = 0,
//        TRANSFORM_IS_TRANSLATION = 1,
//        TRANSFORM_IS_SCALING     = 2, 
//        TRANSFORM_IS_UNKNOWN     = 4
//    } 
// 
// 1. Matrix type must be one of 0, 1, 2, 4, or 3 (for scale and translation)
// 2. Matrix types are true but not exact!  (E.G. A scale or identity transform could be marked as unknown or scale+translate.) 
// 3. Therefore read-only operations can ignore the type with one exception
//      EXCEPTION: A matrix tagged identity might have any coefficients instead of 1,0,0,1,0,0
//                 This is the (now) classic no default constructor for structs issue
// 4. Matrix._type must be maintained by mutation operations 
// 5. MS.Internal.MatrixUtil uses unsafe code to access the private members of Matrix including _type.
// 
// In Jan 2005 the matrix types were changed from being EXACT (i.e. a 
// scale matrix is always tagged as a scale and not something more
// general.)  This resulted in about a 2% speed up in matrix 
// multiplication.
//
// The special cases for matrix multiplication speed up scale*scale
// and translation*translation by 30% compared to a single "no-branch" 
// multiplication algorithm.  Matrix multiplication of two unknown
// matrices is slowed by 20% compared to the no-branch algorithm. 
// 
// windows/wcp/DevTest/Drts/MediaApi/MediaPerf.cs includes the
// simple test of matrix multiplication speed used for these results. 

namespace System.Windows.Media
{
    /// 
    /// Matrix
    /// 
    public partial struct Matrix: IFormattable 
    {
        // the transform is identity by default 
        // Actually fill in the fields - some (internal) code uses the fields directly for perf.
        private static Matrix s_identity = CreateIdentity();

#region Constructor 

        ///  
        /// Creates a matrix of the form 
        ///             / m11, m12, 0 \
        ///             | m21, m22, 0 | 
        ///             \ offsetX, offsetY, 1 /
        /// 
        public Matrix(double m11, double m12,
                      double m21, double m22, 
                      double offsetX, double offsetY)
        { 
            this._m11 = m11; 
            this._m12 = m12;
            this._m21 = m21; 
            this._m22 = m22;
            this._offsetX = offsetX;
            this._offsetY = offsetY;
            _type = MatrixTypes.TRANSFORM_IS_UNKNOWN; 
            _padding = 0;
 
            // We will detect EXACT identity, scale, translation or 
            // scale+translation and use special case algorithms.
            DeriveMatrixType(); 
        }

#endregion Constructor
 
#region Identity
 
        ///  
        /// Identity
        ///  
        public static Matrix Identity
        {
            get
            { 
                return s_identity;
            } 
        } 

        ///  
        /// Sets the matrix to identity.
        /// 
        public void SetIdentity()
        { 
            _type = MatrixTypes.TRANSFORM_IS_IDENTITY;
        } 
 
        /// 
        /// Tests whether or not a given transform is an identity transform 
        /// 
        public bool IsIdentity
        {
            get 
            {
                return (_type == MatrixTypes.TRANSFORM_IS_IDENTITY || 
                        (_m11 == 1 && _m12 == 0 && _m21 == 0 && _m22 == 1 && _offsetX == 0 && _offsetY == 0)); 
            }
        } 

#endregion Identity

#region Operators 
        /// 
        /// Multiplies two transformations. 
        ///  
        public static Matrix operator *(Matrix trans1, Matrix trans2)
        { 
            MatrixUtil.MultiplyMatrix(ref trans1, ref trans2);
            trans1.Debug_CheckType();
            return trans1;
        } 

        ///  
        /// Multiply 
        /// 
        public static Matrix Multiply(Matrix trans1, Matrix trans2) 
        {
            MatrixUtil.MultiplyMatrix(ref trans1, ref trans2);
            trans1.Debug_CheckType();
            return trans1; 
        }
 
#endregion Operators 

#region Combine Methods 

        /// 
        /// Append - "this" becomes this * matrix, the same as this *= matrix.
        ///  
        ///  The Matrix to append to this Matrix 
        public void Append(Matrix matrix) 
        { 
            this *= matrix;
        } 

        /// 
        /// Prepend - "this" becomes matrix * this, the same as this = matrix * this.
        ///  
        ///  The Matrix to prepend to this Matrix 
        public void Prepend(Matrix matrix) 
        { 
            this = matrix * this;
        } 

        /// 
        /// Rotates this matrix about the origin
        ///  
        /// The angle to rotate specifed in degrees
        public void Rotate(double angle) 
        { 
            angle %= 360.0; // Doing the modulo before converting to radians reduces total error
            this *= CreateRotationRadians(angle * (Math.PI/180.0)); 
        }

        /// 
        /// Prepends a rotation about the origin to "this" 
        /// 
        /// The angle to rotate specifed in degrees 
        public void RotatePrepend(double angle) 
        {
            angle %= 360.0; // Doing the modulo before converting to radians reduces total error 
            this = CreateRotationRadians(angle * (Math.PI/180.0)) * this;
        }

        ///  
        /// Rotates this matrix about the given point
        ///  
        /// The angle to rotate specifed in degrees 
        /// The centerX of rotation
        /// The centerY of rotation 
        public void RotateAt(double angle, double centerX, double centerY)
        {
            angle %= 360.0; // Doing the modulo before converting to radians reduces total error
            this *= CreateRotationRadians(angle * (Math.PI/180.0), centerX, centerY); 
        }
 
        ///  
        /// Prepends a rotation about the given point to "this"
        ///  
        /// The angle to rotate specifed in degrees
        /// The centerX of rotation
        /// The centerY of rotation
        public void RotateAtPrepend(double angle, double centerX, double centerY) 
        {
            angle %= 360.0; // Doing the modulo before converting to radians reduces total error 
            this = CreateRotationRadians(angle * (Math.PI/180.0), centerX, centerY) * this; 
        }
 
        /// 
        /// Scales this matrix around the origin
        /// 
        /// The scale factor in the x dimension 
        /// The scale factor in the y dimension
        public void Scale(double scaleX, double scaleY) 
        { 
            this *= CreateScaling(scaleX, scaleY);
        } 

        /// 
        /// Prepends a scale around the origin to "this"
        ///  
        /// The scale factor in the x dimension
        /// The scale factor in the y dimension 
        public void ScalePrepend(double scaleX, double scaleY) 
        {
            this = CreateScaling(scaleX, scaleY) * this; 
        }

        /// 
        /// Scales this matrix around the center provided 
        /// 
        /// The scale factor in the x dimension 
        /// The scale factor in the y dimension 
        /// The centerX about which to scale
        /// The centerY about which to scale 
        public void ScaleAt(double scaleX, double scaleY, double centerX, double centerY)
        {
            this *= CreateScaling(scaleX, scaleY, centerX, centerY);
        } 

        ///  
        /// Prepends a scale around the center provided to "this" 
        /// 
        /// The scale factor in the x dimension 
        /// The scale factor in the y dimension
        /// The centerX about which to scale
        /// The centerY about which to scale
        public void ScaleAtPrepend(double scaleX, double scaleY, double centerX, double centerY) 
        {
            this = CreateScaling(scaleX, scaleY, centerX, centerY) * this; 
        } 

        ///  
        /// Skews this matrix
        /// 
        /// The skew angle in the x dimension in degrees
        /// The skew angle in the y dimension in degrees 
        public void Skew(double skewX, double skewY)
        { 
            skewX %= 360; 
            skewY %= 360;
            this *= CreateSkewRadians(skewX * (Math.PI/180.0), 
                                      skewY * (Math.PI/180.0));
        }

        ///  
        /// Prepends a skew to this matrix
        ///  
        /// The skew angle in the x dimension in degrees 
        /// The skew angle in the y dimension in degrees
        public void SkewPrepend(double skewX, double skewY) 
        {
            skewX %= 360;
            skewY %= 360;
            this = CreateSkewRadians(skewX * (Math.PI/180.0), 
                                     skewY * (Math.PI/180.0)) * this;
        } 
 
        /// 
        /// Translates this matrix 
        /// 
        /// The offset in the x dimension
        /// The offset in the y dimension
        public void Translate(double offsetX, double offsetY) 
        {
            // 
            // / a b 0 \   / 1 0 0 \    / a      b       0 \ 
            // | c d 0 | * | 0 1 0 | = |  c      d       0 |
            // \ e f 1 /   \ x y 1 /    \ e+x    f+y     1 / 
            //
            // (where e = _offsetX and f == _offsetY)
            //
 
            if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY)
            { 
                // Values would be incorrect if matrix was created using default constructor. 
                // or if SetIdentity was called on a matrix which had values.
                // 
                SetMatrix(1, 0,
                          0, 1,
                          offsetX, offsetY,
                          MatrixTypes.TRANSFORM_IS_TRANSLATION); 
            }
            else if (_type == MatrixTypes.TRANSFORM_IS_UNKNOWN) 
            { 
                _offsetX += offsetX;
                _offsetY += offsetY; 
            }
            else
            {
                _offsetX += offsetX; 
                _offsetY += offsetY;
 
                // If matrix wasn't unknown we added a translation 
                _type |= MatrixTypes.TRANSFORM_IS_TRANSLATION;
            } 

            Debug_CheckType();
        }
 
        /// 
        /// Prepends a translation to this matrix 
        ///  
        /// The offset in the x dimension
        /// The offset in the y dimension 
        public void TranslatePrepend(double offsetX, double offsetY)
        {
            this = CreateTranslation(offsetX, offsetY) * this;
        } 

#endregion Set Methods 
 
#region Transformation Services
 
        /// 
        /// Transform - returns the result of transforming the point by this matrix
        /// 
        ///  
        /// The transformed point
        ///  
        ///  The Point to transform  
        public Point Transform(Point point)
        { 
            Point newPoint = point;
            MultiplyPoint(ref newPoint._x, ref newPoint._y);
            return newPoint;
        } 

        ///  
        /// Transform - Transforms each point in the array by this matrix 
        /// 
        ///  The Point array to transform  
        public void Transform(Point[] points)
        {
            if (points != null)
            { 
                for (int i = 0; i < points.Length; i++)
                { 
                    MultiplyPoint(ref points[i]._x, ref points[i]._y); 
                }
            } 
        }

        /// 
        /// Transform - returns the result of transforming the Vector by this matrix. 
        /// 
        ///  
        /// The transformed vector 
        /// 
        ///  The Vector to transform  
        public Vector Transform(Vector vector)
        {
            Vector newVector = vector;
            MultiplyVector(ref newVector._x, ref newVector._y); 
            return newVector;
        } 
 
        /// 
        /// Transform - Transforms each Vector in the array by this matrix. 
        /// 
        ///  The Vector array to transform 
        public void Transform(Vector[] vectors)
        { 
            if (vectors != null)
            { 
                for (int i = 0; i < vectors.Length; i++) 
                {
                    MultiplyVector(ref vectors[i]._x, ref vectors[i]._y); 
                }
            }
        }
 
#endregion Transformation Services
 
#region Inversion 

        ///  
        /// The determinant of this matrix
        /// 
        public double Determinant
        { 
            get
            { 
                switch (_type) 
                {
                case MatrixTypes.TRANSFORM_IS_IDENTITY: 
                case MatrixTypes.TRANSFORM_IS_TRANSLATION:
                    return 1.0;
                case MatrixTypes.TRANSFORM_IS_SCALING:
                case MatrixTypes.TRANSFORM_IS_SCALING | MatrixTypes.TRANSFORM_IS_TRANSLATION: 
                    return(_m11  * _m22);
                default: 
                    return(_m11  * _m22) - (_m12 * _m21); 
                }
            } 
        }

        /// 
        /// HasInverse Property - returns true if this matrix is invertable, false otherwise. 
        /// 
        public bool HasInverse 
        { 
            get
            { 
                return !DoubleUtil.IsZero(Determinant);
            }
        }
 
        /// 
        /// Replaces matrix with the inverse of the transformation.  This will throw an InvalidOperationException 
        /// if !HasInverse 
        /// 
        ///  
        /// This will throw an InvalidOperationException if the matrix is non-invertable
        /// 
        public void Invert()
        { 
            double determinant = Determinant;
 
            if (DoubleUtil.IsZero(determinant)) 
            {
                throw new System.InvalidOperationException(SR.Get(SRID.Transform_NotInvertible)); 
            }

            // Inversion does not change the type of a matrix.
            switch (_type) 
            {
            case MatrixTypes.TRANSFORM_IS_IDENTITY: 
                break; 
            case MatrixTypes.TRANSFORM_IS_SCALING:
                { 
                    _m11 = 1.0 / _m11;
                    _m22 = 1.0 / _m22;
                }
                break; 
            case MatrixTypes.TRANSFORM_IS_TRANSLATION:
                _offsetX = -_offsetX; 
                _offsetY = -_offsetY; 
                break;
            case MatrixTypes.TRANSFORM_IS_SCALING | MatrixTypes.TRANSFORM_IS_TRANSLATION: 
                {
                    _m11 = 1.0 / _m11;
                    _m22 = 1.0 / _m22;
                    _offsetX = -_offsetX * _m11; 
                    _offsetY = -_offsetY * _m22;
                } 
                break; 
            default:
                { 
                    double invdet = 1.0/determinant;
                    SetMatrix(_m22 * invdet,
                              -_m12 * invdet,
                              -_m21 * invdet, 
                              _m11 * invdet,
                              (_m21 * _offsetY - _offsetX * _m22) * invdet, 
                              (_offsetX * _m12 - _m11 * _offsetY) * invdet, 
                              MatrixTypes.TRANSFORM_IS_UNKNOWN);
                } 
                break;
            }
        }
 
#endregion Inversion
 
#region Public Properties 

        ///  
        /// M11
        /// 
        public double M11
        { 
            get
            { 
                if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY) 
                {
                    return 1.0; 
                }
                else
                {
                    return _m11; 
                }
            } 
            set 
            {
                if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY) 
                {
                    SetMatrix(value, 0,
                              0, 1,
                              0, 0, 
                              MatrixTypes.TRANSFORM_IS_SCALING);
                } 
                else 
                {
                    _m11 = value; 
                    if (_type != MatrixTypes.TRANSFORM_IS_UNKNOWN)
                    {
                        _type |= MatrixTypes.TRANSFORM_IS_SCALING;
                    } 
                }
            } 
        } 

        ///  
        /// M12
        /// 
        public double M12
        { 
            get
            { 
                if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY) 
                {
                    return 0; 
                }
                else
                {
                    return _m12; 
                }
            } 
            set 
            {
                if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY) 
                {
                    SetMatrix(1, value,
                              0, 1,
                              0, 0, 
                              MatrixTypes.TRANSFORM_IS_UNKNOWN);
                } 
                else 
                {
                    _m12 = value; 
                    _type = MatrixTypes.TRANSFORM_IS_UNKNOWN;
                }
            }
        } 

        ///  
        /// M22 
        /// 
        public double M21 
        {
            get
            {
                if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY) 
                {
                    return 0; 
                } 
                else
                { 
                    return _m21;
                }
            }
            set 
            {
                if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY) 
                { 
                    SetMatrix(1, 0,
                              value, 1, 
                              0, 0,
                              MatrixTypes.TRANSFORM_IS_UNKNOWN);
                }
                else 
                {
                    _m21 = value; 
                    _type = MatrixTypes.TRANSFORM_IS_UNKNOWN; 
                }
            } 
        }

        /// 
        /// M22 
        /// 
        public double M22 
        { 
            get
            { 
                if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY)
                {
                    return 1.0;
                } 
                else
                { 
                    return _m22; 
                }
            } 
            set
            {
                if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY)
                { 
                    SetMatrix(1, 0,
                              0, value, 
                              0, 0, 
                              MatrixTypes.TRANSFORM_IS_SCALING);
                } 
                else
                {
                    _m22 = value;
                    if (_type != MatrixTypes.TRANSFORM_IS_UNKNOWN) 
                    {
                        _type |= MatrixTypes.TRANSFORM_IS_SCALING; 
                    } 
                }
            } 
        }

        /// 
        /// OffsetX 
        /// 
        public double OffsetX 
        { 
            get
            { 
                if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY)
                {
                    return 0;
                } 
                else
                { 
                    return _offsetX; 
                }
            } 
            set
            {
                if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY)
                { 
                    SetMatrix(1, 0,
                              0, 1, 
                              value, 0, 
                              MatrixTypes.TRANSFORM_IS_TRANSLATION);
                } 
                else
                {
                    _offsetX = value;
                    if (_type != MatrixTypes.TRANSFORM_IS_UNKNOWN) 
                    {
                        _type |= MatrixTypes.TRANSFORM_IS_TRANSLATION; 
                    } 
                }
            } 
        }

        /// 
        /// OffsetY 
        /// 
        public double OffsetY 
        { 
            get
            { 
                if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY)
                {
                    return 0;
                } 
                else
                { 
                    return _offsetY; 
                }
            } 
            set
            {
                if (_type == MatrixTypes.TRANSFORM_IS_IDENTITY)
                { 
                    SetMatrix(1, 0,
                              0, 1, 
                              0, value, 
                              MatrixTypes.TRANSFORM_IS_TRANSLATION);
                } 
                else
                {
                    _offsetY = value;
                    if (_type != MatrixTypes.TRANSFORM_IS_UNKNOWN) 
                    {
                        _type |= MatrixTypes.TRANSFORM_IS_TRANSLATION; 
                    } 
                }
            } 
        }

        #endregion Public Properties
 
        #region Internal Methods
        ///  
        /// MultiplyVector 
        /// 
        internal void MultiplyVector(ref double x, ref double y) 
        {
            switch (_type)
            {
            case MatrixTypes.TRANSFORM_IS_IDENTITY: 
            case MatrixTypes.TRANSFORM_IS_TRANSLATION:
                return; 
            case MatrixTypes.TRANSFORM_IS_SCALING: 
            case MatrixTypes.TRANSFORM_IS_SCALING | MatrixTypes.TRANSFORM_IS_TRANSLATION:
                x *= _m11; 
                y *= _m22;
                break;
            default:
                double xadd = y * _m21; 
                double yadd = x * _m12;
                x *= _m11; 
                x += xadd; 
                y *= _m22;
                y += yadd; 
                break;
            }
        }
 
        /// 
        /// MultiplyPoint 
        ///  
        internal void MultiplyPoint(ref double x, ref double y)
        { 
            switch (_type)
            {
            case MatrixTypes.TRANSFORM_IS_IDENTITY:
                return; 
            case MatrixTypes.TRANSFORM_IS_TRANSLATION:
                x += _offsetX; 
                y += _offsetY; 
                return;
            case MatrixTypes.TRANSFORM_IS_SCALING: 
                x *= _m11;
                y *= _m22;
                return;
            case MatrixTypes.TRANSFORM_IS_SCALING | MatrixTypes.TRANSFORM_IS_TRANSLATION: 
                x *= _m11;
                x += _offsetX; 
                y *= _m22; 
                y += _offsetY;
                break; 
            default:
                double xadd = y * _m21 + _offsetX;
                double yadd = x * _m12 + _offsetY;
                x *= _m11; 
                x += xadd;
                y *= _m22; 
                y += yadd; 
                break;
            } 
        }

        /// 
        /// Creates a rotation transformation about the given point 
        /// 
        /// The angle to rotate specifed in radians 
        internal static Matrix CreateRotationRadians(double angle) 
        {
            return CreateRotationRadians(angle, /* centerX = */ 0, /* centerY = */ 0); 
        }

        /// 
        /// Creates a rotation transformation about the given point 
        /// 
        /// The angle to rotate specifed in radians 
        /// The centerX of rotation 
        /// The centerY of rotation
        internal static Matrix CreateRotationRadians(double angle, double centerX, double centerY) 
        {
            Matrix matrix = new Matrix();

            double sin = Math.Sin(angle); 
            double cos = Math.Cos(angle);
            double dx    = (centerX * (1.0 - cos)) + (centerY * sin); 
            double dy    = (centerY * (1.0 - cos)) - (centerX * sin); 

            matrix.SetMatrix( cos, sin, 
                              -sin, cos,
                              dx,    dy,
                              MatrixTypes.TRANSFORM_IS_UNKNOWN);
 
            return matrix;
        } 
 
        /// 
        /// Creates a scaling transform around the given point 
        /// 
        /// The scale factor in the x dimension
        /// The scale factor in the y dimension
        /// The centerX of scaling 
        /// The centerY of scaling
        internal static Matrix CreateScaling(double scaleX, double scaleY, double centerX, double centerY) 
        { 
            Matrix matrix = new Matrix();
 
            matrix.SetMatrix(scaleX,  0,
                             0, scaleY,
                             centerX - scaleX*centerX, centerY - scaleY*centerY,
                             MatrixTypes.TRANSFORM_IS_SCALING | MatrixTypes.TRANSFORM_IS_TRANSLATION); 

            return matrix; 
        } 

        ///  
        /// Creates a scaling transform around the origin
        /// 
        /// The scale factor in the x dimension
        /// The scale factor in the y dimension 
        internal static Matrix CreateScaling(double scaleX, double scaleY)
        { 
            Matrix matrix = new Matrix(); 
            matrix.SetMatrix(scaleX,  0,
                             0, scaleY, 
                             0, 0,
                             MatrixTypes.TRANSFORM_IS_SCALING);
            return matrix;
        } 

        ///  
        /// Creates a skew transform 
        /// 
        /// The skew angle in the x dimension in degrees 
        /// The skew angle in the y dimension in degrees
        internal static Matrix CreateSkewRadians(double skewX, double skewY)
        {
            Matrix matrix = new Matrix(); 

            matrix.SetMatrix(1.0,  Math.Tan(skewY), 
                             Math.Tan(skewX), 1.0, 
                             0.0, 0.0,
                             MatrixTypes.TRANSFORM_IS_UNKNOWN); 

            return matrix;
        }
 
        /// 
        /// Sets the transformation to the given translation specified by the offset vector. 
        ///  
        /// The offset in X
        /// The offset in Y 
        internal static Matrix CreateTranslation(double offsetX, double offsetY)
        {
            Matrix matrix = new Matrix();
 
            matrix.SetMatrix(1, 0,
                             0, 1, 
                             offsetX, offsetY, 
                             MatrixTypes.TRANSFORM_IS_TRANSLATION);
 
            return matrix;
        }

#endregion Internal Methods 

#region Private Methods 
        ///  
        /// Sets the transformation to the identity.
        ///  
        private static Matrix CreateIdentity()
        {
            Matrix matrix = new Matrix();
            matrix.SetMatrix(1, 0, 
                             0, 1,
                             0, 0, 
                             MatrixTypes.TRANSFORM_IS_IDENTITY); 
            return matrix;
        } 

        ///
        /// Sets the transform to
        ///             / m11, m12, 0 \ 
        ///             | m21, m22, 0 |
        ///             \ offsetX, offsetY, 1 / 
        /// where offsetX, offsetY is the translation. 
        ///
        private void SetMatrix(double m11, double m12, 
                               double m21, double m22,
                               double offsetX, double offsetY,
                               MatrixTypes type)
        { 
            this._m11 = m11;
            this._m12 = m12; 
            this._m21 = m21; 
            this._m22 = m22;
            this._offsetX = offsetX; 
            this._offsetY = offsetY;
            this._type = type;
        }
 
        /// 
        /// Set the type of the matrix based on its current contents 
        ///  
        private void DeriveMatrixType()
        { 
            _type = 0;

            // Now classify our matrix.
            if (!(_m21 == 0 && _m12 == 0)) 
            {
                _type = MatrixTypes.TRANSFORM_IS_UNKNOWN; 
                return; 
            }
 
            if (!(_m11 == 1 && _m22 == 1))
            {
                _type = MatrixTypes.TRANSFORM_IS_SCALING;
            } 

            if (!(_offsetX == 0 && _offsetY == 0)) 
            { 
                _type |= MatrixTypes.TRANSFORM_IS_TRANSLATION;
            } 

            if (0 == (_type & (MatrixTypes.TRANSFORM_IS_TRANSLATION | MatrixTypes.TRANSFORM_IS_SCALING)))
            {
                // We have an identity matrix. 
                _type = MatrixTypes.TRANSFORM_IS_IDENTITY;
            } 
            return; 
        }
 
        /// 
        /// Asserts that the matrix tag is one of the valid options and
        /// that coefficients are correct.
        ///  
        [Conditional("DEBUG")]
        private void Debug_CheckType() 
        { 
            switch(_type)
            { 
            case MatrixTypes.TRANSFORM_IS_IDENTITY:
                return;
            case MatrixTypes.TRANSFORM_IS_UNKNOWN:
                return; 
            case MatrixTypes.TRANSFORM_IS_SCALING:
                Debug.Assert(_m21 == 0); 
                Debug.Assert(_m12 == 0); 
                Debug.Assert(_offsetX == 0);
                Debug.Assert(_offsetY == 0); 
                return;
            case MatrixTypes.TRANSFORM_IS_TRANSLATION:
                Debug.Assert(_m21 == 0);
                Debug.Assert(_m12 == 0); 
                Debug.Assert(_m11 == 1);
                Debug.Assert(_m22 == 1); 
                return; 
            case MatrixTypes.TRANSFORM_IS_SCALING|MatrixTypes.TRANSFORM_IS_TRANSLATION:
                Debug.Assert(_m21 == 0); 
                Debug.Assert(_m12 == 0);
                return;
            default:
                Debug.Assert(false); 
                return;
            } 
        } 

#endregion Private Methods 

#region Private Properties and Fields

        ///  
        /// Efficient but conservative test for identity.  Returns
        /// true if the the matrix is identity.  If it returns false 
        /// the matrix may still be identity. 
        /// 
        private bool IsDistinguishedIdentity 
        {
            get
            {
                return _type == MatrixTypes.TRANSFORM_IS_IDENTITY; 
            }
        } 
 
        // The hash code for a matrix is the xor of its element's hashes.
        // Since the identity matrix has 2 1's and 4 0's its hash is 0. 
        private const int c_identityHashCode = 0;

#endregion Private Properties and Fields
 
        internal double _m11;
        internal double _m12; 
        internal double _m21; 
        internal double _m22;
        internal double _offsetX; 
        internal double _offsetY;
        internal MatrixTypes _type;

// This field is only used by unmanaged code which isn't detected by the compiler. 
#pragma warning disable 0414
        // Matrix in blt'd to unmanaged code, so this is padding 
        // to align structure. 
        //
        // ToDo: [....], Validate that this blt will work on 64-bit 
        //
        internal Int32 _padding;
#pragma warning restore 0414
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK