Как я могу сделать масштабирование и поворот на чернильном холсте? - PullRequest
3 голосов
/ 21 апреля 2011

Использование следующего 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, похоже, не имеет никакого значения для позиции центра, но я знаю, что мне нужно, чтобы она вращалась вокруг центра.

Что я делаю не так?

1 Ответ

1 голос
/ 21 апреля 2011

Вам необходимо компенсировать скачок, который вы получаете от изменения CenterX / Y ScaleTranform в TranslateTransform, вот фрагмент из элемента управления панорамированием и масштабированием, который я написал:

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.

...