如何在 inkcanvas 上同时进行缩放和旋转?

发布于 2024-11-02 17:24:33 字数 2964 浏览 6 评论 0原文

使用以下 XAML:

<Grid x:Name="grid" Background="LightBlue" ClipToBounds="True">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
    <Viewbox x:Name="imgViewbox" >
                <InkCanvas Grid.Row="0" Name="inkCanvas" Background="Red" >
                <Image Source="Images/pic.png" HorizontalAlignment="Left" x:Name="imgObject" VerticalAlignment="Top"  />
                <Label>Testing</Label>
                </InkCanvas>
    </Viewbox>
</Grid>

我尝试围绕图像中心旋转并使用鼠标滚轮进行缩放。我已经设置了这个变换组和事件:

public MainWindow() {

    InitializeComponent();
    DataContext = new MainWindowViewModel();

    transformGroup = new TransformGroup();
    scaleTransform = new ScaleTransform();
    rotateTransform = new RotateTransform();
    translateTransform = new TranslateTransform();
    transformGroup.Children.Add(rotateTransform);
    transformGroup.Children.Add(scaleTransform);
    transformGroup.Children.Add(translateTransform);

    imgViewbox.RenderTransform = transformGroup;

    imgViewbox.MouseWheel += ImageViewboxMouseWheel;
}

旋转很简单:

void Rotate(object sender, RoutedEventArgs e) {
    //imgViewbox.RenderTransformOrigin = new Point(0.5,0.5);
    rotateTransform.Angle += 90;
}

但是缩放正在屏幕上跳跃做各种奇怪的事情。缩放的代码在这里:

void ImageViewboxMouseWheel(object sender, MouseWheelEventArgs e) {
    //imgViewbox.RenderTransformOrigin = new Point(0, 0);
    double zoomFactor = DefaultZoomFactor;
    if (e.Delta <= 0) zoomFactor = 1.0 / DefaultZoomFactor;
    // DoZoom requires both the logical and physical location of the mouse pointer
    var physicalPoint = e.GetPosition(imgViewbox);
    if (transformGroup.Inverse != null) {
        DoZoom(zoomFactor, transformGroup.Inverse.Transform(physicalPoint), physicalPoint);
    }
    else {
        throw new ArgumentException("Missing Inverse");
    }

    //Set the center point of the ScaleTransform object to the cursor location.
    scaleTransform.CenterX = e.GetPosition(imgViewbox).X;
    scaleTransform.CenterY = e.GetPosition(imgViewbox).Y;
    Debug.WriteLine(string.Format("IVMW Center {0},{1}", scaleTransform.CenterX, scaleTransform.CenterY));
}

public void DoZoom(double deltaZoom, Point mousePosition, Point physicalPosition) {
    double currentZoom = scaleTransform.ScaleX;
    currentZoom *= deltaZoom;

    translateTransform.X = -1*(mousePosition.X*currentZoom - physicalPosition.X);
    translateTransform.Y = -1*(mousePosition.X*currentZoom - physicalPosition.Y);
    scaleTransform.ScaleX = currentZoom;
    scaleTransform.ScaleY = currentZoom;
}

我已经删除了尽可能多的动画等。希望只留下关键部分。我认为主要问题是scaleTransform.Center[X|Y],因为即使我尝试在同一位置精确单击,返回的数字也遍布象限。 RenderTransformOrigin 似乎与中心位置没有任何区别,但我知道我需要它围绕中心旋转。

我做错了什么?

Using the following XAML:

<Grid x:Name="grid" Background="LightBlue" ClipToBounds="True">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
    <Viewbox x:Name="imgViewbox" >
                <InkCanvas Grid.Row="0" Name="inkCanvas" Background="Red" >
                <Image Source="Images/pic.png" HorizontalAlignment="Left" x:Name="imgObject" VerticalAlignment="Top"  />
                <Label>Testing</Label>
                </InkCanvas>
    </Viewbox>
</Grid>

I am trying to rotate around the center of the image and also use the wheel mouse to zoom. I have set up this transform group and event:

public MainWindow() {

    InitializeComponent();
    DataContext = new MainWindowViewModel();

    transformGroup = new TransformGroup();
    scaleTransform = new ScaleTransform();
    rotateTransform = new RotateTransform();
    translateTransform = new TranslateTransform();
    transformGroup.Children.Add(rotateTransform);
    transformGroup.Children.Add(scaleTransform);
    transformGroup.Children.Add(translateTransform);

    imgViewbox.RenderTransform = transformGroup;

    imgViewbox.MouseWheel += ImageViewboxMouseWheel;
}

Rotate is simple:

void Rotate(object sender, RoutedEventArgs e) {
    //imgViewbox.RenderTransformOrigin = new Point(0.5,0.5);
    rotateTransform.Angle += 90;
}

but zoom is doing all sorts of weird stuff jumping around the screen. The code for zoom is here:

void ImageViewboxMouseWheel(object sender, MouseWheelEventArgs e) {
    //imgViewbox.RenderTransformOrigin = new Point(0, 0);
    double zoomFactor = DefaultZoomFactor;
    if (e.Delta <= 0) zoomFactor = 1.0 / DefaultZoomFactor;
    // DoZoom requires both the logical and physical location of the mouse pointer
    var physicalPoint = e.GetPosition(imgViewbox);
    if (transformGroup.Inverse != null) {
        DoZoom(zoomFactor, transformGroup.Inverse.Transform(physicalPoint), physicalPoint);
    }
    else {
        throw new ArgumentException("Missing Inverse");
    }

    //Set the center point of the ScaleTransform object to the cursor location.
    scaleTransform.CenterX = e.GetPosition(imgViewbox).X;
    scaleTransform.CenterY = e.GetPosition(imgViewbox).Y;
    Debug.WriteLine(string.Format("IVMW Center {0},{1}", scaleTransform.CenterX, scaleTransform.CenterY));
}

public void DoZoom(double deltaZoom, Point mousePosition, Point physicalPosition) {
    double currentZoom = scaleTransform.ScaleX;
    currentZoom *= deltaZoom;

    translateTransform.X = -1*(mousePosition.X*currentZoom - physicalPosition.X);
    translateTransform.Y = -1*(mousePosition.X*currentZoom - physicalPosition.Y);
    scaleTransform.ScaleX = currentZoom;
    scaleTransform.ScaleY = currentZoom;
}

I have removed as much as I can, animations and such. Hopefully leaving only the key parts. I believe that the major problem is the scaleTransform.Center[X|Y] as the numbers that are being returned are all over the quadrant even when I try to click exactly in the same location. The RenderTransformOrigin doesn't seem to make any difference with the Center position but I am aware that I need it to rotate around center.

What am I doing wrong?

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

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

发布评论

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

评论(1

月光色 2024-11-09 17:24:33

您需要抵消在 TranslateTransform 中更改 ScaleTranform 的 CenterX/Y 所产生的跳跃,这是来自 pan & 的片段。缩放控件我写道:

private void This_MouseWheel(object sender, MouseWheelEventArgs e)
{
    if (IsZoomEnabled)
    {
        Point cursorPos = e.GetPosition(this);
        Point newCenter = _scaleT.Inverse.Transform(_translateT.Inverse.Transform(cursorPos));
        Point oldCenter = new Point(_scaleT.CenterX, _scaleT.CenterY);
        Vector oldToNewCenter = newCenter - oldCenter;
        _scaleT.CenterX = newCenter.X;
        _scaleT.CenterY = newCenter.Y;
        _translateT.X += oldToNewCenter.X * (_scaleT.ScaleX - 1.0);
        _translateT.Y += oldToNewCenter.Y * (_scaleT.ScaleY - 1.0);
        ...

希望您可以将其适应您的代码。在计算新中心的地方,您可能需要考虑 RotateTransform。

You need to offset the jump you get from changing the ScaleTranform's CenterX/Y in the TranslateTransform, here is a snippet from a pan & zoom control i wrote:

private void This_MouseWheel(object sender, MouseWheelEventArgs e)
{
    if (IsZoomEnabled)
    {
        Point cursorPos = e.GetPosition(this);
        Point newCenter = _scaleT.Inverse.Transform(_translateT.Inverse.Transform(cursorPos));
        Point oldCenter = new Point(_scaleT.CenterX, _scaleT.CenterY);
        Vector oldToNewCenter = newCenter - oldCenter;
        _scaleT.CenterX = newCenter.X;
        _scaleT.CenterY = newCenter.Y;
        _translateT.X += oldToNewCenter.X * (_scaleT.ScaleX - 1.0);
        _translateT.Y += oldToNewCenter.Y * (_scaleT.ScaleY - 1.0);
        ...

Hopefully you can adapt this to your code. Where the new center is calculated you might need to take your RotateTransform into account.

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