middleware/src/Communication/Server.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 : Communication
 * Classe : Server
 * 
 * Auteur : alexandre.bastien@iri.centrepompidou.fr
 * 
 * Fonctionnalités : Reçoit des notifications du module sous-module Tracking.
 * Traduit les notifications sous forme de messages OSC et les envoie au Front Atelier.
 * Forme des messages :
 * - Notification de main dans le champ de recherche : Point3D indiquant la position de la main dans l'espace.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Tuio;
using System.Windows;
using Microsoft.Kinect;
using Trakers.Tracking;
using System.Windows.Media.Media3D;
using Trakers.Tracking.Events;
using System.Timers;
using Trakers.Debug;
using System.Resources;
using System.Reflection;

namespace Trakers.Communication
{
    public class Server
    {
        //Serveur TUIO, provenant de la DLL TuioServer créé par Bespoke.
        private TuioServer server;
        //Affichage de debug.
        private DebugWindow debug;

        //Permet de savoir si un curseur pour la main gauche/droite a été créé.
        private bool leftHandCursorCreated;
        private bool rightHandCursorCreated;
        private bool messageCreated;
        private bool gestureLocked;
        //Intervalle minimum entre les gestures.
        private int timerElapsing;
        //Timer.
        private System.Timers.Timer _timer;
        //Gestionnaire de ressources.
        private ResourceManager rm;

        /*
        * Constructeur : On initialise le serveur avec une adresse et un port, au début les curseurs
        * ne sont pas créés et on indique au ThreadPool une fonction de callback de manière à vérifier
        * s'il reçoit des notifications.
        */
        public Server(String host, int port, int _timerElapsing, DebugWindow _debug)
        {
            debug = _debug;
            rm = new ResourceManager("Trakers.Properties.resources", Assembly.GetExecutingAssembly());
            //Au départ, aucune main n'est dans le champ de recherche et aucune gesture n'est détectée.
            leftHandCursorCreated = false;
            rightHandCursorCreated = false;
            messageCreated = false;
            gestureLocked = false;

            timerElapsing = _timerElapsing;

            try
            {
                //On démarre le serveur TUIO.
                server = new TuioServer(host, port);
                //On initialise le threadPool (appelé toutes les N ms).
                ThreadPool.QueueUserWorkItem(ThreadPoolCallback);

                //On instancie le timer à N ms.
                _timer = new System.Timers.Timer(timerElapsing);
                //Dès que le timer est expiré, on appelle _timer_Elapsed.
                _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
            }
            catch (Exception)
            {
                debug.ExceptionLbl.Content = rm.GetString("serverCantStart");
            }
        }

        /*
        * Getter du serveur.
        */
        public TuioServer getServer()
        {
            return server;
        }

        /*
         * Méthode appelée à l'expiration du timer.
         */
        public void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            //On débloque la détection de gesture.
            gestureLocked = false;
            //On arrête le timer.
            _timer.Stop();
        }

        /*
        * Méthode appelée lors d'une notification de type : main gauche entrée dans le champ.
        */
        public void LeftHandTracked(object sender, LeftHandTrackedEventArgs e)
        {
            //Si le curseur de la main gauche n'est pas créé, alors on le crée.
            if (!leftHandCursorCreated)
            {
                server.AddTuioCursor(0, SkeletonPointToPoint3D(e.handJoint.Position));
                leftHandCursorCreated = true;
            }
            //S'il existe, on le met simplement à jour.
            else
            {
                server.UpdateTuioCursor(0, SkeletonPointToPoint3D(e.handJoint.Position));
            }
        }

        /*
        * Méthode appelée lors d'une notification de type : main droite entrée dans le champ.
        */
        public void RightHandTracked(object sender, RightHandTrackedEventArgs e)
        {
            //Si le curseur de la main droite n'est pas créé, alors on le crée.
            if (!rightHandCursorCreated)
            {
                server.AddTuioCursor(1, SkeletonPointToPoint3D(e.handJoint.Position));
                rightHandCursorCreated = true;
            }
            //S'il existe, on le met simplement à jour.
            else
            {
                server.UpdateTuioCursor(1, SkeletonPointToPoint3D(e.handJoint.Position));
            }
        }

        /*
        * Méthode appelée lors d'une notification de type : main gauche sortie du champ.
        */
        public void LeftHandQuit(object sender, LeftHandQuitEventArgs e)
        {
            //Si le curseur de la main gauche existe, alors on le supprime.
            if (leftHandCursorCreated)
            {
                server.DeleteTuioCursor(0);
                leftHandCursorCreated = false;
            }
        }

        /*
        * Méthode appelée lors d'une notification de type : main droite sortie du champ.
        */
        public void RightHandQuit(object sender, RightHandQuitEventArgs e)
        {
            //Si le curseur de la main droite existe, alors on le supprime.
            if (rightHandCursorCreated)
            {
                server.DeleteTuioCursor(1);
                rightHandCursorCreated = false;
            }
        }

        /*
        * Méthode appelée lors d'une notification de type : l'utilisateur fait un swipe.
        */
        public void Swipe(object sender, SwipeEventArgs e)
        {
            if (e.direction == Tracking.Gestures.SwipeDetector.Direction.LEFT)
                GesturePerformed("SWIPE LEFT");
            else if (e.direction == Tracking.Gestures.SwipeDetector.Direction.RIGHT)
                GesturePerformed("SWIPE RIGHT");
        }

        /*
        * Méthode appelée lors d'une notification de type : l'utilisateur fait un push/pull.
        */
        public void Pull(object sender, PushEventArgs e)
        {
            if(e.hand == Tracking.Gestures.PushDetector.Hand.NONE)
                return;

            String pushPull = "", hand = "";
            if (e.direction == Tracking.Gestures.PushDetector.Direction.PUSH)
                pushPull = "PUSH";
            else
                pushPull = "PULL";

            if (e.hand == Tracking.Gestures.PushDetector.Hand.LEFT)
                hand = "LEFT";
            else if (e.hand == Tracking.Gestures.PushDetector.Hand.RIGHT)
                hand = "RIGHT";
            else
                hand = "BOTH";

            GesturePerformed(pushPull + "-" + hand);
        }

        /*
        * Méthode appelée lorsqu'une gesture a été détectée et que l'événement approprié a été lancé.
        */
        public void GesturePerformed(String code)
        {
            //Si une gesture a été effectuée, on bloque un certain temps.
            if (!gestureLocked)
            {
                gestureLocked = true;
                
                //On crée un message contenant le code à envoyer.
                if (!messageCreated)
                {
                    messageCreated = true;
                    server.AddTuioString(2, code);
                    //On démarre le timer.
                    _timer.Start();
                }
            }
        }

        /*
        * Permet de convertir un point de position de noeud en Point3D.
        */
        private Point3D SkeletonPointToPoint3D(SkeletonPoint p)
        {
            return new Point3D((double)p.X, (double)p.Y, (double)p.Z);
        }

        /*
        * Méthode de callback vérifiant toutes les 25 ms les nouvelles notifications.
        * Il est à noter que si le temps de rafraîchissement des trop rapide, les messages n'ont pas
        * le temps d'être envoyés.
        */
        private void ThreadPoolCallback(Object threadContext)
        {
            while (true)
            {
                //On initialise le message OSC.
                server.InitFrame();
                //On l'envoie au client (au host et au port spécifiés dans le constructeur).
                server.CommitFrame();
                //On attend 25 ms.
                Thread.Sleep(25);

                //Si une gesture a été effectuée et que le délai d'attente est expiré.
                if (messageCreated && !gestureLocked)
                {
                    //On débloque la détection de gesture et on supprime l'objet envoyant les messages OSC de gesture.
                    messageCreated = false;
                    server.DeleteTuioString(2);
                }
            }
        }
    }
}