locked
skew is flawed RRS feed

  • Question

    • I wan to demonstrate that under VS2008 the  skew operator is flawed, but I do not know how to transport executables here nor how to insert xaml code.
    • ray reeves
    Monday, May 14, 2012 4:00 PM

Answers

  • "I think I am using separate transforms, I am transforming an object that has aleady been transformed"

    Nope, the original object is never transformed. Every animation frame a new transform is computed and applied to the original object.

    "However, in succession the second operation does not leave a side untouched, and therefore is not performing a skew operation on the current parallelogram."

    The skew is performed with respect to the coordinate system, it has nothing to do with your parallelogram. If you watch carefully the second animation you'll notice that only the Y coordinate of the points changes, the X coordinate stays the same. That's expected because the skew occurs along the Y axis of the coordinate system, not of your parallelogram.

    If I understood correctly what you want then you need to add a rotate transform to change the coordinate system so the second skew is applied along the horizontal axis of the parallelogram. Something like this:

            <Canvas>
                <Button RenderTransformOrigin="1.0 1.0"
                        Canvas.Left="100"
                        Canvas.Top="160"
                        FontSize="24"
                        Width="100"
                        Content="a^a"
                        Height="100">
                    <Button.RenderTransform>
                        <TransformGroup>
                            <SkewTransform x:Name="a1SkewTransform" />
                            <RotateTransform x:Name="a2Rot1Transform" Angle="-60"/>
                            <SkewTransform x:Name="a2SkewTransform" />
                            <RotateTransform x:Name="a2Rot2Transform" Angle="60" />
                        </TransformGroup>
                    </Button.RenderTransform>
                </Button>
                <Button Width="30"
                        Canvas.Top="0"
                        Content="X">
                    <Button.Triggers>
                        <EventTrigger RoutedEvent="Button.Click">
                            <EventTrigger.Actions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="a1SkewTransform"
                                                         Storyboard.TargetProperty="AngleX"
                                                         From="0"
                                                         To="-60"
                                                         BeginTime="0:0:0"
                                                         Duration="0:0:3" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger.Actions>
                        </EventTrigger>
                    </Button.Triggers>
                </Button>
                <Button Width="30"
                        Canvas.Top="50"
                        Content="Y">
                    <Button.Triggers>
                        <EventTrigger RoutedEvent="Button.Click">
                            <EventTrigger.Actions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="a2SkewTransform"
                                                         Storyboard.TargetProperty="AngleY"
                                                         From="0"
                                                         To="60"
                                                         BeginTime="0:0:0"
                                                         Duration="0:0:3" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger.Actions>
                        </EventTrigger>
                    </Button.Triggers>
                </Button>
            </Canvas>

    The first rotate transform changes the coordinate system for the next skew transform. The last rotate transform undoes the effect of the first rotate transform, otherwise your rendered object will be both skewed and rotated.

    • Marked as answer by Sheldon _Xiao Thursday, May 24, 2012 6:54 AM
    Thursday, May 17, 2012 5:09 PM

All replies

  • For XAML - Just click the "Insert Code Block" button and then select "XML" for the language...

    ~Christine


    My Gallery

    Monday, May 14, 2012 6:44 PM
  • I get an elaborate error message when I try to insert my code.
    Tuesday, May 15, 2012 1:41 PM
  • OK Heres my xaml code. I run it under VS2008

    <Window x:Class="askew.Window1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Window1" Height="300" Width="300">

        <Canvas>

     

            <Button RenderTransformOrigin="1.0,1.0" Name="aSq"

                       Background="DodgerBlue"               

                       Canvas.Left="20" Canvas.Top="160" Opacity="1" FontSize="24"

                       Width="100" Height="100" >a^a

                <Button.RenderTransform>

                    <TransformGroup>

                        <SkewTransform      x:Name="a1SkewTransform" />

                    </TransformGroup>

                </Button.RenderTransform>

            </Button>

            <Button Background="Orange" Width="30" Canvas.Top="0" ClickMode="Press"

                   Click="Button_Click" >X

                <Button.Triggers>

                    <EventTrigger RoutedEvent="Button.Click"  >

                        <EventTrigger.Actions>

                            <BeginStoryboard>

                                <Storyboard x:Name="myStoryboard1" >

                                    <DoubleAnimation                                  

                                        Storyboard.TargetName="a1SkewTransform"

                                        Storyboard.TargetProperty="AngleX"              

                                        From="0" To="-60" 

                                        BeginTime="0:0:0" Duration="0:0:3"/>

                                </Storyboard>

                            </BeginStoryboard>

                        </EventTrigger.Actions>

                    </EventTrigger>

                </Button.Triggers>

            </Button>

            <Button Background="Orange" Width="30" Canvas.Top="50" ClickMode="Press"

                   Click="Button_Click" >Y

                <Button.Triggers>

                    <EventTrigger RoutedEvent="Button.Click"  >

                        <EventTrigger.Actions>

                            <BeginStoryboard>

                                <Storyboard x:Name="myStoryboard2" >

                                    <DoubleAnimation                                  

                                        Storyboard.TargetName="a1SkewTransform"

                                        Storyboard.TargetProperty="AngleY"              

                                        From="0" To="60" 

                                        BeginTime="0:0:0" Duration="0:0:3"/>

                                </Storyboard>

                            </BeginStoryboard>

                        </EventTrigger.Actions>

                    </EventTrigger>

                </Button.Triggers>

            </Button>

     

        </Canvas>

    </Window>

    Tuesday, May 15, 2012 1:53 PM
  • The significan property of "skew" ( Not mentioned in the documentation) is that it preserves area.

    In my demonstartion the button X skews a rectangle  along the X axis, and does it correctly. Button B then tries to de-skew it along the Y axis but gets it wrong. It is apparent that the area is no longer preserved.

    Tuesday, May 15, 2012 2:10 PM
  • The area preservation is a property of a shear transform. WPF's SkewTranform is more than that, it is a shear transform only when one of the angle is 0.

    I'm not sure what you mean by "de-skew it along the Y axis" but maybe it will work better if you try to use one transform for each animation instead of targeting both animations at the same transform.

    Tuesday, May 15, 2012 3:39 PM
  • If I skew a recrangle using angleX = theta I can reverse that by skewing again with angleX = -theta, which for want of a better term I call de-skewing, but that is rather pointless. Iif I first  specify anglX = theta and then angleY = -theta then I should obtain a different rectangle of the same area but different proportions, and that would be very useful, but I do not. I could email an executable under 7-zip which demonstrates this, if you could just tell me where to address it.

    I don't see any documentation about shear transforms and I thought I was only using one angle in each transform. If you are saying I cant use a succession of skew transforms on an object then I repeatt that skew is flawed.

    This is the only way I knoew of reshaping an area without using algebra.

    ray reeves

    Tuesday, May 15, 2012 6:28 PM
  • "If I skew a recrangle using angleX = theta I can reverse that by skewing again with angleX = -theta"

    Correct.

    "Iif I first  specify anglX = theta and then angleY = -theta then I should obtain a different rectangle of the same area but different proportions"

    Yes but this "and then" means that you need to use different transforms. As is now your code uses the same transform and the result is not a shear transform anymore. The first animation changes AngleX and then the second animation starts it sets AngleY of the same transform that already has AngleX set.

    "If you are saying I cant use a succession of skew transforms on an object then I repeatt that skew is flawed."

    But you're not using a succession of transforms, you have only one transform.

    Tuesday, May 15, 2012 7:44 PM
  • Allow me to disagree with you without  meaning to be unkind.. When one sets an angle in a parallelogram that effectively sets all four of them. Opposite ones are identical and adjacent ones are complementary. So I don't understand when you say one of them should be zero . When we say angleX or angleY we are merely denoting which  side the angle is measured from. Of course the names X and Y derive from the fact that WPF idefines skew as applied to a rectangle and a rectangle can only be specified as aligned with the X and Y axes. This would be a terrible constraint but happily we can see that it allows rotation, translation. and even some skewing, as examplified in my de-skrw example.. When you talk about one or two transforms I  think you are really playing with words. I am using the same code with different parametes  It doesn't matter whether you think of it as one or two transforms. What is meant by skewing is to slide one side along while remaing parallel to the opposite side. The other two sides rotate and change length to keep the parallelogram closed. The function could be defined in this way without referring to angles at all, and it is clear that there is no new difficulty in skewing an already skewed parallelogram. The movements are cumulative, as in simple de-skewing. With this repair the skew function will have much greater use.

    Tuesday, May 15, 2012 11:27 PM
  • "When you talk about one or two transforms I  think you are really playing with words."

    Nope. Let me play with some formulas to see what's going on:

    A shearing transform matrix looks like one of the following:

    | 1  fy |  or  | 1   0 |
    | 0   1 |      | fx  1 |

    Let's see if such a matrix preserves the area. To keep formulas very simple I'll use a unit square with coordinates P0 = (0, 0), P1 = (1, 0), P2 = (1, 1), P3 = (0, 1). The area can be computed as x1 y3 - x3 y1 = 1 1 - 0 0 = 1.

    Now if we use the second shear matrix to transform P1 and P3 we get the following coordinates:

    x1 = 1
    y1 = 0
    x3 = fx
    y3 = 1

    And the area is x1 y3 - x3 y1 = 1 1 - fx 0 = 1. OK, such a transform preserves the area.

    Now back to your code. When the second animations starts the skew transforms it produces looks like:

    | 1  fy |
    | fx  1 |

    Now P1 and P3 coordinates are:

    x1 = 1
    y1 = fy
    x3 = fx
    y3 = 1

    And the area is now x1 y3 - x3 y1 = 1 1 - fx fy = 1 - fx fy. Oops, the area is not 1 anymore. The only way to get 1 is to make fx or fy (or both) 0. So this "skew" matrix doesn't preserve the area anymore.

    Now let's see what happens if you use 2 separate transforms. We'll multiply the 2 shear matrices:

    | 1  fy |  |  1  0 | = | 1 + fxfy  fy |
    | 0   1 |  | fx  1 |   | fx         1 |

    Obviously, the result is not the same as the "skew" matrix WPF builds. Let's see if this matrix preserves the area:

    x1 = 1 + fxfy
    y1 = fy
    x3 = fx
    y3 = 1
    x1 y3 - x3 y1 = (1 + fxfy) - fxfy = 1 + (fxfy - fxfy) = 1 + 0 = 1

    So, the area is preserved.

    Now the billion dollar question. Why doesn't WPF build a skew matrix that looks like in the above case? Because it can't. Matrix multiplication is not commutative:

    |  1  0 |  | 1  fy | = | 1   fy       |
    | fx  1 |  | 0   1 |   | fx  1 + fxfy |

    And the transformed coordinates and resulting area:

    x1 = 1
    y1 = fy
    x3 = fx
    y3 = 1 + fxfy
    x1 y3 - x3 y1 = (1 + fxfy) - fxfy = 1 + (fxfy - fxfy) = 1 + 0 = 1
    The area is of course preserved. But the coordinates are not the same coordinates that we got in the previous case. Clearly the transform order matters and WPF can't select a particular order when you set both AngleX and AngleY on a skew transform. It's your job to use 2 different matrices in a order of your choice.
    • Edited by Mike Danes Wednesday, May 16, 2012 7:56 AM
    Wednesday, May 16, 2012 7:54 AM
  • Thank you for your careful attention

    Of course the order in which you multiplly matrices is important. Both your orders  produce the same area, yet my demo shows that WPF produces  diifferent areas. It appears that height factor which changes when we interchangs X and Y doesn't get taken into account. Shouldn't there be an error message or at least a warning?

    I do not understand how to rewrite my code in a way you consider acceptable, so I do not consider this matter to be resolved yet.

    Wednesday, May 16, 2012 4:14 PM
  • "Both your orders  produce the same area, yet my demo shows that WPF produces  diifferent areas. "

    But your demo doesn't multiply matrices, it uses a single matrix.

    "It appears that height factor which changes when we interchangs X and Y doesn't get taken into account. Shouldn't there be an error message or at least a warning?"

    The documentation for SkewTransform doesn't make any claims about preserving area or producing a shear matrix. It is what it is.

    "I do not understand how to rewrite my code in a way you consider acceptable"

    Basically you need to add another SkewTransform to the transform group and change one of the animations to target the new transform:

        <Canvas>
            <Button RenderTransformOrigin="1.0 1.0"
                    Canvas.Left="100"
                    Canvas.Top="160"
                    FontSize="24"
                    Width="100"
                    Content="a^a"
                    Height="100">
                <Button.RenderTransform>
                    <TransformGroup>
                        <SkewTransform x:Name="a1SkewTransform" />
                        <SkewTransform x:Name="a2SkewTransform" />
                    </TransformGroup>
                </Button.RenderTransform>
            </Button>
            <Button Width="30"
                    Canvas.Top="0"
                    Content="X">
                <Button.Triggers>
                    <EventTrigger RoutedEvent="Button.Click">
                        <EventTrigger.Actions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="a1SkewTransform"
                                                     Storyboard.TargetProperty="AngleX"
                                                     From="0"
                                                     To="-60"
                                                     BeginTime="0:0:0"
                                                     Duration="0:0:3" />
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger.Actions>
                    </EventTrigger>
                </Button.Triggers>
            </Button>
            <Button Width="30"
                    Canvas.Top="50"
                    Content="Y">
                <Button.Triggers>
                    <EventTrigger RoutedEvent="Button.Click">
                        <EventTrigger.Actions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="a2SkewTransform"
                                                     Storyboard.TargetProperty="AngleY"
                                                     From="0"
                                                     To="60"
                                                     BeginTime="0:0:0"
                                                     Duration="0:0:3" />
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger.Actions>
                    </EventTrigger>
                </Button.Triggers>
            </Button>
        </Canvas>
    I made a screenshot after both animations are completed and as far as I can tell the area was preserved.
    Wednesday, May 16, 2012 5:23 PM
  • I am delighted to have your attention so long in this contentious matter, and thank you for producing actual code.

    I now see what you mean about using two separate skew operators.

    Operating your code, the x and y parts work perfectly on their own, and you can see that each leaves one side  untouched, as they should. However, in succession the second operation does not leave a side untouched, and therefore is not performing a skew operation on the current parallelogram. You will see that my code does leave a side untouched so it does perform a skew operation,  and all that is wrong is the height (and therefore the area).

    As a lowly user, not implementor, I cannot see behind the curtain to know what your code is actually doing, and what is the difference in the two methodes. Although you do not explicitly claim to preform successive mixed skew operations it seems that skewing is of little use without it

     Thank you once again for your terrific support.

    Thursday, May 17, 2012 1:55 PM
  • Looking at your matrix algebra; I think I am using separate transforms, I am transforming an object that has aleady been transformed
    Thursday, May 17, 2012 3:37 PM
  • "I think I am using separate transforms, I am transforming an object that has aleady been transformed"

    Nope, the original object is never transformed. Every animation frame a new transform is computed and applied to the original object.

    "However, in succession the second operation does not leave a side untouched, and therefore is not performing a skew operation on the current parallelogram."

    The skew is performed with respect to the coordinate system, it has nothing to do with your parallelogram. If you watch carefully the second animation you'll notice that only the Y coordinate of the points changes, the X coordinate stays the same. That's expected because the skew occurs along the Y axis of the coordinate system, not of your parallelogram.

    If I understood correctly what you want then you need to add a rotate transform to change the coordinate system so the second skew is applied along the horizontal axis of the parallelogram. Something like this:

            <Canvas>
                <Button RenderTransformOrigin="1.0 1.0"
                        Canvas.Left="100"
                        Canvas.Top="160"
                        FontSize="24"
                        Width="100"
                        Content="a^a"
                        Height="100">
                    <Button.RenderTransform>
                        <TransformGroup>
                            <SkewTransform x:Name="a1SkewTransform" />
                            <RotateTransform x:Name="a2Rot1Transform" Angle="-60"/>
                            <SkewTransform x:Name="a2SkewTransform" />
                            <RotateTransform x:Name="a2Rot2Transform" Angle="60" />
                        </TransformGroup>
                    </Button.RenderTransform>
                </Button>
                <Button Width="30"
                        Canvas.Top="0"
                        Content="X">
                    <Button.Triggers>
                        <EventTrigger RoutedEvent="Button.Click">
                            <EventTrigger.Actions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="a1SkewTransform"
                                                         Storyboard.TargetProperty="AngleX"
                                                         From="0"
                                                         To="-60"
                                                         BeginTime="0:0:0"
                                                         Duration="0:0:3" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger.Actions>
                        </EventTrigger>
                    </Button.Triggers>
                </Button>
                <Button Width="30"
                        Canvas.Top="50"
                        Content="Y">
                    <Button.Triggers>
                        <EventTrigger RoutedEvent="Button.Click">
                            <EventTrigger.Actions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="a2SkewTransform"
                                                         Storyboard.TargetProperty="AngleY"
                                                         From="0"
                                                         To="60"
                                                         BeginTime="0:0:0"
                                                         Duration="0:0:3" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger.Actions>
                        </EventTrigger>
                    </Button.Triggers>
                </Button>
            </Canvas>

    The first rotate transform changes the coordinate system for the next skew transform. The last rotate transform undoes the effect of the first rotate transform, otherwise your rendered object will be both skewed and rotated.

    • Marked as answer by Sheldon _Xiao Thursday, May 24, 2012 6:54 AM
    Thursday, May 17, 2012 5:09 PM
  • By Ceorge, I think you've done it!  I'm going to think on it a while and also apply it to my main project;

    Ray

    Friday, May 18, 2012 8:13 PM
  • Your result is correct but you have distributed the angle specification partly in and partly out of the storyboard, so that the skew operation itself is not complete. I have not succeeded in repairing this myself yet.

    Saturday, May 19, 2012 2:15 PM
  • "you have distributed the angle specification partly in and partly out of the storyboard, so that the skew operation itself is not complete"

    Hmm, I'm not sure what you mean? Do you mean that the rotation angle needs to be animated too?

    Saturday, May 19, 2012 5:18 PM
  • I mean that half the skewing code is outside the animation and that is designed for this particular skew demo. If I wanted to do another X-Y skew on the same object, (which I don't), that initial code would be in the way. I won't press you on this because what you have done so far is heroic

    With your permission I will send you my (much longer) code foe a very nice illustration of Pythagoras"  Theorem, first my way of faking it and second doing it your way.

    Saturday, May 19, 2012 7:08 PM
  • I suppose this is about the rotation angle being hardcode in the transforms. I guess you could just add more animations to the first storyboard:

                                        <DoubleAnimation Storyboard.TargetName="a2Rot1Transform"
                                                         Storyboard.TargetProperty="Angle"
                                                         From="-60"
                                                         To="-60"
                                                         BeginTime="0:0:0"
                                                         Duration="0:0:3" />
                                        <DoubleAnimation Storyboard.TargetName="a2Rot2Transform"
                                                         Storyboard.TargetProperty="Angle"
                                                         From="60"
                                                         To="60"
                                                         BeginTime="0:0:0"
                                                         Duration="0:0:3" />
    This way you have the angle in the same place and it's easy to change.
    • Proposed as answer by Sheldon _Xiao Thursday, May 24, 2012 6:54 AM
    Saturday, May 19, 2012 8:19 PM
  • Hi rayreeves,
     
    I am marking your issue as "Answered", if you have new findings about your issue, please let me know.


    Best regards,


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, May 24, 2012 6:54 AM
  • The support I recieved was magnificent, and he eventually produced a workaround which was very helpful. However I still assert thatthe "skew" operator is flawed.
    Friday, May 25, 2012 3:36 PM