#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

#785 – Using the Visual Profiler Tool

Once you install the WPF Performance Suite, you can use the tool to help improve the performance of your application.

In addition to the Perforator tool, the Performance Suite includes the Visual Profiler tool, which is designed to help you profile your application at run-time.  Profiling involves monitoring your application at run-time to look at the performance aspects of individual elements.  This will help you figure out the location of any performance bottlenecks.

To run the Visual Profiler, start the WPF Performance Suite and click on the Visual Profiler tab.  Start your WPF application and then click Select Process under the Actions menu to select your process.

Once you connect the Visual Profiler to your application, you’ll see a variety of information, including:

  • A visual tree that indicates CPU time spent for layout of an element and its children
  • Measure/Arrange CPU usage for selected element
  • Application CPU usage breakdown

785-001

#784 – Using the Perforator Tool to Analyze WPF Application Performance

Once you install the WPF Performance Suite, you can use the tool to analyze the performance of your application.

After starting the WPF Performance Suite, click on the Perforator tab.

784-001

The next step is to run your WPF application.  Once the application is running, under the Actions menu, click on Select Process.

784-002

Select your application from the list and click the Select button.

784-003

The Perforator app will begin collecting data from your running WPF application and you’ll see various data displayed in the graphs.

784-004

Perforator is showing you the rendering performance of your application.  If nothing is being updated, both the Frame Rate and Dirty Rect Addition Rate graphs will report 0.  If you are updating something in you application, you generally want the frame rate to be as high as possible and the Dirty Rect Addition Rate to be as low as possible.

#783 – Downloading and Installing the WPF Performance Suite

There is a set of tools, known as the WPF Performance Suite, that you can use to analyze the performance of your WPF applications.

To get access to the WPF Performance Suite, you start by installing the Windows SDK 7.1 .  During the install, check the Windows Performance Toolkit option.

783-002

Once installed, you can find the WPF Performance Suite in the start screen under the Microsoft Windows Performance Toolkit section.

783-003

 

The first time that you run the WPF Performance Suite, you’ll see an Add Tools dialog.  Check the options for Perforator and Visual Profiler.

783-004

 

When the performance suite starts up, you’ll see an application with tabs labeled Perforator and Visual Profiler.

783-005

 

#782 – A RenderTransform Has Better Performance than a LayoutTransform

When you transform a 2D element, you specify the desired transform as either a layout transform (transform calculated before layout phase) or a render transform (transform calculated before rendering the element).

A render transform has better performance than a layout transform.  This is especially apparent when you are animating a transform.  Whenever a layout transform changes, the panel containing the element that is being transformed needs to recalculate the layout of the children within the panel.  With a render transform, by contrast, the element only needs to be re-rendered.  Because of the additional layout step, a layout transform is more compute intensive than a render transform.

Because of the performance differences, you should use a render transform by default, unless you need the layout of the elements to change when the transform changes.

 

#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

#779 – Animating a Rotation Transform

Here’s one more example of an animation of a 2D transform.  In this case, we animate a rotation transform of an element so that the element continually spins around.

    <Grid>
        <Label Content="Gambling now legal in Nevada" Background="Plum"
               HorizontalAlignment="Center" VerticalAlignment="Center"
               Padding="20,10" FontSize="16"
               RenderTransformOrigin="0.5,0.5">
            <Label.RenderTransform>
                <RotateTransform x:Name="rotTransform" />
            </Label.RenderTransform>
            <Label.Triggers>
                <EventTrigger RoutedEvent="Label.Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetName="rotTransform"
                                             Storyboard.TargetProperty="Angle"
                                             From="0" To="360" Duration="0:0:2.5"
                                             RepeatBehavior="Forever"/>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Label.Triggers>
        </Label>
    </Grid>

779-001
779-002

#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