MatrixUtil.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Shared / MS / Internal / MatrixUtil.cs / 1 / MatrixUtil.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: MatrixUtil.cs 
//
// Description: This file contains the implementation of MatrixUtil, which 
//              provides matrix multiply code. 
//
// History: 
//  01/06/2004 : adsmith - Created, most copied from wcp\core\system\windows\media\milutilities.cs
//
//---------------------------------------------------------------------------
 
using System;
using System.Windows; 
using System.Windows.Media; 
using System.Diagnostics;
using System.Security; 
using System.Security.Permissions;
#if WINDOWS_BASE
    using MS.Internal.WindowsBase;
#elif PRESENTATION_CORE 
    using MS.Internal.PresentationCore;
#elif PRESENTATIONFRAMEWORK 
    using MS.Internal.PresentationFramework; 
#elif DRT
    using MS.Internal.Drt; 
#else
#error Attempt to use FriendAccessAllowedAttribute from an unknown assembly.
using MS.Internal.YourAssemblyName;
#endif 

namespace MS.Internal 
{ 
    // MatrixTypes
    [System.Flags] 
    internal enum MatrixTypes
    {
        TRANSFORM_IS_IDENTITY = 0,
        TRANSFORM_IS_TRANSLATION = 1, 
        TRANSFORM_IS_SCALING     = 2,
        TRANSFORM_IS_UNKNOWN     = 4 
    } 

    [FriendAccessAllowed] 
    internal static class MatrixUtil
    {
        /// 
        /// TransformRect - Internal helper for perf 
        /// 
        ///  The Rect to transform.  
        ///  The Matrix with which to transform the Rect.  
        internal static void TransformRect(ref Rect rect, ref Matrix matrix)
        { 
            if (rect.IsEmpty)
            {
                return;
            } 

            MatrixTypes matrixType = matrix._type; 
 
            // If the matrix is identity, don't worry.
            if (matrixType == MatrixTypes.TRANSFORM_IS_IDENTITY) 
            {
                return;
            }
 
            // Scaling
            if (0 != (matrixType & MatrixTypes.TRANSFORM_IS_SCALING)) 
            { 
                rect._x *= matrix._m11;
                rect._y *= matrix._m22; 
                rect._width *= matrix._m11;
                rect._height *= matrix._m22;

                // Ensure the width is always positive.  For example, if there was a reflection about the 
                // y axis followed by a translation into the visual area, the width could be negative.
                if (rect._width < 0.0) 
                { 
                    rect._x += rect._width;
                    rect._width = -rect._width; 
                }

                // Ensure the height is always positive.  For example, if there was a reflection about the
                // x axis followed by a translation into the visual area, the height could be negative. 
                if (rect._height < 0.0)
                { 
                    rect._y += rect._height; 
                    rect._height = -rect._height;
                } 
            }

            // Translation
            if (0 != (matrixType & MatrixTypes.TRANSFORM_IS_TRANSLATION)) 
            {
                // X 
                rect._x += matrix._offsetX; 

                // Y 
                rect._y += matrix._offsetY;
            }

            if (matrixType == MatrixTypes.TRANSFORM_IS_UNKNOWN) 
            {
                // Al Bunny implementation. 
                Point point0 = matrix.Transform(rect.TopLeft); 
                Point point1 = matrix.Transform(rect.TopRight);
                Point point2 = matrix.Transform(rect.BottomRight); 
                Point point3 = matrix.Transform(rect.BottomLeft);

                // Width and height is always positive here.
                rect._x = Math.Min(Math.Min(point0.X, point1.X), Math.Min(point2.X, point3.X)); 
                rect._y = Math.Min(Math.Min(point0.Y, point1.Y), Math.Min(point2.Y, point3.Y));
 
                rect._width = Math.Max(Math.Max(point0.X, point1.X), Math.Max(point2.X, point3.X)) - rect._x; 
                rect._height = Math.Max(Math.Max(point0.Y, point1.Y), Math.Max(point2.Y, point3.Y)) - rect._y;
            } 
        }

        /// 
        /// Multiplies two transformations, where the behavior is matrix1 *= matrix2. 
        /// This code exists so that we can efficient combine matrices without copying
        /// the data around, since each matrix is 52 bytes. 
        /// To reduce duplication and to ensure consistent behavior, this is the 
        /// method which is used to implement Matrix * Matrix as well.
        ///  
        internal static void MultiplyMatrix(ref Matrix matrix1, ref Matrix matrix2)
        {
            MatrixTypes type1 = matrix1._type;
            MatrixTypes type2 = matrix2._type; 

            // Check for idents 
 
            // If the second is ident, we can just return
            if (type2 == MatrixTypes.TRANSFORM_IS_IDENTITY) 
            {
                return;
            }
 
            // If the first is ident, we can just copy the memory across.
            if (type1 == MatrixTypes.TRANSFORM_IS_IDENTITY) 
            { 
                matrix1 = matrix2;
                return; 
            }

            // Optimize for translate case, where the second is a translate
            if (type2 == MatrixTypes.TRANSFORM_IS_TRANSLATION) 
            {
                // 2 additions 
                matrix1._offsetX += matrix2._offsetX; 
                matrix1._offsetY += matrix2._offsetY;
 
                // If matrix 1 wasn't unknown we added a translation
                if (type1 != MatrixTypes.TRANSFORM_IS_UNKNOWN)
                {
                    matrix1._type |= MatrixTypes.TRANSFORM_IS_TRANSLATION; 
                }
 
                return; 
            }
 
            // Check for the first value being a translate
            if (type1 == MatrixTypes.TRANSFORM_IS_TRANSLATION)
            {
                // Save off the old offsets 
                double offsetX = matrix1._offsetX;
                double offsetY = matrix1._offsetY; 
 
                // Copy the matrix
                matrix1 = matrix2; 

                matrix1._offsetX = offsetX * matrix2._m11 + offsetY * matrix2._m21 + matrix2._offsetX;
                matrix1._offsetY = offsetX * matrix2._m12 + offsetY * matrix2._m22 + matrix2._offsetY;
 
                if (type2 == MatrixTypes.TRANSFORM_IS_UNKNOWN)
                { 
                    matrix1._type = MatrixTypes.TRANSFORM_IS_UNKNOWN; 
                }
                else 
                {
                    matrix1._type = MatrixTypes.TRANSFORM_IS_SCALING | MatrixTypes.TRANSFORM_IS_TRANSLATION;
                }
                return; 
            }
 
            // The following code combines the type of the transformations so that the high nibble 
            // is "this"'s type, and the low nibble is mat's type.  This allows for a switch rather
            // than nested switches. 

            // trans1._type |  trans2._type
            //  7  6  5  4   |  3  2  1  0
            int combinedType = ((int)type1 << 4) | (int)type2; 

            switch (combinedType) 
            { 
                case 34:  // S * S
                    // 2 multiplications 
                    matrix1._m11 *= matrix2._m11;
                    matrix1._m22 *= matrix2._m22;
                    return;
 
                case 35:  // S * S|T
                    matrix1._m11 *= matrix2._m11; 
                    matrix1._m22 *= matrix2._m22; 
                    matrix1._offsetX = matrix2._offsetX;
                    matrix1._offsetY = matrix2._offsetY; 

                    // Transform set to Translate and Scale
                    matrix1._type = MatrixTypes.TRANSFORM_IS_TRANSLATION | MatrixTypes.TRANSFORM_IS_SCALING;
                    return; 

                case 50: // S|T * S 
                    matrix1._m11 *= matrix2._m11; 
                    matrix1._m22 *= matrix2._m22;
                    matrix1._offsetX *= matrix2._m11; 
                    matrix1._offsetY *= matrix2._m22;
                    return;

                case 51: // S|T * S|T 
                    matrix1._m11 *= matrix2._m11;
                    matrix1._m22 *= matrix2._m22; 
                    matrix1._offsetX = matrix2._m11 * matrix1._offsetX + matrix2._offsetX; 
                    matrix1._offsetY = matrix2._m22 * matrix1._offsetY + matrix2._offsetY;
                    return; 
                case 36: // S * U
                case 52: // S|T * U
                case 66: // U * S
                case 67: // U * S|T 
                case 68: // U * U
                    matrix1 = new Matrix( 
                        matrix1._m11 * matrix2._m11 + matrix1._m12 * matrix2._m21, 
                        matrix1._m11 * matrix2._m12 + matrix1._m12 * matrix2._m22,
 
                        matrix1._m21 * matrix2._m11 + matrix1._m22 * matrix2._m21,
                        matrix1._m21 * matrix2._m12 + matrix1._m22 * matrix2._m22,

                        matrix1._offsetX * matrix2._m11 + matrix1._offsetY * matrix2._m21 + matrix2._offsetX, 
                        matrix1._offsetX * matrix2._m12 + matrix1._offsetY * matrix2._m22 + matrix2._offsetY);
                    return; 
#if DEBUG 
            default:
                Debug.Fail("Matrix multiply hit an invalid case: " + combinedType); 
                break;
#endif
            }
        } 

        ///  
        /// Applies an offset to the specified matrix in place. 
        /// 
        internal static void PrependOffset( 
            ref Matrix matrix,
            double offsetX,
            double offsetY)
        { 
            if (matrix._type == MatrixTypes.TRANSFORM_IS_IDENTITY)
            { 
                matrix = new Matrix(1, 0, 0, 1, offsetX, offsetY); 
                matrix._type = MatrixTypes.TRANSFORM_IS_TRANSLATION;
            } 
            else
            {
                //
                //  / 1   0   0 \       / m11   m12   0 \ 
                //  | 0   1   0 |   *   | m21   m22   0 |
                //  \ tx  ty  1 /       \  ox    oy   1 / 
                // 
                //       /   m11                  m12                     0 \
                //  =    |   m21                  m22                     0 | 
                //       \   m11*tx+m21*ty+ox     m12*tx + m22*ty + oy    1 /
                //

                matrix._offsetX += matrix._m11 * offsetX + matrix._m21 * offsetY; 
                matrix._offsetY += matrix._m12 * offsetX + matrix._m22 * offsetY;
 
                // It just gained a translate if was a scale transform. Identity transform is handled above. 
                Debug.Assert(matrix._type != MatrixTypes.TRANSFORM_IS_IDENTITY);
                if (matrix._type != MatrixTypes.TRANSFORM_IS_UNKNOWN) 
                {
                    matrix._type |= MatrixTypes.TRANSFORM_IS_TRANSLATION;
                }
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: MatrixUtil.cs 
//
// Description: This file contains the implementation of MatrixUtil, which 
//              provides matrix multiply code. 
//
// History: 
//  01/06/2004 : adsmith - Created, most copied from wcp\core\system\windows\media\milutilities.cs
//
//---------------------------------------------------------------------------
 
using System;
using System.Windows; 
using System.Windows.Media; 
using System.Diagnostics;
using System.Security; 
using System.Security.Permissions;
#if WINDOWS_BASE
    using MS.Internal.WindowsBase;
#elif PRESENTATION_CORE 
    using MS.Internal.PresentationCore;
#elif PRESENTATIONFRAMEWORK 
    using MS.Internal.PresentationFramework; 
#elif DRT
    using MS.Internal.Drt; 
#else
#error Attempt to use FriendAccessAllowedAttribute from an unknown assembly.
using MS.Internal.YourAssemblyName;
#endif 

namespace MS.Internal 
{ 
    // MatrixTypes
    [System.Flags] 
    internal enum MatrixTypes
    {
        TRANSFORM_IS_IDENTITY = 0,
        TRANSFORM_IS_TRANSLATION = 1, 
        TRANSFORM_IS_SCALING     = 2,
        TRANSFORM_IS_UNKNOWN     = 4 
    } 

    [FriendAccessAllowed] 
    internal static class MatrixUtil
    {
        /// 
        /// TransformRect - Internal helper for perf 
        /// 
        ///  The Rect to transform.  
        ///  The Matrix with which to transform the Rect.  
        internal static void TransformRect(ref Rect rect, ref Matrix matrix)
        { 
            if (rect.IsEmpty)
            {
                return;
            } 

            MatrixTypes matrixType = matrix._type; 
 
            // If the matrix is identity, don't worry.
            if (matrixType == MatrixTypes.TRANSFORM_IS_IDENTITY) 
            {
                return;
            }
 
            // Scaling
            if (0 != (matrixType & MatrixTypes.TRANSFORM_IS_SCALING)) 
            { 
                rect._x *= matrix._m11;
                rect._y *= matrix._m22; 
                rect._width *= matrix._m11;
                rect._height *= matrix._m22;

                // Ensure the width is always positive.  For example, if there was a reflection about the 
                // y axis followed by a translation into the visual area, the width could be negative.
                if (rect._width < 0.0) 
                { 
                    rect._x += rect._width;
                    rect._width = -rect._width; 
                }

                // Ensure the height is always positive.  For example, if there was a reflection about the
                // x axis followed by a translation into the visual area, the height could be negative. 
                if (rect._height < 0.0)
                { 
                    rect._y += rect._height; 
                    rect._height = -rect._height;
                } 
            }

            // Translation
            if (0 != (matrixType & MatrixTypes.TRANSFORM_IS_TRANSLATION)) 
            {
                // X 
                rect._x += matrix._offsetX; 

                // Y 
                rect._y += matrix._offsetY;
            }

            if (matrixType == MatrixTypes.TRANSFORM_IS_UNKNOWN) 
            {
                // Al Bunny implementation. 
                Point point0 = matrix.Transform(rect.TopLeft); 
                Point point1 = matrix.Transform(rect.TopRight);
                Point point2 = matrix.Transform(rect.BottomRight); 
                Point point3 = matrix.Transform(rect.BottomLeft);

                // Width and height is always positive here.
                rect._x = Math.Min(Math.Min(point0.X, point1.X), Math.Min(point2.X, point3.X)); 
                rect._y = Math.Min(Math.Min(point0.Y, point1.Y), Math.Min(point2.Y, point3.Y));
 
                rect._width = Math.Max(Math.Max(point0.X, point1.X), Math.Max(point2.X, point3.X)) - rect._x; 
                rect._height = Math.Max(Math.Max(point0.Y, point1.Y), Math.Max(point2.Y, point3.Y)) - rect._y;
            } 
        }

        /// 
        /// Multiplies two transformations, where the behavior is matrix1 *= matrix2. 
        /// This code exists so that we can efficient combine matrices without copying
        /// the data around, since each matrix is 52 bytes. 
        /// To reduce duplication and to ensure consistent behavior, this is the 
        /// method which is used to implement Matrix * Matrix as well.
        ///  
        internal static void MultiplyMatrix(ref Matrix matrix1, ref Matrix matrix2)
        {
            MatrixTypes type1 = matrix1._type;
            MatrixTypes type2 = matrix2._type; 

            // Check for idents 
 
            // If the second is ident, we can just return
            if (type2 == MatrixTypes.TRANSFORM_IS_IDENTITY) 
            {
                return;
            }
 
            // If the first is ident, we can just copy the memory across.
            if (type1 == MatrixTypes.TRANSFORM_IS_IDENTITY) 
            { 
                matrix1 = matrix2;
                return; 
            }

            // Optimize for translate case, where the second is a translate
            if (type2 == MatrixTypes.TRANSFORM_IS_TRANSLATION) 
            {
                // 2 additions 
                matrix1._offsetX += matrix2._offsetX; 
                matrix1._offsetY += matrix2._offsetY;
 
                // If matrix 1 wasn't unknown we added a translation
                if (type1 != MatrixTypes.TRANSFORM_IS_UNKNOWN)
                {
                    matrix1._type |= MatrixTypes.TRANSFORM_IS_TRANSLATION; 
                }
 
                return; 
            }
 
            // Check for the first value being a translate
            if (type1 == MatrixTypes.TRANSFORM_IS_TRANSLATION)
            {
                // Save off the old offsets 
                double offsetX = matrix1._offsetX;
                double offsetY = matrix1._offsetY; 
 
                // Copy the matrix
                matrix1 = matrix2; 

                matrix1._offsetX = offsetX * matrix2._m11 + offsetY * matrix2._m21 + matrix2._offsetX;
                matrix1._offsetY = offsetX * matrix2._m12 + offsetY * matrix2._m22 + matrix2._offsetY;
 
                if (type2 == MatrixTypes.TRANSFORM_IS_UNKNOWN)
                { 
                    matrix1._type = MatrixTypes.TRANSFORM_IS_UNKNOWN; 
                }
                else 
                {
                    matrix1._type = MatrixTypes.TRANSFORM_IS_SCALING | MatrixTypes.TRANSFORM_IS_TRANSLATION;
                }
                return; 
            }
 
            // The following code combines the type of the transformations so that the high nibble 
            // is "this"'s type, and the low nibble is mat's type.  This allows for a switch rather
            // than nested switches. 

            // trans1._type |  trans2._type
            //  7  6  5  4   |  3  2  1  0
            int combinedType = ((int)type1 << 4) | (int)type2; 

            switch (combinedType) 
            { 
                case 34:  // S * S
                    // 2 multiplications 
                    matrix1._m11 *= matrix2._m11;
                    matrix1._m22 *= matrix2._m22;
                    return;
 
                case 35:  // S * S|T
                    matrix1._m11 *= matrix2._m11; 
                    matrix1._m22 *= matrix2._m22; 
                    matrix1._offsetX = matrix2._offsetX;
                    matrix1._offsetY = matrix2._offsetY; 

                    // Transform set to Translate and Scale
                    matrix1._type = MatrixTypes.TRANSFORM_IS_TRANSLATION | MatrixTypes.TRANSFORM_IS_SCALING;
                    return; 

                case 50: // S|T * S 
                    matrix1._m11 *= matrix2._m11; 
                    matrix1._m22 *= matrix2._m22;
                    matrix1._offsetX *= matrix2._m11; 
                    matrix1._offsetY *= matrix2._m22;
                    return;

                case 51: // S|T * S|T 
                    matrix1._m11 *= matrix2._m11;
                    matrix1._m22 *= matrix2._m22; 
                    matrix1._offsetX = matrix2._m11 * matrix1._offsetX + matrix2._offsetX; 
                    matrix1._offsetY = matrix2._m22 * matrix1._offsetY + matrix2._offsetY;
                    return; 
                case 36: // S * U
                case 52: // S|T * U
                case 66: // U * S
                case 67: // U * S|T 
                case 68: // U * U
                    matrix1 = new Matrix( 
                        matrix1._m11 * matrix2._m11 + matrix1._m12 * matrix2._m21, 
                        matrix1._m11 * matrix2._m12 + matrix1._m12 * matrix2._m22,
 
                        matrix1._m21 * matrix2._m11 + matrix1._m22 * matrix2._m21,
                        matrix1._m21 * matrix2._m12 + matrix1._m22 * matrix2._m22,

                        matrix1._offsetX * matrix2._m11 + matrix1._offsetY * matrix2._m21 + matrix2._offsetX, 
                        matrix1._offsetX * matrix2._m12 + matrix1._offsetY * matrix2._m22 + matrix2._offsetY);
                    return; 
#if DEBUG 
            default:
                Debug.Fail("Matrix multiply hit an invalid case: " + combinedType); 
                break;
#endif
            }
        } 

        ///  
        /// Applies an offset to the specified matrix in place. 
        /// 
        internal static void PrependOffset( 
            ref Matrix matrix,
            double offsetX,
            double offsetY)
        { 
            if (matrix._type == MatrixTypes.TRANSFORM_IS_IDENTITY)
            { 
                matrix = new Matrix(1, 0, 0, 1, offsetX, offsetY); 
                matrix._type = MatrixTypes.TRANSFORM_IS_TRANSLATION;
            } 
            else
            {
                //
                //  / 1   0   0 \       / m11   m12   0 \ 
                //  | 0   1   0 |   *   | m21   m22   0 |
                //  \ tx  ty  1 /       \  ox    oy   1 / 
                // 
                //       /   m11                  m12                     0 \
                //  =    |   m21                  m22                     0 | 
                //       \   m11*tx+m21*ty+ox     m12*tx + m22*ty + oy    1 /
                //

                matrix._offsetX += matrix._m11 * offsetX + matrix._m21 * offsetY; 
                matrix._offsetY += matrix._m12 * offsetX + matrix._m22 * offsetY;
 
                // It just gained a translate if was a scale transform. Identity transform is handled above. 
                Debug.Assert(matrix._type != MatrixTypes.TRANSFORM_IS_IDENTITY);
                if (matrix._type != MatrixTypes.TRANSFORM_IS_UNKNOWN) 
                {
                    matrix._type |= MatrixTypes.TRANSFORM_IS_TRANSLATION;
                }
            } 
        }
    } 
} 

// 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