locked
How to detect pinch in or out and value? RRS feed

  • Question

  • I'm well aware of the gesture sample.

    What I'm looking for is to [1] get whether the user is pinching inward (fingers moving toward each other) or outward (fingers moving away from each other) and [2] the change in distances in real time. 

    I'm not just looking for a simple manipulation gesture of an object.  I've searched all over and have found nothing that pertains to what I'm looking for.  Please help.

    Tuesday, October 14, 2014 2:52 AM

Answers

  • I took a different approach to this.  Maybe Manipulation methods work, but this one works well for me. 

    <Grid x:Name="MainGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" PointerPressed="Grid_PointerPressed" PointerMoved="Grid_PointerMoved" PointerReleased="Grid_PointerReleased">
            <StackPanel VerticalAlignment="Bottom" Margin="10">
                <StackPanel Orientation="Horizontal"  Margin="5"> 
                    <TextBox Text="Direction"/>
                    <TextBox x:Name="Direction"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal"  Margin="5">
                    <TextBox Text="Distance"/>
                    <TextBox x:Name="Distance"/>
                </StackPanel>
            </StackPanel>
        </Grid>
        public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
            }
    
    
            uint Pointer1Id = 0, Pointer2Id = 0;
            Point Pointer1Position, Pointer2Position;
            bool Pointer1Pressed = false, Pointer2Pressed = false;
            double PreviousDistance = 0;
    
            private void Grid_PointerPressed(object sender, PointerRoutedEventArgs e)
            {
                if (Pointer1Id == 0)
                {
                    Pointer1Id = e.Pointer.PointerId;
                    Pointer1Pressed = true;
                }
                else if (Pointer2Id == 0)
                {
                    Pointer2Id = e.Pointer.PointerId;
                    Pointer2Pressed = true;
                }
            }
    
            private void Grid_PointerMoved(object sender, PointerRoutedEventArgs e)
            {
                if (Pointer1Pressed && Pointer2Pressed)
                {
                    if (e.Pointer.PointerId == Pointer1Id) Pointer1Position = e.GetCurrentPoint(MainGrid).Position;
                    else if (e.Pointer.PointerId == Pointer2Id) Pointer2Position = e.GetCurrentPoint(MainGrid).Position;
                    else return;
                    double CurrentDistance = CalculateLength(Pointer1Position, Pointer2Position);
                    Distance.Text = CurrentDistance.ToString();
                    Direction.Text = PreviousDistance >= CurrentDistance ? "Pinch" : "Expand";
                    PreviousDistance = CurrentDistance;
                }
            }
    
            private double CalculateLength (Point A,Point B)
            {
                double DeltaX = A.X - B.X;
                double DeltaY = A.Y - B.Y;
                DeltaX *= DeltaX;
                DeltaY *= DeltaY;
                return System.Math.Sqrt(DeltaX + DeltaY);
            }
    
    
    
    
            private void Grid_PointerReleased(object sender, PointerRoutedEventArgs e)
            {
                if (e.Pointer.PointerId == Pointer1Id)
                {
                    Pointer1Id = 0;
                    Pointer1Pressed = false;
                }
                else if (e.Pointer.PointerId == Pointer2Id)
                {
                    Pointer2Id = 0;
                    Pointer2Pressed = false;
                }
            }
          
        }



    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Wednesday, October 15, 2014 7:24 PM
    Moderator
  • Are you setting your ManipulationMode to All so you get scale and translate information? You can ignore the rotation fields if you don't want to use them.

    As Matt demonstrates, if you need completely custom gesture handling you can do it at the pointer level, but that is less efficient and will be less smooth than using manipulation events or the GestureRecognizer for the standard gestures.

    --Rob

    Wednesday, October 15, 2014 9:20 PM
    Moderator

All replies

  • Hi Randy - I'm working on a sample for you. It's almost ready, I expect to have it finished tomorrow.

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Tuesday, October 14, 2014 8:35 PM
    Moderator
  • You can look at the ManipulationDelta's values to see what effects they'll have.

    Pinching inward will scale down so ManipulationDeltaRoutedEventArgs.Delta.Scale will be less than one.

    Zooming outward will scale up so ManipulationDeltaRoutedEventArgs.Delta.Scale will be greater than one.

    You may want to track this over multiple frames to cover up any jittering.

    Likewise, the ManipulationDeltaRoutedEventArgs.Delta.Scale.X and Y will trend with distance. If you want speed you can track the initial time for the ManipulationStarted event and subtract it from the time of the ManipulationDelta event. Divide the distance by the time for speed.

    For more real time effects you can track the distance over a smaller amount of time rather than the entire gesture.

    Tuesday, October 14, 2014 9:22 PM
    Moderator
  • You can look at the ManipulationDelta's values to see what effects they'll have.

    Pinching inward will scale down so ManipulationDeltaRoutedEventArgs.Delta.Scale will be less than one.

    Zooming outward will scale up so ManipulationDeltaRoutedEventArgs.Delta.Scale will be greater than one.

    You may want to track this over multiple frames to cover up any jittering.

    Likewise, the ManipulationDeltaRoutedEventArgs.Delta.Scale.X and Y will trend with distance. If you want speed you can track the initial time for the ManipulationStarted event and subtract it from the time of the ManipulationDelta event. Divide the distance by the time for speed.

    For more real time effects you can track the distance over a smaller amount of time rather than the entire gesture.


    Thank you for your reply.  Unfortunately, I've already tried this.  No matter how much I pinch or which way, the value is always 1.
    Tuesday, October 14, 2014 10:17 PM
  • I took a different approach to this.  Maybe Manipulation methods work, but this one works well for me. 

    <Grid x:Name="MainGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" PointerPressed="Grid_PointerPressed" PointerMoved="Grid_PointerMoved" PointerReleased="Grid_PointerReleased">
            <StackPanel VerticalAlignment="Bottom" Margin="10">
                <StackPanel Orientation="Horizontal"  Margin="5"> 
                    <TextBox Text="Direction"/>
                    <TextBox x:Name="Direction"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal"  Margin="5">
                    <TextBox Text="Distance"/>
                    <TextBox x:Name="Distance"/>
                </StackPanel>
            </StackPanel>
        </Grid>
        public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
            }
    
    
            uint Pointer1Id = 0, Pointer2Id = 0;
            Point Pointer1Position, Pointer2Position;
            bool Pointer1Pressed = false, Pointer2Pressed = false;
            double PreviousDistance = 0;
    
            private void Grid_PointerPressed(object sender, PointerRoutedEventArgs e)
            {
                if (Pointer1Id == 0)
                {
                    Pointer1Id = e.Pointer.PointerId;
                    Pointer1Pressed = true;
                }
                else if (Pointer2Id == 0)
                {
                    Pointer2Id = e.Pointer.PointerId;
                    Pointer2Pressed = true;
                }
            }
    
            private void Grid_PointerMoved(object sender, PointerRoutedEventArgs e)
            {
                if (Pointer1Pressed && Pointer2Pressed)
                {
                    if (e.Pointer.PointerId == Pointer1Id) Pointer1Position = e.GetCurrentPoint(MainGrid).Position;
                    else if (e.Pointer.PointerId == Pointer2Id) Pointer2Position = e.GetCurrentPoint(MainGrid).Position;
                    else return;
                    double CurrentDistance = CalculateLength(Pointer1Position, Pointer2Position);
                    Distance.Text = CurrentDistance.ToString();
                    Direction.Text = PreviousDistance >= CurrentDistance ? "Pinch" : "Expand";
                    PreviousDistance = CurrentDistance;
                }
            }
    
            private double CalculateLength (Point A,Point B)
            {
                double DeltaX = A.X - B.X;
                double DeltaY = A.Y - B.Y;
                DeltaX *= DeltaX;
                DeltaY *= DeltaY;
                return System.Math.Sqrt(DeltaX + DeltaY);
            }
    
    
    
    
            private void Grid_PointerReleased(object sender, PointerRoutedEventArgs e)
            {
                if (e.Pointer.PointerId == Pointer1Id)
                {
                    Pointer1Id = 0;
                    Pointer1Pressed = false;
                }
                else if (e.Pointer.PointerId == Pointer2Id)
                {
                    Pointer2Id = 0;
                    Pointer2Pressed = false;
                }
            }
          
        }



    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Wednesday, October 15, 2014 7:24 PM
    Moderator
  • Are you setting your ManipulationMode to All so you get scale and translate information? You can ignore the rotation fields if you don't want to use them.

    As Matt demonstrates, if you need completely custom gesture handling you can do it at the pointer level, but that is less efficient and will be less smooth than using manipulation events or the GestureRecognizer for the standard gestures.

    --Rob

    Wednesday, October 15, 2014 9:20 PM
    Moderator