Как рассчитать перевод при масштабировании в WPF / Surface - PullRequest
3 голосов
/ 27 января 2010

Я делаю поверхностное приложение, в котором мне нужно масштабировать сцену (масштабирование), пока пользователь масштабирует пальцами (т.е. сжимая)

В настоящее время у меня все работает нормально, но проблема в том, что мне нужно увеличить центральную точку между пальцами пользователей.

Я имею в виду, но математика за переводом трудно понять.

Когда я применяю ScaleTransform к моей сцене холста, она увеличивается в левом верхнем углу холста, мне нужно, чтобы увеличить центральную точку моего жеста повышения (что, опять же, у меня есть).

Как математика для перевода будет работать, чтобы масштабирование отображалось для увеличения центральной точки жеста?

Изменить:

Это в основном то, что у меня есть:

void Affine2DManipulationDelta(object sender, Affine2DOperationDeltaEventArgs e)
{
    //apply zoom and translate
    if (e.ScaleDelta != 1)
        ApplyZoom(e);
    else if (e.Delta.Length != 0)
        ApplyTranslation(e);
}

private void ApplyZoom(Affine2DOperationDeltaEventArgs e)
{
    //scale
    var newScale = _zoomTransform.ScaleX * e.ScaleDelta;
    newScale = GetCappedZoomLevel(newScale);

    _zoomTransform.ScaleX = newScale;
    _zoomTransform.ScaleY = newScale;
}

private void ApplyTranslation(Affine2DOperationDeltaEventArgs e)
{
    var xDiff = e.ManipulationOrigin.X - _screenStartPoint.X;
    var yDiff = e.ManipulationOrigin.Y - _screenStartPoint.Y;

    var translateX = xDiff + _startOffset.X;
    var translateY = yDiff + _startOffset.Y;

    //bounds testing to limit translation
    var rect = new Rect(0.0, 0.0, ZoomCanvas.RenderSize.Width, ZoomCanvas.RenderSize.Height);
    Rect bounds = ZoomCanvas.TransformToAncestor(MainViewportCanvas).TransformBounds(rect);

    if (CanTranslateX(translateX, bounds))
        _translateTransform.X = translateX;

    if (CanTranslateY(translateY, bounds))
        _translateTransform.Y = translateY;
}

На самом деле довольно просто, но работает до определенной степени ...

_zoomTransform является ScaleTransform, а _translateTransform является TranslateTransform

MainViewport - это холст, содержащий ZoomCanvas, который является холстом, к которому я применяю преобразования.

Ответы [ 2 ]

1 голос
/ 01 февраля 2010

Вот моя реализация, которая в итоге работала просто отлично

private void ApplyZoom(Affine2DOperationDeltaEventArgs e)
    {
        //scale
        var newScale = _zoomTransform.ScaleX * e.ScaleDelta;
        newScale = GetCappedZoomLevel(newScale);
        var pinchPoint = e.ManipulationOrigin;
        DoZoom(newScale, _transformGroup.Inverse.Transform(pinchPoint), pinchPoint);
    }

    private void DoZoom(double newScale, Point pinchPosition, Point physicalPosition)
    {
        _translateTransform.X = -1 * (pinchPosition.X * newScale - physicalPosition.X);
        _translateTransform.Y = -1 * (pinchPosition.Y * newScale - physicalPosition.Y);
        _zoomTransform.ScaleX = newScale;
        _zoomTransform.ScaleY = newScale;
    }
1 голос
/ 27 января 2010

Я должен был сделать именно это сам. По сути, это элемент управления Surface, который может содержать произвольный контент и позволяет пользователю перемещаться и масштабировать (используя жесты). Обработчик для Affine2DManipulationDelta моего процессора манипуляции показан ниже. Надеюсь, это говорит само за себя и поможет вам быть там, где вам нужно.

private void OnManipulationDelta(object sender, Affine2DOperationDeltaEventArgs e)
{
    Debug.Assert(_scrollViewer != null);

    if (CanScale && _scrollViewer != null && e.ScaleDelta != 1)
    {
        var scrollViewerContent = _scrollViewer.Content as UIElement;

        //can't do anything if the content isn't present and isn't a UIElement
        if (scrollViewerContent != null)
        {
            var newScale = Scale * e.ScaleDelta;

            newScale = Math.Max(MinScale, newScale);
            newScale = Math.Min(MaxScale, newScale);

            var origin = e.ManipulationOrigin;
            var pointInContent = _scrollViewer.TranslatePoint(origin, scrollViewerContent);

            var deltaScale = newScale - Scale;
            //width and height changes across the whole image
            var deltaWidth = deltaScale * _scrollViewer.ExtentWidth;
            var deltaHeight = deltaScale * _scrollViewer.ExtentHeight;
            //width and height changes relative to the point in the scroll viewer's content
            deltaWidth = (pointInContent.X / _scrollViewer.ExtentWidth) * deltaWidth;
            deltaHeight = (pointInContent.Y / _scrollViewer.ExtentHeight) * deltaHeight;

            _offset = Vector.Add(_offset, new Vector(deltaWidth, deltaHeight));
            var centerPoint = new Point(origin.X + deltaWidth, origin.Y + deltaHeight);
            centerPoint.Offset(_offset.X, _offset.Y);

            Scale = newScale;

            HorizontalOffset = _scrollViewer.HorizontalOffset + deltaWidth;
            VerticalOffset = _scrollViewer.VerticalOffset + deltaHeight;
        }
    }
    else if (CanPan && e.Delta.Length != 0)
    {
        var newHorizontalOffset = _scrollViewer.HorizontalOffset + (e.Delta.X * -1);
        var newVerticalOffset = _scrollViewer.VerticalOffset + (e.Delta.Y * -1);
        newHorizontalOffset = Math.Max(0, newHorizontalOffset);
        newVerticalOffset = Math.Max(0, newVerticalOffset);
        HorizontalOffset = newHorizontalOffset;
        VerticalOffset = newVerticalOffset;
    }
}
...