using System;
using System.IO;
using System.Xml;
using System.Reflection;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows;
namespace GestureControl
{
/// <summary>
/// Take a list of points and try to recognize a pattern
/// </summary>
public class SurfaceGesture : List<SurfaceGestureVector>
{
#region Prop
/// <summary>
/// Allow some variation without log a direction
/// </summary>
public int Precision { get; set; }
/// <summary>
/// List of pattern readed in the patterns.xml
/// </summary>
public List<SurfaceGesturePattern> Pattern = new List<SurfaceGesturePattern>();
#endregion
#region Constructor
/// <summary>
/// load know patterns and generate the vector list from a list of points with a default 20 precision factor
/// </summary>
/// <param name="list"></param>
public SurfaceGesture(List<SurfaceGesturePoint> list)
{
this.Precision = 20;
CommonPattern();
this.Generate(list);
}
/// <summary>
/// load know patterns and generate the vector list from a list of points with a precision factor
/// </summary>
/// <param name="list"></param>
/// <param name="precision"></param>
public SurfaceGesture(List<SurfaceGesturePoint> list, int precision)
{
this.Precision = precision;
CommonPattern();
this.Generate(list);
}
//public SurfaceGesture(System.Windows.Ink.Stroke stroke, int precision)
//{
// StylusPointCollection tmp = stroke.GetBezierStylusPoints();
// List<SurfaceGesturePoint> pointList = new List<SurfaceGesturePoint>();
// foreach (StylusPoint p in tmp)
// pointList.Add(new SurfaceGesturePoint { X = p.X, Y = p.Y });
// this.Precision = precision;
// this.Generate(pointList);
// CommonPattern();
//}
#endregion
#region GenerateVector
/// <summary>
/// Generate list of vector from courbe mouvements, filter with the pas value
/// </summary>
/// <param name="list"></param>
/// <param name="pas"></param>
/// <returns></returns>
private bool GenerateCourb(List<SurfaceGesturePoint> list, int pas)
{
List<SurfaceGesturePattern> tmp = new List<SurfaceGesturePattern>();
int sep = list.Count / pas;
double count = 0; ;
SurfaceGesturePoint past = new SurfaceGesturePoint() { X = 0, Y = 0 };
double y = 0;
for (int i = 0; i < list.Count - 1; i++)
{
if (i % pas != 0)
{
count += Math.Atan(list[i + 1].Y / list[i + 1].X) - Math.Atan(list[i].Y / list[i].X);
}
else
{
count /= pas;
if (count == 0 || this.GetDistancePoints(past, list[i + 1]) < 5)
{
y = list[i + 1].Y;
past.X = count;
continue;
}
if (y > list[i + 1].Y)
{
if (past.X > count)
this.AddDirection(SurfaceGestureVectorDirection.UPRIGHT);
else
this.AddDirection(SurfaceGestureVectorDirection.UPLEFT);
}
else
{
if (past.X > count)
this.AddDirection(SurfaceGestureVectorDirection.DOWNRIGHT);
else
this.AddDirection(SurfaceGestureVectorDirection.DOWNLEFT);
}
y = list[i + 1].Y;
past.X = count;
}
}
Console.Write(this);
if (this.GetPattern() != "None")
return true;
else
return false;
}
/// <summary>
/// Get distance between two points
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
private int GetDistancePoints(SurfaceGesturePoint p1, SurfaceGesturePoint p2)
{
return (int)Math.Sqrt(Math.Pow((p2.X - p1.X), 2) + Math.Pow((p1.Y - p2.Y), 2));
}
/// <summary>
/// add a direction in the vector list if past who not the same
/// </summary>
/// <param name="type"></param>
private void AddDirection(SurfaceGestureVectorDirection type)
{
if (this.Count == 0)
{
this.Add(new SurfaceGestureVector{Direction = type, Lenght=42});
return ;
}
if (this[this.Count - 1].Direction != type)
this.Add(new SurfaceGestureVector { Direction = type, Lenght = 42 });
}
/// <summary>
/// generate list of vector
/// </summary>
/// <param name="list"></param>
private void Generate(List<SurfaceGesturePoint> list)
{
if (list.Count < 2)
return ;
SurfaceGestureVectorDirection lastDirection = SurfaceGestureVectorDirection.NONE;
int lastPoint = 0;
SurfaceGesturePoint LastChange = list[0];
/////// TEST///////////
if (this.GenerateCourb(list, 5) == true)
return;
this.Clear();
///////////////////////
for (int i = 0; i < list.Count - 1; i++)
{
if (GetHorizontal(list[lastPoint], list[i + 1]) == SurfaceGestureVectorDirection.UP && lastDirection != SurfaceGestureVectorDirection.UP)
{
this.Add(new SurfaceGestureVector { Direction = SurfaceGestureVectorDirection.UP, Lenght = (Math.Abs(LastChange.Y - list[i + 1].Y)) });
LastChange = list[i + 1];
lastDirection = SurfaceGestureVectorDirection.UP;
}
else if (GetHorizontal(list[lastPoint], list[i + 1]) == SurfaceGestureVectorDirection.DOWN && lastDirection != SurfaceGestureVectorDirection.DOWN)
{
this.Add(new SurfaceGestureVector { Direction = SurfaceGestureVectorDirection.DOWN, Lenght = (Math.Abs(LastChange.Y - list[i + 1].Y)) });
LastChange = list[i + 1];
lastDirection = SurfaceGestureVectorDirection.DOWN;
}
else if (GetVertical(list[lastPoint], list[i + 1]) == SurfaceGestureVectorDirection.LEFT && lastDirection != SurfaceGestureVectorDirection.LEFT)
{
this.Add(new SurfaceGestureVector { Direction = SurfaceGestureVectorDirection.LEFT, Lenght = (Math.Abs(LastChange.X - list[i + 1].X)) });
LastChange = list[i + 1];
lastDirection = SurfaceGestureVectorDirection.LEFT;
}
else if (GetVertical(list[lastPoint], list[i + 1]) == SurfaceGestureVectorDirection.RIGHT && lastDirection != SurfaceGestureVectorDirection.RIGHT)
{
this.Add(new SurfaceGestureVector { Direction = SurfaceGestureVectorDirection.RIGHT, Lenght = (Math.Abs(LastChange.X - list[i + 1].X)) });
LastChange = list[i + 1];
lastDirection = SurfaceGestureVectorDirection.RIGHT;
}
++lastPoint;
}
}
private SurfaceGestureVectorDirection GetHorizontal(SurfaceGesturePoint p1, SurfaceGesturePoint p2)
{
if (p1.Y < p2.Y)
{
// go up
if (Math.Abs(p2.Y - p1.Y) > this.Precision && Math.Abs(p2.X - p1.X) < Math.Abs(p2.Y - p1.Y))
return SurfaceGestureVectorDirection.DOWN;
}
else
{
// go down
if (Math.Abs(p1.Y - p2.Y) > this.Precision && Math.Abs(p1.X - p2.X) < Math.Abs(p1.Y - p2.Y))
return SurfaceGestureVectorDirection.UP;
}
return SurfaceGestureVectorDirection.NONE;
}
private SurfaceGestureVectorDirection GetVertical(SurfaceGesturePoint p1, SurfaceGesturePoint p2)
{
if (p1.X < p2.X)
{
// go left
if (Math.Abs(p2.X - p1.X) > this.Precision && Math.Abs(p2.Y - p1.Y) < Math.Abs(p2.X - p1.X))
return SurfaceGestureVectorDirection.RIGHT;
}
else
{
// go right
if (Math.Abs(p1.X - p2.X) > this.Precision && Math.Abs(p1.Y - p2.Y) < Math.Abs(p1.X - p2.X))
return SurfaceGestureVectorDirection.LEFT;
}
return SurfaceGestureVectorDirection.NONE;
}
#endregion
#region Override
public override String ToString()
{
String ret = "";
foreach (SurfaceGestureVector v in this)
{
ret += (v.Direction + ", lenght:" + v.Lenght + ", precision:" + this.Precision + "\n");
//Console.WriteLine(v.Direction + ", lenght:" + v.Lenght + ", precision:" + this.Precision);
}
return ret;
}
#endregion
#region Pattern
/// <summary>
/// return a String with the recognized pattern, "None" if no pattern
/// </summary>
/// <returns></returns>
public String GetPattern()
{
foreach (SurfaceGesturePattern p in this.Pattern)
{
if (p.Count == this.Count)
{
int i;
for (i = 0; i < p.Count; i++)
{
if (this[i].Direction != p[i].Direction)
break ;
}
if (i == p.Count)
return p.Name;
}
}
return "None";
}
/// <summary>
/// Load know patterns from the Resources/Patterns.xml file
/// </summary>
private void CommonPattern()
{
try
{
#region Load Patterns
System.IO.Stream file = Assembly.GetExecutingAssembly().GetManifestResourceStream("GestureControl.Resources.Patterns.xml");
XmlDocument xml = new XmlDocument();
xml.Load(file);
XmlElement root = xml.DocumentElement;
XmlNodeList nodes = root.SelectNodes("//Pattern");
SurfaceGesturePattern p;
int i = 0;
foreach (XmlNode node in nodes)
{
string name = node["Name"].InnerText;
XmlNodeList subNodes = node.SelectNodes("//Directions");
if (subNodes == null)
continue;
p = new SurfaceGesturePattern() { Name = name };
foreach (XmlNode subNode in subNodes[i++])
{
XmlNodeList dl = subNode.ChildNodes;
foreach (XmlNode d in dl)
{
switch (d.InnerText)
{
case "Up":
p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.UP });
break;
case "Down":
p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.DOWN });
break;
case "Left":
p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.LEFT });
break;
case "Right":
p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.RIGHT });
break;
case "DownRight":
p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.DOWNRIGHT });
break;
case "DownLeft":
p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.DOWNLEFT });
break;
case "UpRight":
p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.UPRIGHT });
break;
case "UpLeft":
p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.UPLEFT });
break;
default:
break;
}
}
}
this.Pattern.Add(p);
}
#endregion
}
catch
{
throw new Exception("Error loading Patterns.xml");
}
}
#endregion
}
#region Tools
/// <summary>
/// Gesture event who return a object with a Gesture String value
/// </summary>
public class GestureRoutedEventArgs : RoutedEventArgs
{
public String Gesture { get; private set; }
public GestureRoutedEventArgs() : base() { }
public GestureRoutedEventArgs(String gesture) : base() { this.Gesture = gesture; }
public GestureRoutedEventArgs(RoutedEvent routedEvent) : base(routedEvent) { }
public GestureRoutedEventArgs(RoutedEvent routedEvent, String gesture) : base(routedEvent) { this.Gesture = gesture; }
public GestureRoutedEventArgs(RoutedEvent routedEvent, Object source) : base(routedEvent, source) { }
public GestureRoutedEventArgs(RoutedEvent routedEvent, Object source, String gesture) : base(routedEvent, source) { this.Gesture = gesture; }
}
public class SurfaceGesturePattern : List<SurfaceGestureVector>
{
public String Name { get; set; }
}
/// <summary>
/// Possible Gesture Vector
/// </summary>
public enum SurfaceGestureVectorDirection
{
UP,
DOWN,
LEFT,
RIGHT,
UPLEFT,
UPRIGHT,
DOWNLEFT,
DOWNRIGHT,
NONE,
}
/// <summary>
/// Describe a point in the grid
/// </summary>
public class SurfaceGesturePoint
{
public double X { get; set; }
public double Y { get; set; }
}
/// <summary>
/// Describe a vector to help the recognize pass
/// </summary>
public class SurfaceGestureVector
{
public SurfaceGestureVectorDirection Direction { get; set; }
public Double Lenght { get; set; }
}
#endregion
}