如何计算缩放至X/Y坐标?

4
我正在编写一个WPF应用程序,它具有缩放和平移功能,但我想实现的是通过单击按钮“自动”缩放和平移。

我已经定义了所有缩放和平移的方法,但我无法告诉应用程序所需的平移X/Y坐标。

基本上,我知道我希望控件在所需的缩放级别下居中(比如6倍缩放),但是平移目标点不是控件的中心点,因为在缩放后,它已经被缩放了。

是否有人知道一种计算要平移到的所需X/Y位置的方法,同时考虑到缩放? 我只需要对所需的目标点进行缩放吗? 但这对我似乎不起作用...

非常感谢

编辑--已完成--

现在这就是我拥有的可以正常工作的代码 :)

<Canvas x:Name="LayoutRoot" Background="{DynamicResource WindowBackground}" Width="1024" Height="768">
    <Canvas x:Name="ProductCanvas" Width="1024" Height="768">
        <Canvas.RenderTransform>
            <TransformGroup>
                <ScaleTransform/>
                <SkewTransform/>
                <RotateTransform/>
                <TranslateTransform />
            </TransformGroup>
        </Canvas.RenderTransform>
        <Rectangle x:Name="r1" Fill="White" Stroke="Black" Width="180" Height="103.5" Canvas.Left="131.5" Canvas.Top="121.5" MouseDown="r1_MouseDown"/>
        <Rectangle x:Name="r2" Fill="#FF942222" Stroke="Black" Width="180" Height="103.5" Canvas.Left="617.5" Canvas.Top="121.5" MouseDown="r2_MouseDown"/>
        <Rectangle x:Name="r3" Fill="#FF2B1E9F" Stroke="Black" Width="180" Height="103.5" Canvas.Left="131.5" Canvas.Top="408" MouseDown="r3_MouseDown"/>
        <Rectangle x:Name="r4" Fill="#FF1F6E1D" Stroke="Black" Width="180" Height="103.5" Canvas.Left="617.5" Canvas.Top="408" MouseDown="r4_MouseDown"/>
    </Canvas>
  </Canvas>

----C#----

    private void r1_MouseDown(object sender, MouseButtonEventArgs e1)
    {
        Rect bounds = r1.TransformToAncestor(ProductCanvas).TransformBounds(new Rect(0, 0, r1.ActualWidth, r1.ActualHeight));
        ZoomInAndPan(5, new Point(bounds.TopLeft.X + (bounds.Width / 2), bounds.TopLeft.Y + (bounds.Height / 2)));
    }

    private void r2_MouseDown(object sender, MouseButtonEventArgs e1)
    {
        Rect bounds = r2.TransformToAncestor(ProductCanvas).TransformBounds(new Rect(0, 0, r2.ActualWidth, r2.ActualHeight));
        ZoomInAndPan(5, new Point(bounds.TopLeft.X + (bounds.Width / 2), bounds.TopLeft.Y + (bounds.Height / 2)));
    }

    private void r3_MouseDown(object sender, MouseButtonEventArgs e1)
    {
        Rect bounds = r3.TransformToAncestor(ProductCanvas).TransformBounds(new Rect(0, 0, r3.ActualWidth, r3.ActualHeight));
        ZoomInAndPan(5, new Point(bounds.TopLeft.X + (bounds.Width / 2), bounds.TopLeft.Y + (bounds.Height / 2)));
    }

    private void r4_MouseDown(object sender, MouseButtonEventArgs e1)
    {
        Rect bounds = r4.TransformToAncestor(ProductCanvas).TransformBounds(new Rect(0, 0, r4.ActualWidth, r4.ActualHeight));
        ZoomInAndPan(5, new Point(bounds.TopLeft.X + (bounds.Width/2), bounds.TopLeft.Y + (bounds.Height/2)));
    }

    public void ZoomInAndPan(double zoomTo, Point translateTarget)
    {
        var group = (ProductCanvas.RenderTransform as TransformGroup);

        var zoomTransform = group.Children[0] as ScaleTransform;
        var translateTransform = group.Children[3] as TranslateTransform;

        Point center = new Point(512, 384);

        destinationPoint.X *= newScale;
        destinationPoint.Y *= newScale;

        var deltaX = center.X - (translateTarget.X);
        var deltaY = center.Y - (translateTarget.Y);

        translateTransform.BeginAnimation(TranslateTransform.XProperty, CreateZoomAnimation(deltaX));
        translateTransform.BeginAnimation(TranslateTransform.YProperty, CreateZoomAnimation(deltaY));

        zoomTransform.BeginAnimation(ScaleTransform.ScaleXProperty, CreateZoomAnimation(zoomTo));
        zoomTransform.BeginAnimation(ScaleTransform.ScaleYProperty, CreateZoomAnimation(zoomTo));
    }

    private DoubleAnimation CreateZoomAnimation(double toValue)
    {
        var da = new DoubleAnimation(toValue, new Duration(TimeSpan.FromMilliseconds(700)))
        {
            AccelerationRatio = 0.1,
            DecelerationRatio = 0.9
        };

        return da;
    }
2个回答

5

你说的是一种变换——平移和缩放。

你可以用几种不同的方法来实现这个效果,但既然你正在使用WPF,那么你为什么不能直接使用RenderTransforms呢?

var pointClicked = (where user clicked)
var myWindow = (whatever your window is);

myWindow.RenderTransform = new TransformGroup();
var pan = new TranslateTransform(pointClicked.X, pointClicked.Y);
var scale = new ScaleTransform(6.0,6.0);
myWindow.RenderTransform.Children.Add(pan);
myWindow.RenderTransform.Children.Add(scale);

如果您不想采用这种方法,您需要手动进行2D转换:先进行平移,然后进行缩放。通常情况下,变换是不可交换的;如果您按不同的顺序执行它们,将会得到错误的结果。

我的变换已经正常工作,但问题是我无法计算所需的X/Y平移量,以便将一个点平移到屏幕中心。 - Mark
这就是我所说的操作顺序 - 你是否先尝试过翻译(即,新中心 = clickpoint.X,clickpoint.Y),然后再进行缩放? - JerKimball
换句话说:如果我点击点(50,50),我应该先将视图重新定位到点(50,50),然后执行缩放。如果你反过来做,为了将其翻译到正确的点,你必须通过比例来转换原始翻译...听起来比实际情况更令人困惑。基本上,为了计算出缩放后的deltaX / deltaY,您需要将deltaX / deltaY 本来应该是的向量按照您的缩放变换进行缩放。 - JerKimball
嗯,那听起来像是正确的想法...我会试一试 :) - Mark
你已经接近成功了 - 你只需要转换翻译向量:deltaX = center.X - translateTarget.X * zoomTo; deltaY = center.Y - translateTarget.Y * zoomTo; 并删除 /= 行 - 这是你不需要的相反操作。 - JerKimball
完成并且可用!非常感谢您的帮助,这将对项目有很大的帮助! - Mark

1

最初,您的视口位于(0,0),图像和视口的大小均为X乘以Y。 您想通过某个放大因子m来缩放大小,使得您的图像大小为mX乘以mY,但您的视口(您正在显示的部分)仍然是一个大小为X乘以Y的矩形,在图像上的位置为(0,0)。 因此,您需要移动视口。

如果您的图像现在是mX乘以mY,则可以通过将每个值除以二来找到中点。 然后,您可以减去视口大小的一半以获得左上角。 类似于(mX/2-X/2,mY/2-Y/2)。


我理解你的意思,但是我仍然不清楚如何计算所需的平移量,以便将所需点动画到屏幕中心。 - Mark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接