/* * @author Valentin Simonov / http://va.lent.in/ */ using System.Collections.Generic; using TouchScript.Layers; using TouchScript.Pointers; using TouchScript.Utils.Geom; using UnityEngine; #if TOUCHSCRIPT_DEBUG using System.Collections; using TouchScript.Debugging.GL; #endif namespace TouchScript.Gestures.TransformGestures.Base { /// /// Abstract base class for Pinned Transform Gestures. /// public abstract class OnePointTrasformGestureBase : TransformGestureBase { #region Constants #endregion #region Events #endregion #region Public properties /// public override Vector2 ScreenPosition { get { if (NumPointers == 0) return TouchManager.INVALID_POSITION; return activePointers[0].Position; } } /// public override Vector2 PreviousScreenPosition { get { if (NumPointers == 0) return TouchManager.INVALID_POSITION; return activePointers[0].PreviousPosition; } } #endregion #region Private variables /// /// Translation buffer. /// protected Vector2 screenPixelTranslationBuffer; /// /// Rotation buffer. /// protected float screenPixelRotationBuffer; /// /// Angle buffer. /// protected float angleBuffer; /// /// Screen space scaling buffer. /// protected float screenPixelScalingBuffer; /// /// Scaling buffer. /// protected float scaleBuffer; #endregion #region Unity methods #if TOUCHSCRIPT_DEBUG /// protected override void Awake() { base.Awake(); debugID = DebugHelper.GetDebugId(this); debugPointerSize = Vector2.one * TouchManager.Instance.DotsPerCentimeter * 1.1f; } #endif #endregion #region Gesture callbacks /// protected override void pointersUpdated(IList pointers) { base.pointersUpdated(pointers); var projectionParams = activePointers[0].ProjectionParams; var dR = deltaRotation = 0; var dS = deltaScale = 1f; #if TOUCHSCRIPT_DEBUG var worldCenter = cachedTransform.position; var screenCenter = projectionParams.ProjectFrom(worldCenter); var newScreenPos = getPointScreenPosition(); drawDebug(screenCenter, newScreenPos); #endif if (pointersNumState != PointersNumState.InRange) return; var rotationEnabled = (Type & TransformGesture.TransformType.Rotation) == TransformGesture.TransformType.Rotation; var scalingEnabled = (Type & TransformGesture.TransformType.Scaling) == TransformGesture.TransformType.Scaling; if (!rotationEnabled && !scalingEnabled) return; if (!relevantPointers(pointers)) return; #if !TOUCHSCRIPT_DEBUG var thePointer = activePointers[0]; var worldCenter = cachedTransform.position; var screenCenter = projectionParams.ProjectFrom(worldCenter); var newScreenPos = thePointer.Position; #endif // Here we can't reuse last frame screen positions because points 0 and 1 can change. // For example if the first of 3 fingers is lifted off. var oldScreenPos = getPointPreviousScreenPosition(); if (rotationEnabled) { if (isTransforming) { dR = doRotation(worldCenter, oldScreenPos, newScreenPos, projectionParams); } else { // Find how much we moved perpendicular to the line (center, oldScreenPos) screenPixelRotationBuffer += TwoD.PointToLineDistance(screenCenter, oldScreenPos, newScreenPos); angleBuffer += doRotation(worldCenter, oldScreenPos, newScreenPos, projectionParams); if (screenPixelRotationBuffer * screenPixelRotationBuffer >= screenTransformPixelThresholdSquared) { isTransforming = true; dR = angleBuffer; } } } if (scalingEnabled) { if (isTransforming) { dS *= doScaling(worldCenter, oldScreenPos, newScreenPos, projectionParams); } else { screenPixelScalingBuffer += (newScreenPos - screenCenter).magnitude - (oldScreenPos - screenCenter).magnitude; scaleBuffer *= doScaling(worldCenter, oldScreenPos, newScreenPos, projectionParams); if (screenPixelScalingBuffer * screenPixelScalingBuffer >= screenTransformPixelThresholdSquared) { isTransforming = true; dS = scaleBuffer; } } } if (dR != 0) transformMask |= TransformGesture.TransformType.Rotation; if (dS != 1) transformMask |= TransformGesture.TransformType.Scaling; if (transformMask != 0) { if (State == GestureState.Possible) setState(GestureState.Began); switch (State) { case GestureState.Began: case GestureState.Changed: deltaRotation = dR; deltaScale = dS; setState(GestureState.Changed); resetValues(); break; } } } /// protected override void reset() { base.reset(); screenPixelTranslationBuffer = Vector2.zero; screenPixelRotationBuffer = 0f; angleBuffer = 0; screenPixelScalingBuffer = 0f; scaleBuffer = 1f; #if TOUCHSCRIPT_DEBUG clearDebug(); #endif } #endregion #region Protected methods /// /// Calculates rotation. /// /// Center screen position. /// Pointer old screen position. /// Pointer new screen position. /// Layer projection parameters. /// Angle in degrees. protected virtual float doRotation(Vector3 center, Vector2 oldScreenPos, Vector2 newScreenPos, ProjectionParams projectionParams) { return 0; } /// /// Calculates scaling. /// /// Center screen position. /// Pointer old screen position. /// Pointer new screen position. /// Layer projection parameters. /// Multiplicative delta scaling. protected virtual float doScaling(Vector3 center, Vector2 oldScreenPos, Vector2 newScreenPos, ProjectionParams projectionParams) { return 1; } /// /// Checks if there are pointers in the list which matter for the gesture. /// /// List of pointers /// true if there are relevant pointers; false otherwise. protected virtual bool relevantPointers(IList pointers) { // We care only about the first pointer var count = pointers.Count; for (var i = 0; i < count; i++) { if (pointers[i] == activePointers[0]) return true; } return false; } /// /// Returns screen position of a point with index 0. /// protected virtual Vector2 getPointScreenPosition() { return activePointers[0].Position; } /// /// Returns previous screen position of a point with index 0. /// protected virtual Vector2 getPointPreviousScreenPosition() { return activePointers[0].PreviousPosition; } /// protected override void updateType() { type = type & ~TransformGesture.TransformType.Translation; } #if TOUCHSCRIPT_DEBUG protected virtual void clearDebug() { GLDebug.RemoveFigure(debugID); GLDebug.RemoveFigure(debugID + 1); GLDebug.RemoveFigure(debugID + 2); if (debugCoroutine != null) StopCoroutine(debugCoroutine); debugCoroutine = null; } protected void drawDebugDelayed(Vector2 point1, Vector2 point2) { if (debugCoroutine != null) StopCoroutine(debugCoroutine); debugCoroutine = StartCoroutine(doDrawDebug(point1, point2)); } protected virtual void drawDebug(Vector2 point1, Vector2 point2) { if (!DebugMode) return; var color = State == GestureState.Possible ? Color.red : Color.green; GLDebug.DrawSquareScreenSpace(debugID + 1, point2, 0f, debugPointerSize, color, float.PositiveInfinity); GLDebug.DrawLineScreenSpace(debugID + 2, point1, point2, color, float.PositiveInfinity); } private IEnumerator doDrawDebug(Vector2 point1, Vector2 point2) { yield return new WaitForEndOfFrame(); drawDebug(point1, point2); } #endif #endregion #region Private functions #endregion } }