diff -r a446351f08c0 -r 50de8e8f44d7 middleware/src/Tracking/Search/Segmenter.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/middleware/src/Tracking/Search/Segmenter.cs Thu Mar 29 14:39:21 2012 +0200 @@ -0,0 +1,284 @@ +/* +* This file is part of the TraKERS\Middleware package. +* +* (c) IRI +* +* For the full copyright and license information, please view the LICENSE_MIDDLEWARE +* file that was distributed with this source code. +*/ + +/* + * Projet : TraKERS + * Module : MIDDLEWARE + * Sous-Module : Search + * Classe : Segmenter + * + * Auteur : alexandre.bastien@iri.centrepompidou.fr + * + * Fonctionnalités : Permet d'extraire à la volée les segments du tracé en cours. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Media.Media3D; + +namespace Trakers.Tracking.Search +{ + public class Segmenter + { + //Accès à la classe de détection principale pour les paramètres. + private KinectMain kinectMain; + //Stocke les positions d'une main au cours du temps. + private List handPointerHistory; + //Point précédent. + private Point3D prevPt; + //Ratio : on prend 1/ratio points. + private int ratio; + //Indique le numéro du point actuellement enregistré (pour le ratio). + private int currentPointNumber; + //Extremums enregistrés parmi les 3 axes pour détecter les changements de sens. + private double Xmax, Ymax, Zmax; + private double Xmin, Ymin, Zmin; + //On établit une distance en nombre de points entre le point actuel l'extremum + //local détecté dans les 3 axes (pour copier le segment : points de 0 à id de l'extremum). + private int distToXmax, distToYmax, distToZmax; + private int distToXmin, distToYmin, distToZmin; + //Points critiques. + private Point3D minPt, maxPt; + //Tendance actuelle du tracé. + private bool XtowardRight, YtowardUp, ZtowardFront; + //Limites de différences à partir desquelles . + private int directionChangeTresholdXY; + private float directionChangeTresholdZ; + + /* + * Initialisation du segmenter. + * Coupe une courbe en deux dès qu'il repère un changement important de trajectoire. + */ + public Segmenter(int _ratio, KinectMain _kinectMain) + { + kinectMain = _kinectMain; + directionChangeTresholdXY = kinectMain.getDirectionChangeTresholdXY(); + directionChangeTresholdZ = kinectMain.getDirectionChangeTresholdZ(); + handPointerHistory = new List(); + ratio = _ratio; + currentPointNumber = 1; + prevPt = new Point3D(0, 0, 0); + + Xmax = Ymax = Zmax = Xmin = Ymin = Zmin = -1; + distToXmax = distToYmax = distToZmax = distToXmin = distToYmin = distToZmin = -1; + } + + /* + * Getters et setters. + */ + public void SetRatio(int _ratio) + { + ratio = _ratio; + } + public void SetDirectionChangeTresholdXY(int _directionChangeTresholdXY) + { + directionChangeTresholdXY = _directionChangeTresholdXY; + } + public void SetDirectionChangeTresholdZ(float _directionChangeTresholdZ) + { + directionChangeTresholdZ = _directionChangeTresholdZ; + } + + public int GetRatio() + { + return ratio; + } + public int SetDirectionChangeTresholdXY() + { + return directionChangeTresholdXY; + } + public float SetDirectionChangeTresholdZ() + { + return directionChangeTresholdZ; + } + + /* + * On charge tous les paramètres d'un coup. + */ + public void setParams(int _ratio, int _directionChangeTresholdXY, float _directionChangeTresholdZ) + { + ratio = _ratio; + directionChangeTresholdXY = _directionChangeTresholdXY; + directionChangeTresholdZ = _directionChangeTresholdZ; + } + + /* + * Enregistre le point passé en paramètre d'après le ratio. + */ + public void RecordPoint(Point3D pt) + { + //Indique l'ID du point à couper. + int whereToCut; + //Si le ratio est excédé, on peut enregistrer. + if (currentPointNumber > ratio) + currentPointNumber = 1; + + //Si le point précédent est à une position différente du point actuel. + if(prevPt.X != pt.X || prevPt.Y != pt.Y || prevPt.Z != pt.Z) + { + //Si le numéro est 1 (début ou ratio atteint), on enregistre. + if(currentPointNumber == 1) + handPointerHistory.Add(pt); + + //Si le point précédent a été initialisé avec un vrai point. + if (prevPt.X > 0 && prevPt.Y > 0 && prevPt.Z > 0) + { + //Appel aux detecteurs d'extremums. + if ((whereToCut = DetectDirectionChangeAtXAxis(pt)) > 0) + Segment(whereToCut); + else if((whereToCut = DetectDirectionChangeAtYAxis(pt)) > 0) + Segment(whereToCut); + else if ((whereToCut = DetectDirectionChangeAtZAxis(pt)) > 0) + Segment(whereToCut); + } + //On met à jour le point précédent. + prevPt = pt; + //On passe au numéro suivant (jusqu'à atteindre le ration plus tard). + currentPointNumber++; + } + } + + /* + * Détecte un changement de sens (extremum) dans l'axe X. + */ + public int DetectDirectionChangeAtXAxis(Point3D pt) + { + //ID où couper en cas d'extremum. + int whereToCut = -1; + + //Mise à jour des extremums. + if (Xmax == -1 || Xmax < pt.X) + { + //Si le point est plus grand en X que Xmax, alors il est remplacé et on réinitialise la + //distance au dernier maximum en X. + Xmax = pt.X; + maxPt = pt; + distToXmax = 0; + } + else + distToXmax++; + if (Xmin == -1 || Xmin > pt.X) + { + //Si le point est plus petit en X que Xmin, alors il est remplacé et on réinitialise la + //distance au dernier minimum en X. + Xmin = pt.X; + minPt = pt; + distToXmin = 0; + } + else + distToXmin++; + + //Si X max est plus grand que la position actuelle additionnée du seuil + //et que l'extremum n'est pas le premier point sauvegardé. + if (Xmax > pt.X + directionChangeTresholdXY && maxPt != handPointerHistory.First()) + whereToCut = currentPointNumber - distToXmax; + //Si X min est plus petit que la position actuelle à laquelle on a retiré le seuil + //et que l'extremum n'est pas le premier point sauvegardé. + if (Xmin < pt.X - directionChangeTresholdXY && minPt != handPointerHistory.First()) + whereToCut = currentPointNumber - distToXmin; + + return whereToCut; + } + + /* + * Détecte un changement de sens (extremum) dans l'axe Y. + */ + public int DetectDirectionChangeAtYAxis(Point3D pt) + { + //ID où couper en cas d'extremum. + int whereToCut = -1; + + //Mise à jour des extremums. + if (Ymax == -1 || Ymax < pt.Y) + { + //Si le point est plus grand en Y que Ymax, alors il est remplacé et on réinitialise la + //distance au dernier maximum en Y. + Ymax = pt.Y; + maxPt = pt; + distToYmax = 0; + } + else + distToYmax++; + if (Ymin == -1 || Ymin > pt.Y) + { + //Si le point est plus petit en Y que Ymin, alors il est remplacé et on réinitialise la + //distance au dernier minimum en Y. + Ymin = pt.Y; + minPt = pt; + distToYmin = 0; + } + else + distToYmin++; + + //Si Y max est plus grand que la position actuelle additionnée du seuil + //et que l'extremum n'est pas le premier point sauvegardé. + if (Ymax > pt.Y + directionChangeTresholdXY && maxPt != handPointerHistory.First()) + whereToCut = currentPointNumber - distToYmax; + //Si Y min est plus petit que la position actuelle à laquelle on a retiré le seuil + //et que l'extremum n'est pas le premier point sauvegardé. + if (Ymin < pt.Y - directionChangeTresholdXY && minPt != handPointerHistory.First()) + whereToCut = currentPointNumber - distToYmin; + + return whereToCut; + } + + /* + * Détecte un changement de sens (extremum) dans l'axe Z. + */ + public int DetectDirectionChangeAtZAxis(Point3D pt) + { + //ID où couper en cas d'extremum. + int whereToCut = -1; + + //Mise à jour des extremums. + if (Zmax == -1 || Zmax < pt.Z) + { + //Si le point est plus grand en Z que Ymax, alors il est remplacé et on réinitialise la + //distance au dernier maximum en Z. + Zmax = pt.Z; + maxPt = pt; + distToZmax = 0; + } + else + distToZmax++; + if (Zmin == -1 || Zmin > pt.Z) + { + //Si le point est plus petit en Z que Zmin, alors il est remplacé et on réinitialise la + //distance au dernier minimum en Z. + Zmin = pt.Z; + minPt = pt; + distToZmin = 0; + } + else + distToZmin++; + + //Si Z max est plus grand que la position actuelle additionnée du seuil + //et que l'extremum n'est pas le premier point sauvegardé. + if (Zmax > pt.Z + directionChangeTresholdXY && maxPt != handPointerHistory.First()) + whereToCut = currentPointNumber - distToZmax; + //Si Z min est plus petit que la position actuelle à laquelle on a retiré le seuil + //et que l'extremum n'est pas le premier point sauvegardé. + if (Zmin < pt.Z - directionChangeTresholdXY && minPt != handPointerHistory.First()) + whereToCut = currentPointNumber - distToZmin; + + return whereToCut; + } + + /* + * Découpe le tracé en cours en segment allant du premier point au premier extremum trouvé. + */ + public void Segment(int whereToCut) + { + handPointerHistory.RemoveRange(0, whereToCut); + currentPointNumber -= whereToCut; + } + } +}