|
1 using System; |
|
2 using System.IO; |
|
3 using System.Xml; |
|
4 using System.Reflection; |
|
5 using System.Xml.Linq; |
|
6 using System.Collections.Generic; |
|
7 using System.Linq; |
|
8 using System.Text; |
|
9 using System.Windows.Input; |
|
10 using System.Windows; |
|
11 |
|
12 namespace GestureControl |
|
13 { |
|
14 /// <summary> |
|
15 /// Take a list of points and try to recognize a pattern |
|
16 /// </summary> |
|
17 public class SurfaceGesture : List<SurfaceGestureVector> |
|
18 { |
|
19 |
|
20 #region Prop |
|
21 /// <summary> |
|
22 /// Allow some variation without log a direction |
|
23 /// </summary> |
|
24 public int Precision { get; set; } |
|
25 /// <summary> |
|
26 /// List of pattern readed in the patterns.xml |
|
27 /// </summary> |
|
28 public List<SurfaceGesturePattern> Pattern = new List<SurfaceGesturePattern>(); |
|
29 #endregion |
|
30 #region Constructor |
|
31 /// <summary> |
|
32 /// load know patterns and generate the vector list from a list of points with a default 20 precision factor |
|
33 /// </summary> |
|
34 /// <param name="list"></param> |
|
35 public SurfaceGesture(List<SurfaceGesturePoint> list) |
|
36 { |
|
37 this.Precision = 20; |
|
38 CommonPattern(); |
|
39 this.Generate(list); |
|
40 } |
|
41 /// <summary> |
|
42 /// load know patterns and generate the vector list from a list of points with a precision factor |
|
43 /// </summary> |
|
44 /// <param name="list"></param> |
|
45 /// <param name="precision"></param> |
|
46 public SurfaceGesture(List<SurfaceGesturePoint> list, int precision) |
|
47 { |
|
48 this.Precision = precision; |
|
49 CommonPattern(); |
|
50 this.Generate(list); |
|
51 } |
|
52 //public SurfaceGesture(System.Windows.Ink.Stroke stroke, int precision) |
|
53 //{ |
|
54 // StylusPointCollection tmp = stroke.GetBezierStylusPoints(); |
|
55 // List<SurfaceGesturePoint> pointList = new List<SurfaceGesturePoint>(); |
|
56 // foreach (StylusPoint p in tmp) |
|
57 // pointList.Add(new SurfaceGesturePoint { X = p.X, Y = p.Y }); |
|
58 // this.Precision = precision; |
|
59 // this.Generate(pointList); |
|
60 // CommonPattern(); |
|
61 //} |
|
62 #endregion |
|
63 #region GenerateVector |
|
64 /// <summary> |
|
65 /// Generate list of vector from courbe mouvements, filter with the pas value |
|
66 /// </summary> |
|
67 /// <param name="list"></param> |
|
68 /// <param name="pas"></param> |
|
69 /// <returns></returns> |
|
70 private bool GenerateCourb(List<SurfaceGesturePoint> list, int pas) |
|
71 { |
|
72 List<SurfaceGesturePattern> tmp = new List<SurfaceGesturePattern>(); |
|
73 int sep = list.Count / pas; |
|
74 double count = 0; ; |
|
75 SurfaceGesturePoint past = new SurfaceGesturePoint() { X = 0, Y = 0 }; |
|
76 double y = 0; |
|
77 |
|
78 for (int i = 0; i < list.Count - 1; i++) |
|
79 { |
|
80 if (i % pas != 0) |
|
81 { |
|
82 count += Math.Atan(list[i + 1].Y / list[i + 1].X) - Math.Atan(list[i].Y / list[i].X); |
|
83 } |
|
84 else |
|
85 { |
|
86 count /= pas; |
|
87 if (count == 0 || this.GetDistancePoints(past, list[i + 1]) < 5) |
|
88 { |
|
89 y = list[i + 1].Y; |
|
90 past.X = count; |
|
91 continue; |
|
92 } |
|
93 if (y > list[i + 1].Y) |
|
94 { |
|
95 if (past.X > count) |
|
96 this.AddDirection(SurfaceGestureVectorDirection.UPRIGHT); |
|
97 else |
|
98 this.AddDirection(SurfaceGestureVectorDirection.UPLEFT); |
|
99 } |
|
100 else |
|
101 { |
|
102 if (past.X > count) |
|
103 this.AddDirection(SurfaceGestureVectorDirection.DOWNRIGHT); |
|
104 else |
|
105 this.AddDirection(SurfaceGestureVectorDirection.DOWNLEFT); |
|
106 } |
|
107 y = list[i + 1].Y; |
|
108 past.X = count; |
|
109 } |
|
110 } |
|
111 Console.Write(this); |
|
112 if (this.GetPattern() != "None") |
|
113 return true; |
|
114 else |
|
115 return false; |
|
116 } |
|
117 /// <summary> |
|
118 /// Get distance between two points |
|
119 /// </summary> |
|
120 /// <param name="p1"></param> |
|
121 /// <param name="p2"></param> |
|
122 /// <returns></returns> |
|
123 private int GetDistancePoints(SurfaceGesturePoint p1, SurfaceGesturePoint p2) |
|
124 { |
|
125 return (int)Math.Sqrt(Math.Pow((p2.X - p1.X), 2) + Math.Pow((p1.Y - p2.Y), 2)); |
|
126 } |
|
127 /// <summary> |
|
128 /// add a direction in the vector list if past who not the same |
|
129 /// </summary> |
|
130 /// <param name="type"></param> |
|
131 private void AddDirection(SurfaceGestureVectorDirection type) |
|
132 { |
|
133 if (this.Count == 0) |
|
134 { |
|
135 this.Add(new SurfaceGestureVector{Direction = type, Lenght=42}); |
|
136 return ; |
|
137 } |
|
138 if (this[this.Count - 1].Direction != type) |
|
139 this.Add(new SurfaceGestureVector { Direction = type, Lenght = 42 }); |
|
140 } |
|
141 /// <summary> |
|
142 /// generate list of vector |
|
143 /// </summary> |
|
144 /// <param name="list"></param> |
|
145 private void Generate(List<SurfaceGesturePoint> list) |
|
146 { |
|
147 if (list.Count < 2) |
|
148 return ; |
|
149 SurfaceGestureVectorDirection lastDirection = SurfaceGestureVectorDirection.NONE; |
|
150 int lastPoint = 0; |
|
151 SurfaceGesturePoint LastChange = list[0]; |
|
152 |
|
153 /////// TEST/////////// |
|
154 if (this.GenerateCourb(list, 5) == true) |
|
155 return; |
|
156 this.Clear(); |
|
157 /////////////////////// |
|
158 |
|
159 for (int i = 0; i < list.Count - 1; i++) |
|
160 { |
|
161 if (GetHorizontal(list[lastPoint], list[i + 1]) == SurfaceGestureVectorDirection.UP && lastDirection != SurfaceGestureVectorDirection.UP) |
|
162 { |
|
163 this.Add(new SurfaceGestureVector { Direction = SurfaceGestureVectorDirection.UP, Lenght = (Math.Abs(LastChange.Y - list[i + 1].Y)) }); |
|
164 LastChange = list[i + 1]; |
|
165 lastDirection = SurfaceGestureVectorDirection.UP; |
|
166 } |
|
167 else if (GetHorizontal(list[lastPoint], list[i + 1]) == SurfaceGestureVectorDirection.DOWN && lastDirection != SurfaceGestureVectorDirection.DOWN) |
|
168 { |
|
169 this.Add(new SurfaceGestureVector { Direction = SurfaceGestureVectorDirection.DOWN, Lenght = (Math.Abs(LastChange.Y - list[i + 1].Y)) }); |
|
170 LastChange = list[i + 1]; |
|
171 lastDirection = SurfaceGestureVectorDirection.DOWN; |
|
172 } |
|
173 else if (GetVertical(list[lastPoint], list[i + 1]) == SurfaceGestureVectorDirection.LEFT && lastDirection != SurfaceGestureVectorDirection.LEFT) |
|
174 { |
|
175 this.Add(new SurfaceGestureVector { Direction = SurfaceGestureVectorDirection.LEFT, Lenght = (Math.Abs(LastChange.X - list[i + 1].X)) }); |
|
176 LastChange = list[i + 1]; |
|
177 lastDirection = SurfaceGestureVectorDirection.LEFT; |
|
178 } |
|
179 else if (GetVertical(list[lastPoint], list[i + 1]) == SurfaceGestureVectorDirection.RIGHT && lastDirection != SurfaceGestureVectorDirection.RIGHT) |
|
180 { |
|
181 this.Add(new SurfaceGestureVector { Direction = SurfaceGestureVectorDirection.RIGHT, Lenght = (Math.Abs(LastChange.X - list[i + 1].X)) }); |
|
182 LastChange = list[i + 1]; |
|
183 lastDirection = SurfaceGestureVectorDirection.RIGHT; |
|
184 } |
|
185 ++lastPoint; |
|
186 } |
|
187 } |
|
188 private SurfaceGestureVectorDirection GetHorizontal(SurfaceGesturePoint p1, SurfaceGesturePoint p2) |
|
189 { |
|
190 if (p1.Y < p2.Y) |
|
191 { |
|
192 // go up |
|
193 if (Math.Abs(p2.Y - p1.Y) > this.Precision && Math.Abs(p2.X - p1.X) < Math.Abs(p2.Y - p1.Y)) |
|
194 return SurfaceGestureVectorDirection.DOWN; |
|
195 } |
|
196 else |
|
197 { |
|
198 // go down |
|
199 if (Math.Abs(p1.Y - p2.Y) > this.Precision && Math.Abs(p1.X - p2.X) < Math.Abs(p1.Y - p2.Y)) |
|
200 return SurfaceGestureVectorDirection.UP; |
|
201 } |
|
202 return SurfaceGestureVectorDirection.NONE; |
|
203 } |
|
204 private SurfaceGestureVectorDirection GetVertical(SurfaceGesturePoint p1, SurfaceGesturePoint p2) |
|
205 { |
|
206 if (p1.X < p2.X) |
|
207 { |
|
208 // go left |
|
209 if (Math.Abs(p2.X - p1.X) > this.Precision && Math.Abs(p2.Y - p1.Y) < Math.Abs(p2.X - p1.X)) |
|
210 return SurfaceGestureVectorDirection.RIGHT; |
|
211 } |
|
212 else |
|
213 { |
|
214 // go right |
|
215 if (Math.Abs(p1.X - p2.X) > this.Precision && Math.Abs(p1.Y - p2.Y) < Math.Abs(p1.X - p2.X)) |
|
216 return SurfaceGestureVectorDirection.LEFT; |
|
217 } |
|
218 return SurfaceGestureVectorDirection.NONE; |
|
219 } |
|
220 #endregion |
|
221 #region Override |
|
222 public override String ToString() |
|
223 { |
|
224 String ret = ""; |
|
225 |
|
226 foreach (SurfaceGestureVector v in this) |
|
227 { |
|
228 ret += (v.Direction + ", lenght:" + v.Lenght + ", precision:" + this.Precision + "\n"); |
|
229 //Console.WriteLine(v.Direction + ", lenght:" + v.Lenght + ", precision:" + this.Precision); |
|
230 } |
|
231 return ret; |
|
232 } |
|
233 #endregion |
|
234 #region Pattern |
|
235 /// <summary> |
|
236 /// return a String with the recognized pattern, "None" if no pattern |
|
237 /// </summary> |
|
238 /// <returns></returns> |
|
239 public String GetPattern() |
|
240 { |
|
241 foreach (SurfaceGesturePattern p in this.Pattern) |
|
242 { |
|
243 if (p.Count == this.Count) |
|
244 { |
|
245 int i; |
|
246 for (i = 0; i < p.Count; i++) |
|
247 { |
|
248 if (this[i].Direction != p[i].Direction) |
|
249 break ; |
|
250 } |
|
251 if (i == p.Count) |
|
252 return p.Name; |
|
253 } |
|
254 } |
|
255 return "None"; |
|
256 } |
|
257 /// <summary> |
|
258 /// Load know patterns from the Resources/Patterns.xml file |
|
259 /// </summary> |
|
260 private void CommonPattern() |
|
261 { |
|
262 try |
|
263 { |
|
264 #region Load Patterns |
|
265 System.IO.Stream file = Assembly.GetExecutingAssembly().GetManifestResourceStream("GestureControl.Resources.Patterns.xml"); |
|
266 XmlDocument xml = new XmlDocument(); |
|
267 xml.Load(file); |
|
268 XmlElement root = xml.DocumentElement; |
|
269 XmlNodeList nodes = root.SelectNodes("//Pattern"); |
|
270 SurfaceGesturePattern p; |
|
271 int i = 0; |
|
272 foreach (XmlNode node in nodes) |
|
273 { |
|
274 string name = node["Name"].InnerText; |
|
275 XmlNodeList subNodes = node.SelectNodes("//Directions"); |
|
276 if (subNodes == null) |
|
277 continue; |
|
278 p = new SurfaceGesturePattern() { Name = name }; |
|
279 foreach (XmlNode subNode in subNodes[i++]) |
|
280 { |
|
281 XmlNodeList dl = subNode.ChildNodes; |
|
282 foreach (XmlNode d in dl) |
|
283 { |
|
284 switch (d.InnerText) |
|
285 { |
|
286 case "Up": |
|
287 p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.UP }); |
|
288 break; |
|
289 case "Down": |
|
290 p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.DOWN }); |
|
291 break; |
|
292 case "Left": |
|
293 p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.LEFT }); |
|
294 break; |
|
295 case "Right": |
|
296 p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.RIGHT }); |
|
297 break; |
|
298 case "DownRight": |
|
299 p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.DOWNRIGHT }); |
|
300 break; |
|
301 case "DownLeft": |
|
302 p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.DOWNLEFT }); |
|
303 break; |
|
304 case "UpRight": |
|
305 p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.UPRIGHT }); |
|
306 break; |
|
307 case "UpLeft": |
|
308 p.Add(new SurfaceGestureVector() { Direction = SurfaceGestureVectorDirection.UPLEFT }); |
|
309 break; |
|
310 default: |
|
311 break; |
|
312 } |
|
313 } |
|
314 } |
|
315 this.Pattern.Add(p); |
|
316 } |
|
317 #endregion |
|
318 } |
|
319 catch |
|
320 { |
|
321 throw new Exception("Error loading Patterns.xml"); |
|
322 } |
|
323 } |
|
324 #endregion |
|
325 } |
|
326 #region Tools |
|
327 /// <summary> |
|
328 /// Gesture event who return a object with a Gesture String value |
|
329 /// </summary> |
|
330 public class GestureRoutedEventArgs : RoutedEventArgs |
|
331 { |
|
332 public String Gesture { get; private set; } |
|
333 |
|
334 public GestureRoutedEventArgs() : base() { } |
|
335 public GestureRoutedEventArgs(String gesture) : base() { this.Gesture = gesture; } |
|
336 public GestureRoutedEventArgs(RoutedEvent routedEvent) : base(routedEvent) { } |
|
337 public GestureRoutedEventArgs(RoutedEvent routedEvent, String gesture) : base(routedEvent) { this.Gesture = gesture; } |
|
338 public GestureRoutedEventArgs(RoutedEvent routedEvent, Object source) : base(routedEvent, source) { } |
|
339 public GestureRoutedEventArgs(RoutedEvent routedEvent, Object source, String gesture) : base(routedEvent, source) { this.Gesture = gesture; } |
|
340 } |
|
341 |
|
342 public class SurfaceGesturePattern : List<SurfaceGestureVector> |
|
343 { |
|
344 public String Name { get; set; } |
|
345 |
|
346 } |
|
347 /// <summary> |
|
348 /// Possible Gesture Vector |
|
349 /// </summary> |
|
350 public enum SurfaceGestureVectorDirection |
|
351 { |
|
352 UP, |
|
353 DOWN, |
|
354 LEFT, |
|
355 RIGHT, |
|
356 UPLEFT, |
|
357 UPRIGHT, |
|
358 DOWNLEFT, |
|
359 DOWNRIGHT, |
|
360 NONE, |
|
361 } |
|
362 /// <summary> |
|
363 /// Describe a point in the grid |
|
364 /// </summary> |
|
365 public class SurfaceGesturePoint |
|
366 { |
|
367 public double X { get; set; } |
|
368 public double Y { get; set; } |
|
369 } |
|
370 |
|
371 /// <summary> |
|
372 /// Describe a vector to help the recognize pass |
|
373 /// </summary> |
|
374 public class SurfaceGestureVector |
|
375 { |
|
376 public SurfaceGestureVectorDirection Direction { get; set; } |
|
377 public Double Lenght { get; set; } |
|
378 } |
|
379 #endregion |
|
380 } |