среда, 29 июня 2011 г.

Изучение классов Transform в Silverlight



Silverlight предоставляет разработчикам унифицированную модель программирования для реализации ожиданий веб-пользователей, которая включает графику, анимацию и мультимедиа.

 В этой статье описываются способы создания приложений на базе Silverlight с графикой, анимацией и мультимедиа. В данной статье мы поговорим об использовании двумерных (2-D) классов Transform в Silverlight для поворота, масштабирования, наклона и перемещения (перевода) объектов.

Transform определяет способ сопоставления или преобразования точек из одного координатного пространства в другое. Это сопоставление описано преобразованием Matrix, которое представляет собой коллекцию из трех строк с тремя столбцами, содержащую значения типа Double.Silverlight использует матрицы, основанные на строках. Векторы представляют собой векторы-строки, а не векторы-столбцы.

В следующей таблице показана структура матрицы Silverlight.
Значение по умолчанию: 1,0
Значение по умолчанию: 0,0
0.0
Значение по умолчанию: 0,0
Значение по умолчанию: 1,0
0.0
Значение по умолчанию: 0,0
Значение по умолчанию: 0,0
1.0

Управляя значениями матрицы, можно поворачивать, масштабировать, наклонять и перемещать объект. Например, изменив значения в первом столбце третьей строки (значение OffsetX) на 100, можно переместить объект на 100 единиц вдоль оси X. Изменив значение во втором столбце второй строки на 3, можно растянуть объект в высоту в три раза относительно текущего размера. Если изменить оба значения, объект переместится на 100 единиц вдоль оси X и растянется в высоту с коэффициентом 3. Поскольку Silverlight поддерживает только аффинные преобразования, значения в правом столбце всегда остаются равными 0, 0, 1.

Несмотря на то, что Silverlight предоставляет возможность непосредственно управлять значениями матрицы, в Silverlight также имеется несколько классов Transform, позволяющих преобразовывать объект, не зная структуру базовой матрицы. Например, класс ScaleTransform позволяет масштабировать объект с помощью определения его свойств ScaleX и ScaleY вместо управления матрицей преобразования. Аналогично класс RotateTransform позволяет повернуть объект, просто задав его свойство Angle.

Silverlight предоставляет следующие двумерные классы Transform для стандартных операций преобразования.
Класс
Описание
Поворачивает элемент на значение, заданное в Angle.
Масштабирует элемент, используя коэффициенты, заданные в ScaleX и ScaleY.
Наклоняет элемент на коэффициенты, заданные в AngleX и AngleY.
Сдвигает элемент на расстояние, заданное в X и Y.

Для совершения более сложных преобразований Silverlight предоставляет следующие три класса:
Класс
Описание
Используйте этот класс, чтобы применить несколько преобразований к одному и тому же объекту (например, наклон и вращение). Этот класс применяет несколько преобразований в предпочтительном порядке и поэтому обычно является наилучшим способом применения нескольких преобразований.
Как в случае с CompositeTransform, можно использовать этот класс для применения нескольких преобразований; тем не менее, класс CompositeTransform является предпочтительным средством для этого, если не требуется применить преобразования в определенном порядке или применить различные центральные точки для различных преобразований.
Создает настраиваемые преобразования, не предоставленные другими классами Transform. При использовании MatrixTransform происходит непосредственное управление матрицей.

В своём примере я использую основные преобразования, такие как RotateTransform, ScaleTransform, SkewTransform и MatrixTransform. Наболее сложное из них, это последнее преобразование. 

MatrixTransform используется для создания пользовательских преобразований, не предоставленных классами RotateTransform, ScaleTransform, SkewTransform и TranslateTransform.
Двухмерная плоскость x-y использует для преобразований матрицу 3 x 3. Аффинные преобразования с матричным представлением можно умножать для получения линейных преобразований, таких как поворот и отклонение (сдвиг), следующих за переносом.
Последний столбец аффинного преобразования с матричным представлением равен (0, 0, 1); поэтому необходимо лишь задать члены первых двух столбцов.
Члены в последней строке, OffsetX и OffsetY, представляют значения преобразования.
Обычно методы и свойства задают матрицу преобразования как вектор, имеющий только шесть членов; эти члены таковы:
    (M11, M12, M21, M22, OffsetX, OffsetY)
Можно сместить локальную позицию (0,0) для объекта на Canvas с помощью свойств Canvas..::..Left и Canvas..::..Top, но это не считается преобразованием; в этом случае объект сохраняет собственную локальную (0,0) позицию для преобразования.

Ну на этом хватит теории, давайте приступим к практике. Давайте рассмотрим пример, который рисует одну и ту же фигуру (улыбающееся существо) используя различные преобразования.

<Window x:Class="TransformationDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="240" Width="700">
    <StackPanel Orientation="Horizontal">
        <Canvas Margin="5" Background="Green" Height="120" Width="120">
            <Canvas.LayoutTransform>
                <ScaleTransform ScaleX="1.5" ScaleY="1.5" />
            </Canvas.LayoutTransform>
            <Path Canvas.Top="0" Canvas.Left="0" Stroke="Black" >
                <Path.Fill>
                    <RadialGradientBrush GradientOrigin="0.2,0.2">
                        <GradientStop Offset="0" Color="LightBlue" />
                        <GradientStop Offset="0.6" Color="Blue" />
                        <GradientStop Offset="1.0" Color="DarkBlue" />
                    </RadialGradientBrush>
                </Path.Fill>
                <Path.Data>
                    <CombinedGeometry GeometryCombineMode="Union">
                        <CombinedGeometry.Geometry1>
                            <EllipseGeometry Center="60,60" RadiusX="60" RadiusY="40" />
                        </CombinedGeometry.Geometry1>
                        <CombinedGeometry.Geometry2>
                            <RectangleGeometry Rect="20,60 85 50" />
                        </CombinedGeometry.Geometry2>
                    </CombinedGeometry>
                </Path.Data>
            </Path>

            <Ellipse Canvas.Left="30" Canvas.Top="35" Width="25" Height="20" Stroke="Blue" StrokeThickness="3" Fill="White" />
            <Ellipse Canvas.Left="40" Canvas.Top="43" Width="6" Height="5" Fill="Black" />

            <Ellipse Canvas.Left="65" Canvas.Top="35" Width="25" Height="20" Stroke="Blue" StrokeThickness="3" Fill="White" />
            <Ellipse Canvas.Left="75" Canvas.Top="43" Width="6" Height="5" Fill="Black" />
            <Path Name="mouth" Stroke="Red" StrokeThickness="4" Data="M 40,74 Q 57,95 80,74 " />
        </Canvas>
        <Canvas Background="Red" Height="120" Width="120">
            <Canvas.LayoutTransform>
                <RotateTransform Angle="40" />
            </Canvas.LayoutTransform>
            <Path Canvas.Top="0" Canvas.Left="0" Stroke="Black" >
                <Path.Fill>
                    <RadialGradientBrush GradientOrigin="0.2,0.2">
                        <GradientStop Offset="0" Color="LightBlue" />
                        <GradientStop Offset="0.6" Color="Blue" />
                        <GradientStop Offset="1.0" Color="DarkBlue" />
                    </RadialGradientBrush>
                </Path.Fill>
                <Path.Data>
                    <CombinedGeometry GeometryCombineMode="Union">
                        <CombinedGeometry.Geometry1>
                            <EllipseGeometry Center="60,60" RadiusX="60" RadiusY="40" />
                        </CombinedGeometry.Geometry1>
                        <CombinedGeometry.Geometry2>
                            <RectangleGeometry Rect="20,60 85 50" />
                        </CombinedGeometry.Geometry2>
                    </CombinedGeometry>
                </Path.Data>
            </Path>

            <Ellipse Canvas.Left="30" Canvas.Top="35" Width="25" Height="20" Stroke="Blue" StrokeThickness="3" Fill="White" />
            <Ellipse Canvas.Left="40" Canvas.Top="43" Width="6" Height="5" Fill="Black" />

            <Ellipse Canvas.Left="65" Canvas.Top="35" Width="25" Height="20" Stroke="Blue" StrokeThickness="3" Fill="White" />
            <Ellipse Canvas.Left="75" Canvas.Top="43" Width="6" Height="5" Fill="Black" />
            <Path  Stroke="Red" StrokeThickness="4" Data="M 40,74 Q 57,95 80,74 " />
        </Canvas>

        <Canvas Background="BlanchedAlmond" Height="120" Width="120">
            <Canvas.LayoutTransform>
                <SkewTransform AngleX="20" AngleY="25" />
            </Canvas.LayoutTransform>
            <Path Canvas.Top="0" Canvas.Left="0" Stroke="Black" >
                <Path.Fill>
                    <RadialGradientBrush GradientOrigin="0.2,0.2">
                        <GradientStop Offset="0" Color="LightBlue" />
                        <GradientStop Offset="0.6" Color="Blue" />
                        <GradientStop Offset="1.0" Color="DarkBlue" />
                    </RadialGradientBrush>
                </Path.Fill>
                <Path.Data>
                    <CombinedGeometry GeometryCombineMode="Union">
                        <CombinedGeometry.Geometry1>
                            <EllipseGeometry Center="60,60" RadiusX="60" RadiusY="40" />
                        </CombinedGeometry.Geometry1>
                        <CombinedGeometry.Geometry2>
                            <RectangleGeometry Rect="20,60 85 50" />
                        </CombinedGeometry.Geometry2>
                    </CombinedGeometry>
                </Path.Data>
            </Path>

            <Ellipse Canvas.Left="30" Canvas.Top="35" Width="25" Height="20" Stroke="Blue" StrokeThickness="3" Fill="White" />
            <Ellipse Canvas.Left="40" Canvas.Top="43" Width="6" Height="5" Fill="Black" />

            <Ellipse Canvas.Left="65" Canvas.Top="35" Width="25" Height="20" Stroke="Blue" StrokeThickness="3" Fill="White" />
            <Ellipse Canvas.Left="75" Canvas.Top="43" Width="6" Height="5" Fill="Black" />
            <Path  Stroke="Red" StrokeThickness="4" Data="M 40,74 Q 57,95 80,74 " />
        </Canvas>

        <Canvas Background="Aqua" Height="120" Width="120">
            <Canvas.LayoutTransform>
                <MatrixTransform>
                    <MatrixTransform.Matrix>
                        <Matrix M11="0.8" M22="1.9" M12="1.3" M21="0.4" />
                    </MatrixTransform.Matrix>
                </MatrixTransform>
            </Canvas.LayoutTransform>
            <Path Canvas.Top="0" Canvas.Left="0" Stroke="Black" >
                <Path.Fill>
                    <RadialGradientBrush GradientOrigin="0.2,0.2">
                        <GradientStop Offset="0" Color="LightBlue" />
                        <GradientStop Offset="0.6" Color="Blue" />
                        <GradientStop Offset="1.0" Color="DarkBlue" />
                    </RadialGradientBrush>
                </Path.Fill>
                <Path.Data>
                    <CombinedGeometry GeometryCombineMode="Union">
                        <CombinedGeometry.Geometry1>
                            <EllipseGeometry Center="60,60" RadiusX="60" RadiusY="40" />
                        </CombinedGeometry.Geometry1>
                        <CombinedGeometry.Geometry2>
                            <RectangleGeometry Rect="20,60 85 50" />
                        </CombinedGeometry.Geometry2>
                    </CombinedGeometry>
                </Path.Data>
            </Path>

            <Ellipse Canvas.Left="30" Canvas.Top="35" Width="25" Height="20" Stroke="Blue" StrokeThickness="3" Fill="White" />
            <Ellipse Canvas.Left="40" Canvas.Top="43" Width="6" Height="5" Fill="Black" />

            <Ellipse Canvas.Left="65" Canvas.Top="35" Width="25" Height="20" Stroke="Blue" StrokeThickness="3" Fill="White" />
            <Ellipse Canvas.Left="75" Canvas.Top="43" Width="6" Height="5" Fill="Black" />
            <Path  Stroke="Red" StrokeThickness="4" Data="M 40,74 Q 57,95 80,74 " />
        </Canvas>
    </StackPanel>
</Window>



Вот то, что получилось у меня, надеюсь у вас получилось ещё лучше J



Комментариев нет:

Отправить комментарий