#794 – Matrix Multiplication, Part IV – Some Examples

Here are a few examples of doing matrix multiplication, for some of the typical matrix sizes used for doing 2D and 3D transforms.

794-002

 

#792 – Matrix Multiplication, Part II – Multiplying a Row by a Column

When you multiply two matrixes together, you perform a series of operations where you multiply a row in the first matrix by a column in the second matrix.  This multiplication results in a single term that will appear in the resulting matrix.

To multiply a row by a column, they must have the same number of elements.  If you consider each of them as vectors, you multiply them by calculating the dot product of the two vectors.

A dot product is calculated by multiplying the corresponding elements in the two vectors and then adding the terms together.

For example, we might multiply a row containing the values a, b, c with a column containing the values x, y, z as follows:

792-001

#790 – How a Rotation Transform Works

A 2D rotation transform in WPF is accomplished by using a transformation matrix.  The transformation matrix is multiplied by another matrix representing a single 2D point to be transformed.  The resulting matrix describes the transformed point.  When rotating a user interface element, this transformation is done individually on each point to generate the set of points representing the transformed element.

The transformation operation for rotation looks like:

790-001

Where ϴ represents the Angle property of the ScaleTransform, indicating the number of degrees to rotate the point in a clockwise direction.

This leads to the equations:

790-002

#787 – Transforming a Point Using Matrix Multiplication

In WPF, all 2D transformations (e.g. scale, rotate, translate) are done internally using matrix multiplication.

Every point that you want to transform is represented as a 2 x 1 matrix (two rows and one column).  For example:

787-001

 

Assume that you want to transform this point, represented by x and y, into a new point.  We do this by multiplying a 2 x 2 transformation matrix by our original 2 x 1 matrix.  The result is another 2 x 1 matrix, containing our new (transformed) point.

The operation is written as follows, assuming that a, b, c and represent the four values in our 2 x 2 matrix.  We multiply the 2 x 2 transformation matrix by the original 2 x 1 matrix to get a new 2 x 1 matrix.

787-002

 

(Don’t worry about the values of a, b, c and d for now–we’ll fill them in later).  The actual multiplication is done as follows:

787-003

#786 – Using Data Binding to Control a 2D Transform

It’s common to use data binding to control the values used for 2D transformations.  Below is a simple example that binds the AngleCenterX and CenterY properties of a RotateTransform to corresponding properties in a class.

    <StackPanel Margin="20,80">
        <Label Content="Dwight D. Eisenhower (1890-1969)" Background="Plum" Margin="10"
               HorizontalAlignment="Center" Padding="20,10" FontSize="16">
            <Label.LayoutTransform>
                <RotateTransform  Angle="{Binding IkeAngle}"
                                  CenterX="{Binding IkeCenterX}"
                                  CenterY="{Binding IkeCenterY}" />
            </Label.LayoutTransform>
        </Label>
    </StackPanel>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;

            // Test data
            IkeAngle = 25;
            IkeCenterX = 0.0;
            IkeCenterY = 0.0;
        }

        public double IkeAngle { get; set; }
        public double IkeCenterX { get; set; }
        public double IkeCenterY { get; set; }

        //-- INotifyPropertyChanged implementation

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void RaisePropertyChanged(string prop)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }

786-001

#781 – Transform Order Matters

When you combine several 2D transforms into a transform group, the order in which you list the constituent transforms matters.  The transforms are applied in the order that you list them in the TransformGroup.  The order that they are applied in makes a difference, because if you translate and then rotate an object, you get a different result than if you rotate the object first and then translate it.

In the example below, the labels start out on top of each other, but end up at different positions, because the order of their transforms is different.

    <Grid>
        <Label Content="Dr. Livingstone, I presume?"
               Style="{StaticResource styAfrica}">
            <Label.RenderTransform>
                <TransformGroup>
                    <TranslateTransform X="70" />
                    <RotateTransform Angle="60" />
                </TransformGroup>
            </Label.RenderTransform>
        </Label>
        <Label Content="Dr. Livingstone, I presume?"
               Style="{StaticResource styAfrica}">
            <Label.RenderTransform>
                <TransformGroup>
                    <RotateTransform Angle="60" />
                    <TranslateTransform X="70" />
                </TransformGroup>
            </Label.RenderTransform>
        </Label>
    </Grid>

781-001

#780 – Combining Transforms

When you apply a 2D transform to an element, you use the RenderTransform or LayoutTransform properties to specify the  transform to apply.  You set the value of these properties to a single instance of the Transform type.

Often, the value of the Transform type will be a specific transform, like ScaleTransform.  However, you can combine multiple transforms by setting the property to an instance of a TransformGroup, which in turn contains a collection of Transform elements.

In the example below, we first apply a rotate transform to the middle label, followed by a translation transform.

    <StackPanel>
        <Label Content="We few, we happy few, we band of brothers"
               Style="{StaticResource styRoyal}"/>
        <Label Content="For he to-day that sheds his blood with me"
               Style="{StaticResource styRoyal}">
            <Label.RenderTransform>
                <TransformGroup>
                    <RotateTransform Angle="20" />
                    <TranslateTransform X="50" />
                </TransformGroup>
            </Label.RenderTransform>
        </Label>
        <Label Content="Shall be my brother; be he ne'er so vile"
               Style="{StaticResource styRoyal}"/>
    </StackPanel>

780-001

#778 – Animating a Scale Transform

Here’s another example of an animation of a 2D transform.  In this case, we animate the scale of the object so that it grows larger and smaller and then repeats the behavior.  This results in a sort of pulsating button.

    <Grid>
        <Button Content="Ship via Wells, Fargo &amp; Co." HorizontalAlignment="Center" VerticalAlignment="Center"
                Padding="20,10" FontSize="16"
                RenderTransformOrigin="0.5,0.5">
            <Button.RenderTransform>
                <ScaleTransform x:Name="scaleTransform" ScaleX="0.98" ScaleY="1.02"/>
            </Button.RenderTransform>
            <Button.Triggers>
                <EventTrigger RoutedEvent="Button.Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetName="scaleTransform"
                                             Storyboard.TargetProperty="ScaleX"
                                             From="0.98" To="1.02" Duration="0:0:0.3"
                                             AutoReverse="True" RepeatBehavior="Forever"/>
                            <DoubleAnimation Storyboard.TargetName="scaleTransform"
                                             Storyboard.TargetProperty="ScaleY"
                                             From="0.98" To="1.02" Duration="0:0:0.3"
                                             AutoReverse="True" RepeatBehavior="Forever"/>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Button.Triggers>
        </Button>
    </Grid>

778-001

#776 – Setting the Center Point for Skew Transforms

Like rotation transforms, you can set the origin for a skew transform using either the RenderTransformOrigin property on the element, or the CenterX/CenterY properties on the SkewTransform element.

You can think of the center of a skew transform as the point that will be held in one place as the object is tilted.

Also note–setting the X value of the center point only affects skews specified using AngleY and setting the Y value only affects skews specified using AngleX.

In the example below, we use RenderTransformOrigin to move the Y component of the center point, which impacts how the AngleX skew is done.

776-001

 

You can better see how this works by looking at how the Visual Studio designer shows you the skew.  It also shows the pre-transformed element, so you can see which point is being used as the origin.

776-002

 

776-003

#774 – Translate Transforms

You can use a translation transform to translate, or move, a user interface element in the X or Y dimensions.  You specify translation values separately in both X and Y dimensions, expressed in device independent units.

You specify translation using a TranslateTransform element, setting values for the X and Y properties.  Both properties default to a value of 0.

LayoutTransform will ignore translation transforms (since the element will be moved around during the layout process anyway).  So you only use translation transforms with a RenderTransform.

Here’s an example that uses a couple of Sliders to dynamically change the X and Y values of a TranslateTransform.

    <StackPanel Orientation="Vertical">
        <TextBlock Text="Jack Kerouac" FontWeight="Bold" HorizontalAlignment="Center"
                   Padding="10,5" Background="PaleGoldenrod" Margin="5">
            <TextBlock.RenderTransform>
                <TranslateTransform  X="{Binding ElementName=sliX, Path=Value}" Y="{Binding ElementName=sliY, Path=Value}"/>
            </TextBlock.RenderTransform>
        </TextBlock>
        <TextBlock Text="Born 12 Mar, 1922" HorizontalAlignment="Center"
                   Padding="10,5" Background="Thistle"/>

        <Slider Name="sliX" Minimum="0" Maximum="300" Margin="10"/>
        <Slider Name="sliY" Minimum="0" Maximum="300" Margin="10"/>
    </StackPanel>

774-001
774-002
774-003