Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Shared / MS / Internal / MatrixUtil.cs / 1305600 / 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 : [....] - 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 : [....] - 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- KeyboardEventArgs.cs
- ProgressBar.cs
- InvalidEnumArgumentException.cs
- WmiEventSink.cs
- ObjectQuery.cs
- DPTypeDescriptorContext.cs
- WebPartEventArgs.cs
- MD5.cs
- TextEffect.cs
- Decimal.cs
- EntityDataSourceWrapperCollection.cs
- HMACSHA512.cs
- KeyProperty.cs
- OLEDB_Enum.cs
- TableRowCollection.cs
- PageCache.cs
- SurrogateEncoder.cs
- panel.cs
- CollectionBuilder.cs
- OdbcConnectionPoolProviderInfo.cs
- APCustomTypeDescriptor.cs
- NumericPagerField.cs
- DataPagerFieldCollection.cs
- CopyOnWriteList.cs
- SelectedDatesCollection.cs
- ObjectReaderCompiler.cs
- Color.cs
- HwndSourceKeyboardInputSite.cs
- RowType.cs
- TreeNodeMouseHoverEvent.cs
- OdbcConnectionStringbuilder.cs
- HandleCollector.cs
- MaskInputRejectedEventArgs.cs
- VariableAction.cs
- KerberosSecurityTokenAuthenticator.cs
- FormParameter.cs
- EdmToObjectNamespaceMap.cs
- Soap.cs
- ComboBoxDesigner.cs
- PerformanceCounterPermission.cs
- DbConnectionHelper.cs
- XPathNavigatorKeyComparer.cs
- FlowDocumentView.cs
- AssemblyHash.cs
- ResolveMatchesCD1.cs
- BamlLocalizer.cs
- PageThemeCodeDomTreeGenerator.cs
- CellLabel.cs
- StyleSheetComponentEditor.cs
- TextEditorTyping.cs
- DataServiceOperationContext.cs
- ButtonStandardAdapter.cs
- StreamUpgradeInitiator.cs
- StylusButtonCollection.cs
- BamlBinaryReader.cs
- PropertyEmitter.cs
- ColorAnimationUsingKeyFrames.cs
- EncodingTable.cs
- RTLAwareMessageBox.cs
- ApplicationBuildProvider.cs
- DefaultValidator.cs
- XPathSingletonIterator.cs
- SqlDataSourceAdvancedOptionsForm.cs
- ExtentCqlBlock.cs
- CompilerScope.cs
- Double.cs
- TypeElement.cs
- CodeCastExpression.cs
- DbDataAdapter.cs
- sqlinternaltransaction.cs
- TcpClientCredentialType.cs
- RequestNavigateEventArgs.cs
- IUnknownConstantAttribute.cs
- ColorContextHelper.cs
- unitconverter.cs
- Helper.cs
- XmlSchemaDatatype.cs
- TextServicesManager.cs
- RootProjectionNode.cs
- Int32.cs
- CategoryValueConverter.cs
- SynchronizingStream.cs
- WindowsPen.cs
- TimestampInformation.cs
- ObjectTokenCategory.cs
- DataListItemCollection.cs
- DSGeneratorProblem.cs
- PropertyDescriptorGridEntry.cs
- RSAPKCS1SignatureDeformatter.cs
- ConfigXmlElement.cs
- DiscoveryVersionConverter.cs
- TableLayoutPanelCellPosition.cs
- X509Chain.cs
- XmlParserContext.cs
- StylusButton.cs
- DBSchemaRow.cs
- XPathAncestorQuery.cs
- EpmCustomContentSerializer.cs
- Base64Decoder.cs
- DocumentPageView.cs