Circle gesture detection

Hello to everyone,

I found a code from an asset which it is capable of detecting a circle gesture on a mobile screen.
I would like someone who knows how it works mathematically to explain it also to me. More specific I don’t really understand what I get from the calculation : (screen.width + screen.height) / 4. By the way the code is working correct. Thank you very much.

List<Vector2> gestureDetector = new List<Vector2>();
Vector2 gestureSum = Vector2.zero;
float gestureLength = 0;
int gestureCount = 0;

bool isGestureDone()
    {
        if (Input.touches.Length > 2)
        {
            gestureDetector.Clear();
            gestureCount = 0;
        }
        else
        {
            if (Input.touches[touches - 1].phase == TouchPhase.Canceled || Input.touches[touches - 1].phase == TouchPhase.Ended)
                gestureDetector.Clear();
            else if (Input.touches[touches - 1].phase == TouchPhase.Moved)
            {
                Vector2 p = Input.touches[touches - 1].position;
                if (gestureDetector.Count == 0 || (p - gestureDetector[gestureDetector.Count - 1]).magnitude > 10)
                    gestureDetector.Add(p);
            }
        }

        if (gestureDetector.Count < 10)
            return false;

        gestureSum = Vector2.zero;
        gestureLength = 0;
        Vector2 prevDelta = Vector2.zero;
        for (int i = 0; i < gestureDetector.Count - 2; i++)
        {

            Vector2 delta = gestureDetector[i + 1] - gestureDetector[i];
            float deltaLength = delta.magnitude;
            gestureSum += delta;
            gestureLength += deltaLength;

            float dot = Vector2.Dot(delta, prevDelta);
            if (dot < 0f)
            {
                gestureDetector.Clear();
                gestureCount = 0;
                return false;
            }

            prevDelta = delta;
        }

        int gestureBase = (Screen.width + Screen.height) / 4;

        if (gestureLength > gestureBase && gestureSum.magnitude < gestureBase / 2)
        {
            gestureDetector.Clear();
            gestureCount++;
            if (gestureCount >= numOfCircleToShow)
                return true;
        }

        return false;
    }

Let’s break down the maths aspects of your gesture detection code.

  • Initialization:

  • You start by initializing some variables:

  • gestureDetector: A list of Vector2 points that records the touch positions.

  • gestureSum: A Vector2 that accumulates the total movement.

  • gestureLength: A float that accumulates the total length of the gesture.

  • gestureCount: An integer to keep track of the number of touch points.

  • Touch Input Handling:

  • The code checks the number of active touches (Input.touches.Length). If there are more than two touches, it clears the gesture data and resets the count.

  • Otherwise, it processes the touch input:

  • If the touch phase is canceled or ended, it clears the gesture data.

  • If the touch phase is moved, it adds the current touch position to the gestureDetector list if the movement exceeds a threshold (10 units).

  • Gesture Length and Direction:

  • Once enough touch points are recorded (at least 10), the code calculates the gesture length and direction:

  • delta represents the difference between consecutive touch positions.

  • deltaLength is the magnitude (length) of the delta.

  • gestureSum accumulates the total movement by adding up the delta vectors.

  • gestureLength accumulates the total length of the gesture.

  • dot computes the dot product between the current delta and the previous delta. If the dot product is negative, it indicates a change in direction (e.g., from clockwise to counterclockwise).

  • If the direction changes, the gesture data is cleared.

  • What About (screen.width + screen.height) / 4?:

  • The expression gestureBase = (Screen.width + Screen.height) / 4 calculates a reference value for the gesture length.

  • It takes the sum of the screen width and height and divides it by 4.

  • This value serves as a baseline for determining whether the detected gesture is significant.

  • Gesture Recognition*:

  • The code checks if the gesture length exceeds the gestureBase and if the magnitude of gestureSum is less than half of gestureBase.

  • If both conditions are met, it clears the gesture data, increments the gestureCount, and checks if the required number of circles (numOfCircleToShow) has been detected.

  • If so, it returns true, indicating that a circular gesture has been recognized.

the code accumulates touch positions, calculates gesture length, and detects changes in direction. It’s a basic approach to identifying circular gestures. This simple method can work well for certain scenarios. More advanced algorithms may involve curve fitting or pattern recognition

1 Like

Here’s am implementation of curve fitting. Using the least squares regression method to fit a circle to a set of touch points. Here’s a simplified example

using System.Collections.Generic;
using UnityEngine;

public class CircularGestureDetector : MonoBehaviour
{
    public int minPointsForGesture = 10; // Minimum number of touch points for a gesture
    public float minRadius = 50f; // Minimum radius for a circular gesture

    private List<Vector2> touchPositions = new List<Vector2>();

    void Update()
    {
        // Capture touch input
        if (Input.touchCount > 0)
        {
            Vector2 touchPosition = Input.GetTouch(0).position;
            touchPositions.Add(touchPosition);
        }

        // Check if we have enough touch points
        if (touchPositions.Count >= minPointsForGesture)
        {
            // Fit a circle to the touch points
            CircleFitResult circleFit = FitCircle(touchPositions);

            // Check if the circle meets criteria for a circular gesture
            if (circleFit.radius > minRadius)
            {
                Debug.Log("Circular gesture detected!");
            }
        }
    }

    CircleFitResult FitCircle(List<Vector2> points)
    {
        // Calculate centroid (average position)
        Vector2 centroid = Vector2.zero;
        foreach (Vector2 point in points)
        {
            centroid += point;
        }
        centroid /= points.Count;

        // Estimate circle parameters (center and radius)
        float radiusSum = 0f;
        foreach (Vector2 point in points)
        {
            radiusSum += Vector2.Distance(point, centroid);
        }
        float estimatedRadius = radiusSum / points.Count;

        return new CircleFitResult(centroid, estimatedRadius);
    }
}

// Custom struct to hold circle fit results
public struct CircleFitResult
{
    public Vector2 center;
    public float radius;

    public CircleFitResult(Vector2 center, float radius)
    {
        this.center = center;
        this.radius = radius;
    }
}
  • The CircularGestureDetector script captures touch input and accumulates touch positions.
  • When enough touch points are collected, it calls the FitCircle method to estimate the circle parameters (center and radius).
  • The FitCircle method calculates the centroid and estimates the radius based on the average distance from the centroid.
  • Finally, it checks if the estimated radius exceeds the minimum required radius for a circular gesture.
1 Like