Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / XAML

Zeroing the Center of a CompositeTransform

3.00/5 (1 vote)
8 Oct 2019CPOL3 min read 2.1K  
Zeroing the center of a CompositeTransform

Sometimes, it is useful to convert a transformation with a non-zero center point to an equivalent transformation with a zero center point. If you find you have a need for this, then maybe this post will be helpful.

Posts in this series:

Consider this diagram:

Cp

In the above drawing, the green rectangle is translated Tx=80, Ty=60, and rotated R=40° about the center Cx=100, and Cy=30. The goal of this post is to come up with an equivalent transformation with a center point of Cx=0, Cy=0.

The first step is to apply only the translation of Tx=80, Ty=60 and see where that gets us. The result of that is the blue rectangle.

The next step is to apply the rotation of R=40° about the center at Cx=0, Cy=0. The result of that is the red rectangle.

Our last step is to adjust the translation of Tx and Ty to move point B to point G. That is, if we know Bx, By, Gx, and Gy then the new translation is:

  • \( Tx = 80 + Gx – Bx \)
  • \( Ty = 80 + Gy – By \)

This will require a bit of trigonometry.

Point C is the center point of the rotation of the blue and green rectangles. The distance from C to B is the same as the distance from C to G. That is, the distance CB = CG. For simplicity, we will call this distance d. Clearly:

  • \( d = \sqrt{Cx^2 + Cy^2} \)

Now let’s imagine point C is at 0,0 (but let’s keep the original values of Cx=100 and Cy=30 for the rest of the calculations). If that is the case, then:

  • \( Bx = -Cx \)
  • \( By = -Cy \)
  • \( Gx = \cos(g).d \)
  • \( Gy = \sin(g).d \)

Once we determine the angles b and g, we are done. Determining the first angle b is easy:

  • \( b = \text{atan2}(-Cy,-Cx) \)

The second angle g is even easier:

  • g = b + R.

So let’s work this problem through:

  • \( d = \sqrt{Cx^2 + Cy^2} = \sqrt{100^2 + 30^2} = 104.4 \)
  • \( b = \text{atan2}(-Cy,-Cx) = \text{atan2}(-30,-100) = -163.3° \)
  • \( g = b + R = -163.3° + 40° = -123.3° \)
  • \(Bx = -Cx = -100 \)
  • \( By = -Cy = -30 \)
  • \(Gx = Cos(g) * d = \cos(-123.3°) * 104.4 = -57.3\)
  • \(Gy = Sin(g) * d = \sin(-123.3°) * 104.4 = -87.3\)
  • \(Tx = Tx + Gx -Bx = 80 + (-57.3) - (-100) = 122.7\)
  • \(Ty = Ty + Gy -By = 60 + (-87.3) - (-30) = 2.7\)

Here is an overlay of the before (green) and after (blue) transformations:

image 2

Here is the XAML that overlays both transformations:

ZeroCtrPtExample.xaml

XML
<Page
				    x:Class="PanViewDemoApp.ZeroCtrPtExample"
				    IsTabStop="false"
				    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
				    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
				    xmlns:local="using:PanViewDemoApp"
				    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
				    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
				    mc:Ignorable="d"
				    FontSize="16">
				    <Canvas>
				        <Border
				            Height="120"
				            Width="200"
				            Background="LightGreen">
				            <Border.RenderTransform>
				                <CompositeTransform
				                    x:Name="M"
				                    TranslateX="80"
				                    TranslateY="60"
				                    Rotation="40"
				                    CenterX="100"
				                    CenterY="30" />
				            </Border.RenderTransform>
				            <TextBlock
				                Margin="3"
				                Foreground="Green">Tx=80 Ty=60<LineBreak />
                                R=40<LineBreak />Cx=100 Cy=30</TextBlock>
				        </Border>
				        <Border
				            Height="120"
				            Width="200"
				            BorderThickness="3"
				            BorderBrush="Blue">
				            <Border.RenderTransform>
				                <CompositeTransform
				                    x:Name="N"
				                    TranslateX="122.7"
				                    TranslateY="2.7"
				                    Rotation="40" />
				            </Border.RenderTransform>
				            <TextBlock
				                VerticalAlignment="Bottom"
				                Foreground="Blue"
				                Margin="3">Tx=122.7 Ty=2.7<LineBreak />
                                R=40<LineBreak />Cx=0 Cy=0</TextBlock>
				        </Border>
				    </Canvas>
				</Page>

Here is some C# code that performs the zeroing of the center point of a transformation:

TransformExtensions.cs

C#
static void InternalZeroCenterPoint(ICompositeTransform t)
				{
				    var d = Math.Sqrt(t.CenterX * t.CenterX + t.CenterY * t.CenterY);
				    var b = Math.Atan2(-t.CenterY, -t.CenterX);
				    var g = b + t.Rotation * Math.PI / 180;
				    var Bx = -t.CenterX;
				    var By = -t.CenterY;
				    var Gx = Math.Cos(g) * d;
				    var Gy = Math.Sin(g) * d;
				    t.TranslateX += Gx - Bx;
				    t.TranslateY += Gy - By;
				    t.CenterX = 0;
				    t.CenterY = 0;
				}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)