如何计算要缩放到的 X/Y 坐标

发布于 2024-08-23 07:37:33 字数 4060 浏览 3 评论 0原文

我正在编写一个具有缩放和平移功能的 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;
    }

Im writing a WPF application that has a zoom and pan ability, but what I want to also implement is the ability to zoom and pan "automatically" (via a button click).

I have the methods all defined to zoom and pan, but Im having trouble telling the app the desired X/Y coordinates for the panning.

Basically, I know that I want the control to be centered at a desired zoom level (say zoomed in 6X times), but the panning destination point is NOT the center point of the control because after the zooming, its been scaled.

Does anyone know a way of calculating the desired X/Y position to pan to, taking into account the zooming as well? Do I just scale the desired destination Point? It doesnt seem to work for me...

Thanks a lot

EDIT -- COMPLETED --

Here is now what I have which is working just fine :)

<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;
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

栩栩如生 2024-08-30 07:37:33

你谈论的是一种转变——平底锅和天平。

您可以通过几种不同的方式来完成此操作,但由于您使用的是 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 转换:但首先进行平移,然后进行缩放。转变通常不是交流性的;如果你以不同的顺序执行它们,你会得到错误的结果。

You're talking about a transformation - a pan and a scale.

You can do this a couple of different ways, but since you are using WPF, is there a reason you can't just use the 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);

If you don't want to go that route, you need to do the 2D transformation "by hand": but do the pan first, then the scale. Transformations are not usually communitive; you'll get wrong results if you do them in a different order.

灯角 2024-08-30 07:37:33

最初,您的视口位于 (0,0),图像和视口的大小均为 X x Y。您希望通过某个放大系数 m 缩放大小,以便图像的大小为 mX x m Y,但您的视口(您显示的部分)仍然是一个大小为 X x Y 的矩形,位于图像上的 (0,0) 处。所以你需要移动视口。

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

Initially your viewport is at (0,0) and both the image and the viewport is of size X by Y. You want to scale the size by some magnification factor, m so that your images is of size mX by mY, but your viewport (the part you're showing) is still a rectangle of size X by Y, positioned at (0,0) on the image. So you need to move the view port.

If your image is now mX by mY, you can find the midpoints by dividing each by two. You can then subtract half of the viewport size to get the upper left corner. Something like (mX/2 - X/2, mY/2 - Y/2).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文