예제 #1
0
        /// <inheritdoc />
        protected internal override bool UpdateGesture()
        {
            var foundTouches = GestureTouchesUtility.TryFindTouch(fingerId1, out var touch1);

            foundTouches =
                GestureTouchesUtility.TryFindTouch(fingerId2, out var touch2) && foundTouches;

            if (!foundTouches)
            {
                Cancel();
                return(false);
            }

            if (touch1.phase == TouchPhase.Canceled || touch2.phase == TouchPhase.Canceled)
            {
                Cancel();
                return(false);
            }

            if (touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended)
            {
                Complete();
                return(false);
            }

            if (touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved)
            {
                float newgap = (touch1.position - touch2.position).magnitude;
                gapDelta = newgap - gap;
                gap      = newgap;
                return(true);
            }

            return(false);
        }
예제 #2
0
        /// <inheritdoc />
        protected internal override bool CanStart()
        {
            if (GestureTouchesUtility.IsFingerIdRetained(fingerId1) ||
                GestureTouchesUtility.IsFingerIdRetained(fingerId2))
            {
                Cancel();
                return(false);
            }

            var foundTouches = GestureTouchesUtility.TryFindTouch(fingerId1, out var touch1);

            foundTouches =
                GestureTouchesUtility.TryFindTouch(fingerId2, out var touch2) && foundTouches;

            if (!foundTouches)
            {
                Cancel();
                return(false);
            }

            // Check that both fingers are moving.
            if (touch1.deltaPosition == Vector2.zero || touch2.deltaPosition == Vector2.zero)
            {
                return(false);
            }

            var rotation = CalculateDeltaRotation(
                touch1.position, touch2.position, startPosition1, startPosition2);

            return(Mathf.Abs(rotation) >= twistRecognizer.slopRotation);
        }
        /// <inheritdoc />
        protected internal override bool UpdateGesture()
        {
            var foundTouches = GestureTouchesUtility.TryFindTouch(fingerId1, out var touch1);

            foundTouches =
                GestureTouchesUtility.TryFindTouch(fingerId2, out var touch2) && foundTouches;

            if (!foundTouches)
            {
                Cancel();
                return(false);
            }

            if (touch1.isPhaseCanceled || touch2.isPhaseCanceled)
            {
                Cancel();
                return(false);
            }

            if (touch1.isPhaseEnded || touch2.isPhaseEnded)
            {
                Complete();
                return(false);
            }

            if (touch1.isPhaseMoved || touch2.isPhaseMoved)
            {
                delta    = ((touch1.position + touch2.position) / 2) - position;
                position = (touch1.position + touch2.position) / 2;
                return(true);
            }

            return(false);
        }
예제 #4
0
        /// <summary>
        /// Updates this gesture.
        /// </summary>
        /// <returns>True if the update was successful.</returns>
        protected internal override bool UpdateGesture()
        {
            Touch touch;

            if (GestureTouchesUtility.TryFindTouch(FingerId, out touch))
            {
                if (touch.phase == TouchPhase.Moved)
                {
                    Delta    = touch.position - Position;
                    Position = touch.position;
                    return(true);
                }
                else if (touch.phase == TouchPhase.Ended)
                {
                    Complete();
                }
                else if (touch.phase == TouchPhase.Canceled)
                {
                    Cancel();
                }
            }
            else
            {
                Cancel();
            }

            return(false);
        }
        /// <inheritdoc />
        protected internal override void OnStart()
        {
            GestureTouchesUtility.LockFingerId(fingerId1);
            GestureTouchesUtility.LockFingerId(fingerId2);

            if (GestureTouchesUtility.RaycastFromCamera(startPosition1, recognizer.arSessionOrigin, out var hit1))
            {
                var gameObject         = hit1.transform.gameObject;
                var interactableObject = gameObject.GetComponentInParent <ARBaseGestureInteractable>();
                if (interactableObject != null)
                {
                    targetObject = interactableObject.gameObject;
                }
            }
            else if (GestureTouchesUtility.RaycastFromCamera(startPosition2, recognizer.arSessionOrigin, out var hit2))
            {
                var gameObject         = hit2.transform.gameObject;
                var interactableObject = gameObject.GetComponentInParent <ARBaseGestureInteractable>();
                if (interactableObject != null)
                {
                    targetObject = interactableObject.gameObject;
                }
            }

            GestureTouchesUtility.TryFindTouch(fingerId1, out var touch1);
            GestureTouchesUtility.TryFindTouch(fingerId2, out var touch2);
            position = (touch1.position + touch2.position) / 2;
        }
예제 #6
0
        /// <summary>
        /// Updates this gesture.
        /// </summary>
        /// <returns>Returns <see langword="true"/> if the update was successful. Returns <see langword="false"/> otherwise.</returns>
        protected internal override bool UpdateGesture()
        {
            if (GestureTouchesUtility.TryFindTouch(fingerId, out var touch))
            {
                var tapRecognizer = m_Recognizer as TapGestureRecognizer;
                m_ElapsedTime += touch.deltaTime;
                if (m_ElapsedTime > tapRecognizer.m_TimeSeconds)
                {
                    Cancel();
                }
                else if (touch.phase == TouchPhase.Moved)
                {
                    var diff       = (touch.position - startPosition).magnitude;
                    var diffInches = GestureTouchesUtility.PixelsToInches(diff);
                    if (diffInches > tapRecognizer.m_SlopInches)
                    {
                        Cancel();
                    }
                }
                else if (touch.phase == TouchPhase.Ended)
                {
                    Complete();
                }
            }
            else
            {
                Cancel();
            }

            return(false);
        }
        /// <inheritdoc />
        protected internal override bool UpdateGesture()
        {
            if (GestureTouchesUtility.TryFindTouch(fingerId, out var touch))
            {
                if (touch.isPhaseMoved)
                {
                    delta    = touch.position - position;
                    position = touch.position;
                    return(true);
                }

                if (touch.isPhaseEnded)
                {
                    Complete();
                }
                else if (touch.isPhaseCanceled)
                {
                    Cancel();
                }
            }
            else
            {
                Cancel();
            }

            return(false);
        }
        /// <summary>
        /// Updates this gesture.
        /// </summary>
        /// <returns>True if the update was successful.</returns>
        protected internal override bool UpdateGesture()
        {
            Touch touch1, touch2;
            bool  foundTouches = GestureTouchesUtility.TryFindTouch(FingerId1, out touch1);

            foundTouches =
                GestureTouchesUtility.TryFindTouch(FingerId2, out touch2) && foundTouches;

            if (!foundTouches)
            {
                Cancel();
                return(false);
            }

            if (touch1.phase == TouchPhase.Canceled || touch2.phase == TouchPhase.Canceled)
            {
                Cancel();
                return(false);
            }

            if (touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended)
            {
                Complete();
                return(false);
            }

            if (touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved)
            {
                Delta    = ((touch1.position + touch2.position) / 2) - Position;
                Position = (touch1.position + touch2.position) / 2;
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Action to be performed when this gesture is started.
        /// </summary>
        protected internal override void OnStart()
        {
            GestureTouchesUtility.LockFingerId(FingerId1);
            GestureTouchesUtility.LockFingerId(FingerId2);

            RaycastHit hit1;
            RaycastHit hit2;

            if (GestureTouchesUtility.RaycastFromCamera(StartPosition1, out hit1))
            {
                var gameObject = hit1.transform.gameObject;
                if (gameObject != null && gameObject.GetComponentInParent <ARGestureInteractor>() != null)
                {
                    TargetObject = gameObject.GetComponentInParent <ARGestureInteractor>().gameObject;
                }
            }
            else if (GestureTouchesUtility.RaycastFromCamera(StartPosition2, out hit2))
            {
                var gameObject = hit2.transform.gameObject;
                if (gameObject != null && gameObject.GetComponentInParent <ARGestureInteractor>() != null)
                {
                    TargetObject = gameObject.GetComponentInParent <ARGestureInteractor>().gameObject;
                }
            }

            Touch touch1;

            GestureTouchesUtility.TryFindTouch(FingerId1, out touch1);
            Touch touch2;

            GestureTouchesUtility.TryFindTouch(FingerId2, out touch2);
            Position = (touch1.position + touch2.position) / 2;
        }
예제 #10
0
        /// <summary>
        /// Returns true if this gesture can start.
        /// </summary>
        /// <returns>True if the gesture can start.</returns>
        protected internal override bool CanStart()
        {
            if (GestureTouchesUtility.IsFingerIdRetained(FingerId1) ||
                GestureTouchesUtility.IsFingerIdRetained(FingerId2))
            {
                Cancel();
                return(false);
            }

            Touch touch1, touch2;
            bool  foundTouches = GestureTouchesUtility.TryFindTouch(FingerId1, out touch1);

            foundTouches =
                GestureTouchesUtility.TryFindTouch(FingerId2, out touch2) && foundTouches;

            if (!foundTouches)
            {
                Cancel();
                return(false);
            }

            // Check that at least one finger is moving.
            if (touch1.deltaPosition == Vector2.zero && touch2.deltaPosition == Vector2.zero)
            {
                return(false);
            }

            PinchGestureRecognizer pinchRecognizer = m_Recognizer as PinchGestureRecognizer;

            Vector3 firstToSecondDirection = (StartPosition1 - StartPosition2).normalized;
            float   dot1         = Vector3.Dot(touch1.deltaPosition.normalized, -firstToSecondDirection);
            float   dot2         = Vector3.Dot(touch2.deltaPosition.normalized, firstToSecondDirection);
            float   dotThreshold =
                Mathf.Cos(pinchRecognizer.m_SlopMotionDirectionDegrees * Mathf.Deg2Rad);

            // Check angle of motion for the first touch.
            if (touch1.deltaPosition != Vector2.zero && Mathf.Abs(dot1) < dotThreshold)
            {
                return(false);
            }

            // Check angle of motion for the second touch.
            if (touch2.deltaPosition != Vector2.zero && Mathf.Abs(dot2) < dotThreshold)
            {
                return(false);
            }

            float startgap = (StartPosition1 - StartPosition2).magnitude;

            Gap = (touch1.position - touch2.position).magnitude;
            float separation = GestureTouchesUtility.PixelsToInches(Mathf.Abs(Gap - startgap));

            if (separation < pinchRecognizer.m_SlopInches)
            {
                return(false);
            }

            return(true);
        }
예제 #11
0
        /// <inheritdoc />
        protected internal override void OnStart()
        {
            GestureTouchesUtility.LockFingerId(fingerId1);
            GestureTouchesUtility.LockFingerId(fingerId2);

            GestureTouchesUtility.TryFindTouch(fingerId1, out var touch1);
            GestureTouchesUtility.TryFindTouch(fingerId2, out var touch2);
            m_PreviousPosition1 = touch1.position;
            m_PreviousPosition2 = touch2.position;
        }
예제 #12
0
        /// <summary>
        /// Returns true if this gesture can start.
        /// </summary>
        /// <returns>Returns <see langword="true"/> if the gesture can start. Returns <see langword="false"/> otherwise.</returns>
        protected internal override bool CanStart()
        {
            if (GestureTouchesUtility.IsFingerIdRetained(fingerId))
            {
                Cancel();
                return(false);
            }

            return(true);
        }
예제 #13
0
        /// <summary>
        /// Returns true if this gesture can start.
        /// </summary>
        /// <returns>True if the gesture can start.</returns>
        protected internal override bool CanStart()
        {
            if (GestureTouchesUtility.IsFingerIdRetained(FingerId1) ||
                GestureTouchesUtility.IsFingerIdRetained(FingerId2))
            {
                Cancel();
                return(false);
            }

            Touch touch1, touch2;
            bool  foundTouches = GestureTouchesUtility.TryFindTouch(FingerId1, out touch1);

            foundTouches =
                GestureTouchesUtility.TryFindTouch(FingerId2, out touch2) && foundTouches;

            if (!foundTouches)
            {
                Cancel();
                return(false);
            }

            // Check that at least one finger is moving.
            if (touch1.deltaPosition == Vector2.zero && touch2.deltaPosition == Vector2.zero)
            {
                return(false);
            }

            Vector2 pos1       = touch1.position;
            float   diff1      = (pos1 - StartPosition1).magnitude;
            Vector2 pos2       = touch2.position;
            float   diff2      = (pos2 - StartPosition2).magnitude;
            float   slopInches = (m_Recognizer as TwoFingerDragGestureRecognizer).m_SlopInches;

            if (GestureTouchesUtility.PixelsToInches(diff1) < slopInches ||
                GestureTouchesUtility.PixelsToInches(diff2) < slopInches)
            {
                return(false);
            }

            TwoFingerDragGestureRecognizer recognizer =
                m_Recognizer as TwoFingerDragGestureRecognizer;

            // Check both fingers move in the same direction.
            float dot =
                Vector3.Dot(touch1.deltaPosition.normalized, touch2.deltaPosition.normalized);

            if (dot < Mathf.Cos(recognizer.m_AngleThresholdRadians))
            {
                return(false);
            }

            return(true);
        }
 void TryCreateOneFingerGestureOnTouchBegan(Func <CommonTouch, T> createGestureFunction)
 {
     foreach (var touch in GestureTouchesUtility.touches)
     {
         if (touch.isPhaseBegan &&
             !GestureTouchesUtility.IsFingerIdRetained(touch.fingerId) &&
             !GestureTouchesUtility.IsTouchOffScreenEdge(touch))
         {
             var gesture = createGestureFunction(touch);
             AddGesture(gesture);
         }
     }
 }
예제 #15
0
        /// <inheritdoc />
        protected internal override bool CanStart()
        {
            if (GestureTouchesUtility.IsFingerIdRetained(fingerId1) ||
                GestureTouchesUtility.IsFingerIdRetained(fingerId2))
            {
                Cancel();
                return(false);
            }

            var foundTouches = GestureTouchesUtility.TryFindTouch(fingerId1, out var touch1);

            foundTouches =
                GestureTouchesUtility.TryFindTouch(fingerId2, out var touch2) && foundTouches;

            if (!foundTouches)
            {
                Cancel();
                return(false);
            }

            // Check that at least one finger is moving.
            if (touch1.deltaPosition == Vector2.zero && touch2.deltaPosition == Vector2.zero)
            {
                return(false);
            }

            Vector3 firstToSecondDirection = (startPosition1 - startPosition2).normalized;
            var     dot1         = Vector3.Dot(touch1.deltaPosition.normalized, -firstToSecondDirection);
            var     dot2         = Vector3.Dot(touch2.deltaPosition.normalized, firstToSecondDirection);
            var     dotThreshold = Mathf.Cos(pinchRecognizer.slopMotionDirectionDegrees * Mathf.Deg2Rad);

            // Check angle of motion for the first touch.
            if (touch1.deltaPosition != Vector2.zero && Mathf.Abs(dot1) < dotThreshold)
            {
                return(false);
            }

            // Check angle of motion for the second touch.
            if (touch2.deltaPosition != Vector2.zero && Mathf.Abs(dot2) < dotThreshold)
            {
                return(false);
            }

            var startgap = (startPosition1 - startPosition2).magnitude;

            gap = (touch1.position - touch2.position).magnitude;
            var separation = GestureTouchesUtility.PixelsToInches(Mathf.Abs(gap - startgap));

            return(separation >= pinchRecognizer.slopInches);
        }
예제 #16
0
 /// <inheritdoc />
 protected internal override void OnStart()
 {
     if (GestureTouchesUtility.RaycastFromCamera(startPosition, recognizer.arSessionOrigin, out var hit))
     {
         var gameObject = hit.transform.gameObject;
         if (gameObject != null)
         {
             var interactableObject = gameObject.GetComponentInParent <ARBaseGestureInteractable>();
             if (interactableObject != null)
             {
                 targetObject = interactableObject.gameObject;
             }
         }
     }
 }
예제 #17
0
 /// <summary>
 /// Helper function for creating one finger gestures when a touch begins.
 /// </summary>
 /// <param name="createGestureFunction">Function to be executed to create the gesture.</param>
 protected internal void TryCreateOneFingerGestureOnTouchBegan(
     Func <Touch, T> createGestureFunction)
 {
     for (int i = 0; i < GestureTouchesUtility.Touches.Length; i++)
     {
         Touch touch = GestureTouchesUtility.Touches[i];
         if (touch.phase == TouchPhase.Began &&
             !GestureTouchesUtility.IsFingerIdRetained(touch.fingerId) &&
             !GestureTouchesUtility.IsTouchOffScreenEdge(touch))
         {
             T gesture = createGestureFunction(touch);
             gesture.onStart    += OnStart;
             gesture.onFinished += OnFinished;
             m_Gestures.Add(gesture);
         }
     }
 }
예제 #18
0
        /// <summary>
        /// Updates this gesture.
        /// </summary>
        /// <returns>True if the update was successful.</returns>
        protected internal override bool UpdateGesture()
        {
            Touch touch1, touch2;
            bool  foundTouches = GestureTouchesUtility.TryFindTouch(FingerId1, out touch1);

            foundTouches =
                GestureTouchesUtility.TryFindTouch(FingerId2, out touch2) && foundTouches;

            if (!foundTouches)
            {
                Cancel();
                return(false);
            }

            if (touch1.phase == TouchPhase.Canceled || touch2.phase == TouchPhase.Canceled)
            {
                Cancel();
                return(false);
            }

            if (touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended)
            {
                Complete();
                return(false);
            }

            if (touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved)
            {
                float rotation = CalculateDeltaRotation(
                    touch1.position,
                    touch2.position,
                    m_PreviousPosition1,
                    m_PreviousPosition2);

                DeltaRotation       = rotation;
                m_PreviousPosition1 = touch1.position;
                m_PreviousPosition2 = touch2.position;
                return(true);
            }

            m_PreviousPosition1 = touch1.position;
            m_PreviousPosition2 = touch2.position;
            DeltaRotation       = 0.0f;
            return(false);
        }
예제 #19
0
        void TryCreateGestureTwoFingerGestureOnTouchBeganForTouchIndex(
            int touchIndex,
            Func <Touch, Touch, T> createGestureFunction)
        {
            if (GestureTouchesUtility.Touches[touchIndex].phase != TouchPhase.Began)
            {
                return;
            }

            var touch = GestureTouchesUtility.Touches[touchIndex];

            if (GestureTouchesUtility.IsFingerIdRetained(touch.fingerId) ||
                GestureTouchesUtility.IsTouchOffScreenEdge(touch))
            {
                return;
            }

            for (var i = 0; i < GestureTouchesUtility.Touches.Length; i++)
            {
                if (i == touchIndex)
                {
                    continue;
                }

                // Prevents the same two touches from creating two gestures if both touches began on
                // the same frame.
                if (i < touchIndex && GestureTouchesUtility.Touches[i].phase == TouchPhase.Began)
                {
                    continue;
                }

                var otherTouch = GestureTouchesUtility.Touches[i];
                if (GestureTouchesUtility.IsFingerIdRetained(otherTouch.fingerId) ||
                    GestureTouchesUtility.IsTouchOffScreenEdge(otherTouch))
                {
                    continue;
                }

                var gesture = createGestureFunction(touch, otherTouch);
                gesture.onStart    += OnStart;
                gesture.onFinished += OnFinished;
                m_Gestures.Add(gesture);
            }
        }
        /// <inheritdoc />
        protected internal override bool CanStart()
        {
            if (GestureTouchesUtility.IsFingerIdRetained(fingerId1) ||
                GestureTouchesUtility.IsFingerIdRetained(fingerId2))
            {
                Cancel();
                return(false);
            }

            var foundTouches = GestureTouchesUtility.TryFindTouch(fingerId1, out var touch1);

            foundTouches =
                GestureTouchesUtility.TryFindTouch(fingerId2, out var touch2) && foundTouches;

            if (!foundTouches)
            {
                Cancel();
                return(false);
            }

            // Check that at least one finger is moving.
            if (touch1.deltaPosition == Vector2.zero && touch2.deltaPosition == Vector2.zero)
            {
                return(false);
            }

            var pos1       = touch1.position;
            var diff1      = (pos1 - startPosition1).magnitude;
            var pos2       = touch2.position;
            var diff2      = (pos2 - startPosition2).magnitude;
            var slopInches = dragRecognizer.slopInches;

            if (GestureTouchesUtility.PixelsToInches(diff1) < slopInches ||
                GestureTouchesUtility.PixelsToInches(diff2) < slopInches)
            {
                return(false);
            }

            // Check both fingers move in the same direction.
            var dot = Vector3.Dot(touch1.deltaPosition.normalized, touch2.deltaPosition.normalized);

            return(dot >= Mathf.Cos(dragRecognizer.angleThresholdRadians));
        }
예제 #21
0
        /// <inheritdoc />
        protected internal override void OnStart()
        {
            GestureTouchesUtility.LockFingerId(fingerId);

            if (GestureTouchesUtility.RaycastFromCamera(startPosition, out var hit))
            {
                var gameObject = hit.transform.gameObject;
                if (gameObject != null)
                {
                    var interactableObject = gameObject.GetComponentInParent <ARBaseGestureInteractable>();
                    if (interactableObject != null)
                    {
                        TargetObject = interactableObject.gameObject;
                    }
                }
            }

            GestureTouchesUtility.TryFindTouch(fingerId, out var touch);
            position = touch.position;
        }
예제 #22
0
        /// <summary>
        /// Action to be performed when this gesture is started.
        /// </summary>
        protected internal override void OnStart()
        {
            RaycastHit hit;

            if (GestureTouchesUtility.RaycastFromCamera(startPosition, out hit))
            {
                var gameObject = hit.transform.gameObject;
                if (gameObject != null)
                {
                    var interactableObject = gameObject.GetComponentInParent <ARBaseGestureInteractable>();
                    if (interactableObject != null)
                    {
                        TargetObject = interactableObject.gameObject;
                    }
                    else if (gameObject.layer == 9)
                    {
                        TargetObject = gameObject;
                    }
                }
            }
        }
예제 #23
0
        /// <summary>
        /// Returns true if this gesture can start.
        /// </summary>
        /// <returns>True if the gesture can start.</returns>
        protected internal override bool CanStart()
        {
            if (GestureTouchesUtility.IsFingerIdRetained(FingerId))
            {
                Cancel();
                return(false);
            }

            if (GestureTouchesUtility.Touches.Length > 1)
            {
                for (int i = 0; i < GestureTouchesUtility.Touches.Length; i++)
                {
                    Touch currentTouch = GestureTouchesUtility.Touches[i];
                    if (currentTouch.fingerId != FingerId &&
                        !GestureTouchesUtility.IsFingerIdRetained(currentTouch.fingerId))
                    {
                        return(false);
                    }
                }
            }

            Touch touch;

            if (GestureTouchesUtility.TryFindTouch(FingerId, out touch))
            {
                Vector2 pos  = touch.position;
                float   diff = (pos - StartPosition).magnitude;
                if (GestureTouchesUtility.PixelsToInches(diff) >=
                    (m_Recognizer as DragGestureRecognizer).m_SlopInches)
                {
                    return(true);
                }
            }
            else
            {
                Cancel();
            }

            return(false);
        }
        void TryCreateGestureTwoFingerGestureOnTouchBeganForTouchIndex(
            int touchIndex,
            IReadOnlyList <CommonTouch> touches,
            Func <CommonTouch, CommonTouch, T> createGestureFunction)
        {
            var touch = touches[touchIndex];

            if (!touch.isPhaseBegan ||
                GestureTouchesUtility.IsFingerIdRetained(touch.fingerId) ||
                GestureTouchesUtility.IsTouchOffScreenEdge(touch))
            {
                return;
            }

            for (var i = 0; i < touches.Count; i++)
            {
                if (i == touchIndex)
                {
                    continue;
                }

                var otherTouch = touches[i];

                // Prevents the same two touches from creating two gestures if both touches began on
                // the same frame.
                if (i < touchIndex && otherTouch.isPhaseBegan)
                {
                    continue;
                }

                if (GestureTouchesUtility.IsFingerIdRetained(otherTouch.fingerId) ||
                    GestureTouchesUtility.IsTouchOffScreenEdge(otherTouch))
                {
                    continue;
                }

                var gesture = createGestureFunction(touch, otherTouch);
                AddGesture(gesture);
            }
        }
예제 #25
0
        /// <summary>
        /// Returns true if this gesture can start.
        /// </summary>
        /// <returns>True if the gesture can start.</returns>
        protected internal override bool CanStart()
        {
            if (GestureTouchesUtility.IsFingerIdRetained(FingerId1) ||
                GestureTouchesUtility.IsFingerIdRetained(FingerId2))
            {
                Cancel();
                return(false);
            }

            Touch touch1, touch2;
            bool  foundTouches = GestureTouchesUtility.TryFindTouch(FingerId1, out touch1);

            foundTouches =
                GestureTouchesUtility.TryFindTouch(FingerId2, out touch2) && foundTouches;

            if (!foundTouches)
            {
                Cancel();
                return(false);
            }

            // Check that both fingers are moving.
            if (touch1.deltaPosition == Vector2.zero || touch2.deltaPosition == Vector2.zero)
            {
                return(false);
            }

            TwistGestureRecognizer twistRecognizer = m_Recognizer as TwistGestureRecognizer;

            float rotation = CalculateDeltaRotation(
                touch1.position, touch2.position, StartPosition1, StartPosition2);

            if (Mathf.Abs(rotation) < twistRecognizer.m_SlopRotation)
            {
                return(false);
            }

            return(true);
        }
#pragma warning restore IDE1006

        /// <inheritdoc />
        protected internal override bool CanStart()
        {
            if (GestureTouchesUtility.IsFingerIdRetained(fingerId))
            {
                Cancel();
                return(false);
            }

            var touches = GestureTouchesUtility.touches;

            if (touches.Count > 1)
            {
                foreach (var currentTouch in touches)
                {
                    if (currentTouch.fingerId != fingerId &&
                        !GestureTouchesUtility.IsFingerIdRetained(currentTouch.fingerId))
                    {
                        return(false);
                    }
                }
            }

            if (GestureTouchesUtility.TryFindTouch(fingerId, out var touch))
            {
                var pos  = touch.position;
                var diff = (pos - startPosition).magnitude;
                if (GestureTouchesUtility.PixelsToInches(diff) >= dragRecognizer.slopInches)
                {
                    return(true);
                }
            }
            else
            {
                Cancel();
            }

            return(false);
        }
예제 #27
0
 /// <summary>
 /// Action to be performed when this gesture is finished.
 /// </summary>
 protected internal override void OnFinish()
 {
     GestureTouchesUtility.ReleaseFingerId(FingerId1);
     GestureTouchesUtility.ReleaseFingerId(FingerId2);
 }
예제 #28
0
 /// <summary>
 /// Action to be performed when this gesture is started.
 /// </summary>
 protected internal override void OnStart()
 {
     GestureTouchesUtility.LockFingerId(FingerId1);
     GestureTouchesUtility.LockFingerId(FingerId2);
 }
예제 #29
0
 /// <inheritdoc />
 protected internal override void OnFinish() => GestureTouchesUtility.ReleaseFingerId(fingerId);
        /// <summary>
        /// Calculates the best position to place an object in AR based on screen position.
        /// Could be used for tapping a location on the screen, dragging an object, or using a fixed
        /// cursor in the center of the screen for placing and moving objects.
        ///
        /// Objects are placed along the x/z of the grounding plane. When placed on an AR plane
        /// below the grounding plane, the object will drop straight down onto it in world space.
        /// This prevents the object from being pushed deeper into the scene when moving from a
        /// higher plane to a lower plane. When moving from a lower plane to a higher plane, this
        /// function returns a new groundingPlane to replace the old one.
        /// </summary>
        /// <returns>The best placement position.</returns>
        /// <param name="currentAnchorPosition">Position of the parent anchor, i.e., where the
        /// object is before translation starts.</param>
        /// <param name="screenPos">Location on the screen in pixels to place the object at.</param>
        /// <param name="groundingPlaneHeight">The starting height of the plane that the object is
        /// being placed along.</param>
        /// <param name="hoverOffset">How much should the object hover above the groundingPlane
        /// before it has been placed.</param>
        /// <param name="maxTranslationDistance">The maximum distance that the object can be
        /// translated.</param>
        /// <param name="gestureTranslationMode">The translation mode, indicating the plane types allowed.
        /// </param>
        public static Placement GetBestPlacementPosition(
            Vector3 currentAnchorPosition,
            Vector2 screenPos,
            float groundingPlaneHeight,
            float hoverOffset,
            float maxTranslationDistance,
            GestureTranslationMode gestureTranslationMode)
        {
            Placement result = new Placement();

            if (!CheckDependentManagers())
            {
                return(result);
            }

            result.UpdatedGroundingPlaneHeight = groundingPlaneHeight;

            // Get the angle between the camera and the object's down direction.
            float angle = Vector3.Angle(Camera.main.transform.forward, Vector3.down);

            angle = 90.0f - angle;

            float touchOffsetRatio  = Mathf.Clamp01(angle / 90.0f);
            float screenTouchOffset = touchOffsetRatio * k_MaxScreenTouchOffset;

            screenPos.y += GestureTouchesUtility.InchesToPixels(screenTouchOffset);

            float hoverRatio = Mathf.Clamp01(angle / 45.0f);

            hoverOffset *= hoverRatio;

            float distance           = (Camera.main.transform.position - currentAnchorPosition).magnitude;
            float distanceHoverRatio = Mathf.Clamp01(distance / k_HoverDistanceThreshold);

            hoverOffset *= distanceHoverRatio;

            // The best estimate of the point in the plane where the object will be placed:
            Vector3 groundingPoint;

            // Get the ray to cast into the scene from the perspective of the camera.
            if (Raycast(new Vector2(screenPos.x, screenPos.y), s_Hits, TrackableType.Planes))
            {
                var firstHit = s_Hits[0];
                var plane    = s_ARPlaneManager.GetPlane(firstHit.trackableId);
                if (plane == null || IsPlaneTypeAllowed(gestureTranslationMode, plane.alignment))
                {
                    // Avoid detecting the back of existing planes.
                    if (Vector3.Dot(Camera.main.transform.position - firstHit.pose.position,
                                    firstHit.pose.rotation * Vector3.up) < 0)
                    {
                        return(result);
                    }

                    // Don't allow hovering for vertical or horizontal downward facing planes.
                    if (plane == null ||
                        (plane.alignment == PlaneAlignment.Vertical ||
                         plane.alignment == PlaneAlignment.HorizontalDown ||
                         plane.alignment == PlaneAlignment.HorizontalUp))
                    {
                        groundingPoint = LimitTranslation(
                            firstHit.pose.position, currentAnchorPosition, maxTranslationDistance);

                        if (plane != null)
                        {
                            result.PlacementPlane = plane;
                            result.HasPlane       = true;
                        }

                        result.HasPlacementPosition        = true;
                        result.PlacementPosition           = groundingPoint;
                        result.HasHoveringPosition         = true;
                        result.HoveringPosition            = groundingPoint;
                        result.UpdatedGroundingPlaneHeight = groundingPoint.y;
                        result.PlacementRotation           = firstHit.pose.rotation;
                        return(result);
                    }
                }
                else
                {
                    // Plane type not allowed.
                    return(result);
                }
            }

            // Return early if the camera is pointing upwards.
            if (angle < 0f)
            {
                return(result);
            }

            // If the grounding point is lower than the current grounding plane height, or if the
            // raycast did not return a hit, then we extend the grounding plane to infinity, and do
            // a new raycast into the scene from the perspective of the camera.
            Ray   cameraRay      = Camera.main.ScreenPointToRay(screenPos);
            Plane groundingPlane =
                new Plane(Vector3.up, new Vector3(0.0f, groundingPlaneHeight, 0.0f));

            // Find the hovering position by casting from the camera onto the grounding plane
            // and offsetting the result by the hover offset.
            float enter;

            if (groundingPlane.Raycast(cameraRay, out enter))
            {
                groundingPoint = LimitTranslation(
                    cameraRay.GetPoint(enter), currentAnchorPosition, maxTranslationDistance);

                result.HasHoveringPosition = true;
                result.HoveringPosition    = groundingPoint + (Vector3.up * hoverOffset);
            }
            else
            {
                // If we can't successfully cast onto the groundingPlane, just return early.
                return(result);
            }

            return(result);
        }