middleware/src/Tracking/Gestures/SwipeDetector.cs
author bastiena
Tue, 20 Mar 2012 18:00:55 +0100
changeset 7 8a21bec5d45f
parent 5 d40f84d77db4
child 8 e4e7db2435f8
permissions -rw-r--r--
Middleware : No proximity bugs anymore. The skeleton disappear if a tracked person is too close or not tracked anymore. Processing : There are no laggs anymore when an user stay too long moving his hands and drawing tons of ellipses. (TUIO Cursors are not taken by their vectors, only the last position of the cursors are caught to be drawn).

/*
 * Projet : TraKERS
 * Module : MIDDLEWARE
 * Sous-Module : Tracking/Gestures
 * Classe : SwipeDetector
 * 
 * Auteur : alexandre.bastien@iri.centrepompidou.fr
 * 
 * Fonctionnalités : Permet de détecter si l'utilisateur a effectué un Swipe, en se basant sur
 * des règles appliquées à la positions des noeuds dans le temps.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Kinect;

namespace Trakers.Tracking.Gestures
{
    public class SwipeDetector : GestureDetector
    {
        public enum Direction {LEFT, RIGHT, TOP, DOWN};

        Debug.DebugWindow debug;

        public SwipeDetector(Debug.DebugWindow _d) : base()
        {
            debug = _d;
            gesturePeriod = (float)0.5;
            indexesPerSecond = 30;
            indexesToCheck = (int)(gesturePeriod * indexesPerSecond);
        }

        /*
         * Lit les noeuds de l'historique du squelette afin de détecter un Swipe left.
         * Règles :
         * Se fait avec la main droite.
         * Chaque nouvelle position de la main doit être à la gauche de la précédente.
         * Chaque nouvelle position de la main ne doit pas s'éloigner verticalement de plus d'une certaine distance.
         * Le geste doit mesurer horizontalement une certaine distance.
         */
        public bool CheckForSwipeLeft()
        {
            //Crée un historique de squelette local, puisque l'historique est mis à jour toutes les ~1/30 s.
            List<List<Joint>> localHistory = new List<List<Joint>>(history);

            //Si il n'y a pas assez de positions dans l'historique local pour vérifier le geste.
            if (localHistory.Count < indexesToCheck+1)
                return false;
            
            //La distance de référence est ici la distance entre le milieu du dos et le milieu des épaules.
            refDistance = Math.Abs(localHistory[0][(int)JointType.Spine].Position.Y - localHistory[0][(int)JointType.ShoulderCenter].Position.Y);
            //On commence la position pour les indexesToCheck dernières postures (celle à l'index 0 étant la dernière).
            startPoint = localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position;

            //De la position p1 à pn, on suit l'algorithme.
            for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
            {
                //Si la position Y de la main est plus haute que la tête
                //OU si la position Y de la main est plus basse que la hanche
                //OU si la nouvelle position X de la main est à droite de la précédente
                //OU si la nouvelle position Y de la main est plus éloignée de la distance N par rapport à la première position Y
                //Alors on retourne faux.
                if (localHistory[i][(int)JointType.HandRight].Position.Y < localHistory[i][(int)JointType.Head].Position.Y ||
                localHistory[i][(int)JointType.HandRight].Position.Y > localHistory[i][(int)JointType.HipCenter].Position.Y ||
                localHistory[i][(int)JointType.HandRight].Position.X > localHistory[i - 1][(int)JointType.HandRight].Position.X ||
                Math.Abs(localHistory[i][(int)JointType.HandRight].Position.Y - startPoint.Y) > refDistance / 2)
                    return false;
            }

            //Si la distance horizontale du geste a été plus courte que la distance N
            //Alors on retourne faux.
            if (Math.Abs(localHistory[0][(int)JointType.HandRight].Position.X - localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position.X) < refDistance / 2)
                return false;

            //Si la dernière position de la main droite est sur le côté droit du corps
            //OU si la première position calculée de la main droite est sur le côté gauche du corps
            //Alors on retourne faux.
            if (localHistory[localHistory.Count - 1][(int)JointType.HandRight].Position.X > localHistory[localHistory.Count - 1][(int)JointType.HipCenter].Position.X ||
               localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandRight].Position.X < localHistory[localHistory.Count - 1][(int)JointType.HipCenter].Position.X)
                return false;

            //On supprime l'historique local.
            localHistory.Clear();
            //Si on est arrivé jusqu'ici, toutes les conditions pour un swipe left ont été remplies.
            return true;
        }

        /*
         * Lit les noeuds de l'historique du squelette afin de détecter un Swipe right.
         * Règles :
         * Se fait avec la main gauche.
         * Chaque nouvelle position de la main doit être à la droite de la précédente.
         * Chaque nouvelle position de la main ne doit pas s'éloigner verticalement de plus d'une certaine distance.
         * Le geste doit mesurer horizontalement une certaine distance.
         */
        public bool CheckForSwipeRight()
        {
            //Crée un historique de squelette local, puisque l'historique est mis à jour toutes les ~1/30 s.
            List<List<Joint>> localHistory = new List<List<Joint>>(history);

            //Si il n'y a pas assez de positions dans l'historique local pour vérifier le geste.
            if (localHistory.Count < indexesToCheck + 1)
                return false;

            //La distance de référence est ici la distance entre le milieu du dos et le milieu des épaules.
            refDistance = Math.Abs(localHistory[0][(int)JointType.Spine].Position.Y - localHistory[0][(int)JointType.ShoulderCenter].Position.Y);
            //On commence la position pour les indexesToCheck dernières postures (celle à l'index 0 étant la dernière).
            startPoint = localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandLeft].Position;

            //De la position p1 à pn, on suit l'algorithme.
            for (int i = localHistory.Count - indexesToCheck + 1; i < localHistory.Count; i++)
            {
                //Si la position Y de la main est plus haute que la tête
                //OU si la position Y de la main est plus basse que la hanche
                //OU si la nouvelle position X de la main est à gauche de la précédente
                //OU si la nouvelle position Y de la main est plus éloignée de la distance N par rapport à la première position Y
                //Alors on retourne faux.
                if (localHistory[i][(int)JointType.HandLeft].Position.Y < localHistory[i][(int)JointType.Head].Position.Y ||
                localHistory[i][(int)JointType.HandLeft].Position.Y > localHistory[i][(int)JointType.HipCenter].Position.Y ||
                localHistory[i][(int)JointType.HandLeft].Position.X < localHistory[i - 1][(int)JointType.HandLeft].Position.X ||
                Math.Abs(localHistory[i][(int)JointType.HandLeft].Position.Y - startPoint.Y) > refDistance / 2)
                    return false;
            }

            //Si la distance horizontale du geste a été plus courte que la distance N
            //Alors on retourne faux.
            if (Math.Abs(localHistory[0][(int)JointType.HandLeft].Position.X - localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandLeft].Position.X) < refDistance / 2)
                return false;

            //Si la dernière position de la main droite est sur le côté gauche du corps
            //OU si la première position calculée de la main droite est sur le côté droit du corps
            //Alors on retourne faux.
            if (localHistory[localHistory.Count - 1][(int)JointType.HandLeft].Position.X < localHistory[localHistory.Count - 1][(int)JointType.HipCenter].Position.X ||
               localHistory[localHistory.Count - indexesToCheck][(int)JointType.HandLeft].Position.X > localHistory[localHistory.Count - 1][(int)JointType.HipCenter].Position.X)
                return false;

            //On supprime l'historique local.
            localHistory.Clear();
            //Si on est arrivé jusqu'ici, toutes les conditions pour un swipe right ont été remplies.
            return true;
        }
    }
}