2010-01-27 13 views
3

Je fais une application de surface où je dois escalader ma scène (zoom) pendant que l'utilisateur échelles avec leurs doigts (c.-à-pincements)Comment calculer traduire tout en effectuant un zoom avant WPF/Surface

Actuellement, je l'ai travail ok, mais le problème est que je dois zoomer sur le point central entre les doigts des utilisateurs. J'ai le point, mais les maths derrière la traduction sont difficiles à comprendre. Lorsque j'applique un ScaleTransform à ma scène de toile, il zoome en haut à gauche de la toile, j'en ai besoin pour zoomer sur le point central de mon geste de pincement (ce que, encore une fois, j'ai).

Comment les maths de la traduction fonctionneraient-ils pour que le zoom apparaisse pour faire un zoom avant sur le point central du mouvement?

Edit:

Ceci est essentiellement ce que j'ai:

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

vraiment basique Jolie, mais il fonctionne à un point ...

_zoomTransform est un ScaleTransform et _translateTransform est un TranslateTransform

MainViewport est une toile qui contient ZoomCanvas qui est le canevas auquel j'applique les transformations.

Répondre

1

Voici ma mise en œuvre qui a fini par travailler très bien

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

Je devais faire exactement cela moi-même. Fondamentalement, un contrôle de Surface qui peut héberger du contenu arbitraire et permettre à l'utilisateur de faire un panoramique et un zoom (en utilisant des gestes). Le gestionnaire de mon processeur de maniplation Affine2DManipulationDelta est illustré ci-dessous. Espérons que c'est assez explicite et que vous obtenez où vous devez être.

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

Juste quelques questions, est '' Scale', CanPan' et 'CanScale' seulement des propriétés personnalisées? Ou avez-vous étendu un 'ScrollViewer'? Est-ce que l'utilisation de scrollviewer serait plus facile qu'avec des traductions X et Y? – Mark