Combining RotateTransform and TranslateTransform

不打扰是莪最后的温柔 提交于 2020-08-26 10:20:52

问题


I am using the Thumb class to let the user drag and drop an image across a canvas. When the right button gets pressed, i want the user to be able to rotate the image. The rotation is based around the center of the image. I have the following XAML Code

<Grid>

    <Canvas Background="Red" Grid.RowSpan="2" x:Name="canvas" 
        PreviewMouseRightButtonUp="Canvas_MouseUp" 
        PreviewMouseMove="Canvas_MouseMove">

        <UserControl MouseRightButtonDown="Canvas_MouseDown" RenderTransformOrigin="0.5,0.5">

            <Thumb Name="myRoot" DragDelta="myRoot_DragDelta">
                <Thumb.Template>
                    <ControlTemplate>
                        <Grid>

                            <Image Source="/WpfApplication1;component/someImage.png" />

                            <Rectangle Stroke="#FF0061CE" StrokeThickness="1" Width="230" Height="250" />

                        </Grid>
                    </ControlTemplate>
                </Thumb.Template>
            </Thumb>

            <UserControl.RenderTransform>
                <TransformGroup>
                    <RotateTransform x:Name="rotateTransform" />
                    <TranslateTransform x:Name="translateTransform" />
                </TransformGroup>
            </UserControl.RenderTransform>
        </UserControl>

    </Canvas>

</Grid>

And this code behind

    bool isMouseDown = false;
    Point pos;
    double lastAngle = 0;

    private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
    {
        isMouseDown = true;
        lastAngle = rotateTransform.Angle;
        pos = Mouse.GetPosition(canvas);
    }   

    private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
    {
        isMouseDown = false;
    }

    private void Canvas_MouseMove(object sender, MouseEventArgs e)
    {
        if (!isMouseDown) return;

        var curPos = Mouse.GetPosition(canvas);
        rotateTransform.Angle = lastAngle + (pos.Y - curPos.Y);
    }

    private void myRoot_DragDelta(object sender, DragDeltaEventArgs e)
    {
        translateTransform.X += e.HorizontalChange;
        translateTransform.Y += e.VerticalChange; 
    }

It works if i only drag and drop the image around the screen and rotate the image a small amount (50 degrees in any direction seems ok). However manipulating it more than that and the image starts move around the screen unpredictibly.

I have tried moving the transformations to different controls, so to not to mix them up but have not received an acceptable result.

How can i get my code to behave like i want?

UPDATE: This is driving my crazy. I have changed the code and XAML to use a MatrixTransformation instead

    private void Canvas_MouseMove(object sender, MouseEventArgs e)
    {
        if (!isMouseDown) return;

        var curPos = Mouse.GetPosition(canvas);

        angle = (lastAngle + (pos.Y - curPos.Y)) % 360;

        UpdateMatrixTransform();
    }

    private void myRoot_DragDelta(object sender, DragDeltaEventArgs e)
    {
        posX += e.HorizontalChange;
        posY += e.VerticalChange;  

        UpdateMatrixTransform();
    }

    void UpdateMatrixTransform()
    {
        Matrix m = new Matrix();


        m.Rotate(angle);

        m.OffsetX = posX;
        m.OffsetY = posY;

        matrixT.Matrix = m;
    }

In my mind, this should work: First, rotate the graphic than move it to the offset. It does not work like i expect it to. It rotates the image, but than moves it strangely in spiral fashion outwards if i keep moving the mouse. No matter what i do, and in what order i execute my transformations, it wont work.


回答1:


I'm not sure why you're using a UserControl to wrap the Thumb since it should be able to act as the root element here. Here is a solution that involes scrapping the use of TranslateTransform and instead using Canvas.Left and Canvas.Top properties:

EDIT: Updated Answer

Here's the XAML:

<Canvas x:Name="canvas">
    <Thumb Name="myRoot"
            Canvas.Left="0" Canvas.Top="0"
            DragDelta="myRoot_DragDelta"
            MouseMove="myRoot_MouseMove"
            MouseDown="myRoot_MouseDown"
            MouseUp="myRoot_MouseUp">
        <Thumb.Template>
            <ControlTemplate>
                <Grid RenderTransformOrigin="0.5, 0.5">
                    <Rectangle Fill="AliceBlue"
                               Stroke="#FF0061CE"
                               StrokeThickness="1"
                               Width="100" Height="100"/>
                    <Grid.RenderTransform>
                        <RotateTransform x:Name="rotateTransform" />
                    </Grid.RenderTransform>
                </Grid>
            </ControlTemplate>
        </Thumb.Template>
    </Thumb>
</Canvas>

And here's the code behind:

public partial class TestWindow : Window
{
    public TestWindow()
    {
        InitializeComponent();
    }

    Point? lastPosition = null;
    RotateTransform rotateTransform;

    private void myRoot_MouseDown(object sender, MouseButtonEventArgs e)
    {
        lastPosition = null;

        if (e.ChangedButton == MouseButton.Right)
            myRoot.CaptureMouse();
    }

    private void myRoot_MouseUp(object sender, MouseButtonEventArgs e)
    {
        if (e.ChangedButton == MouseButton.Right)
            myRoot.ReleaseMouseCapture();
    }

    private void myRoot_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.RightButton == MouseButtonState.Pressed)
        {
            Point curPosition = Mouse.GetPosition(myRoot);

            if (lastPosition != null)
            {
                Point centerPoint = new Point(myRoot.ActualWidth / 2, myRoot.ActualWidth / 2);

                if (rotateTransform == null)
                    rotateTransform = (RotateTransform)myRoot.Template.FindName("rotateTransform", myRoot);

                rotateTransform.Angle = Math.Atan2(curPosition.Y - centerPoint.Y, curPosition.X - centerPoint.X) * 100;
            }

            lastPosition = curPosition;
            e.Handled = true;
        }
    }

    private void myRoot_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
    {
        Canvas.SetLeft(myRoot, Canvas.GetLeft(myRoot) + e.HorizontalChange);
        Canvas.SetTop(myRoot, Canvas.GetTop(myRoot) + e.VerticalChange);
    }
}



回答2:


You have to tell the RotateTransform that you want to rotate around the center of the object rather than the center of the coordinate system, which is the default. To do that, set the CenterX and CenterY properties of the RotateTransform to the center of the object.



来源:https://stackoverflow.com/questions/10885380/combining-rotatetransform-and-translatetransform

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!