Mercurial > sdl-ios-xcode
comparison touchTest/gestureTest.c @ 4654:7dbcd71216df
Added $1 gesture recognition.
Functional.
author | Jim Grandpre <jim.tla@gmail.com> |
---|---|
date | Thu, 17 Jun 2010 03:41:27 -0400 |
parents | 744b75ad18b8 |
children | 4c94f2023d62 |
comparison
equal
deleted
inserted
replaced
4653:744b75ad18b8 | 4654:7dbcd71216df |
---|---|
2 #include <SDL.h> | 2 #include <SDL.h> |
3 #include <math.h> | 3 #include <math.h> |
4 #include <SDL_touch.h> | 4 #include <SDL_touch.h> |
5 | 5 |
6 #define PI 3.1415926535897 | 6 #define PI 3.1415926535897 |
7 #define PHI ((sqrt(5)-1)/2) | |
7 #define WIDTH 640 | 8 #define WIDTH 640 |
8 #define HEIGHT 480 | 9 #define HEIGHT 480 |
9 #define BPP 4 | 10 #define BPP 4 |
10 #define DEPTH 32 | 11 #define DEPTH 32 |
11 | 12 |
12 #define MAXFINGERS 3 | 13 #define MAXFINGERS 3 |
13 | 14 |
14 | 15 #define DOLLARNPOINTS 64 |
15 | 16 #define DOLLARSIZE 256 |
16 | 17 |
17 //MUST BE A POWER OF 2! | 18 //MUST BE A POWER OF 2! |
18 #define EVENT_BUF_SIZE 256 | 19 #define EVENT_BUF_SIZE 256 |
19 | 20 |
20 SDL_Event events[EVENT_BUF_SIZE]; | 21 SDL_Event events[EVENT_BUF_SIZE]; |
43 Point d,s; //direction, start | 44 Point d,s; //direction, start |
44 int points; | 45 int points; |
45 } Line; | 46 } Line; |
46 | 47 |
47 | 48 |
49 typedef struct { | |
50 float length; | |
51 | |
52 int numPoints; | |
53 Point p[EVENT_BUF_SIZE]; //To be safe | |
54 } DollarPath; | |
55 | |
56 | |
48 Finger finger[MAXFINGERS]; | 57 Finger finger[MAXFINGERS]; |
49 | 58 |
50 Finger gestureLast[MAXFINGERS]; | 59 Finger gestureLast[MAXFINGERS]; |
60 DollarPath dollarPath[MAXFINGERS]; | |
61 | |
62 #define MAXTEMPLATES 4 | |
63 | |
64 Point dollarTemplate[MAXTEMPLATES][DOLLARNPOINTS]; | |
65 int numDollarTemplates = 0; | |
66 #ifdef DRAW_VECTOR_EST | |
51 Line gestureLine[MAXFINGERS]; | 67 Line gestureLine[MAXFINGERS]; |
68 #endif | |
52 | 69 |
53 void handler (int sig) | 70 void handler (int sig) |
54 { | 71 { |
55 printf ("\exiting...(%d)\n", sig); | 72 printf ("\exiting...(%d)\n", sig); |
56 exit (0); | 73 exit (0); |
108 if(r > 0) { //r > 0 ==> filled circle | 125 if(r > 0) { //r > 0 ==> filled circle |
109 for(tx=x-r*cos(a);tx<x+r*cos(a);tx++) { | 126 for(tx=x-r*cos(a);tx<x+r*cos(a);tx++) { |
110 setpix(screen,tx,(int)(y+r*sin(a)),c); | 127 setpix(screen,tx,(int)(y+r*sin(a)),c); |
111 setpix(screen,tx,(int)(y-r*sin(a)),c); | 128 setpix(screen,tx,(int)(y-r*sin(a)),c); |
112 } | 129 } |
113 } | 130 } else { |
114 else { | |
115 //Draw Outline | 131 //Draw Outline |
116 setpix(screen,(int)(x+r*cos(a)),(int)(y+r*sin(a)),c); | 132 setpix(screen,(int)(x+r*cos(a)),(int)(y+r*sin(a)),c); |
117 setpix(screen,(int)(x-r*cos(a)),(int)(y+r*sin(a)),c); | 133 setpix(screen,(int)(x-r*cos(a)),(int)(y+r*sin(a)),c); |
118 setpix(screen,(int)(x+r*cos(a)),(int)(y-r*sin(a)),c); | 134 setpix(screen,(int)(x+r*cos(a)),(int)(y-r*sin(a)),c); |
119 setpix(screen,(int)(x-r*cos(a)),(int)(y-r*sin(a)),c); | 135 setpix(screen,(int)(x-r*cos(a)),(int)(y-r*sin(a)),c); |
131 else { | 147 else { |
132 setpix(screen,x-xr+.5,y+ty,c); | 148 setpix(screen,x-xr+.5,y+ty,c); |
133 setpix(screen,x+xr-.5,y+ty,c); | 149 setpix(screen,x+xr-.5,y+ty,c); |
134 } | 150 } |
135 } | 151 } |
152 } | |
153 | |
154 void drawDollarPath(SDL_Surface* screen,Point* points,int numPoints, | |
155 int rad,unsigned int col){ | |
156 int i; | |
157 for(i=0;i<numPoints;i++) { | |
158 drawCircle(screen,points[i].x+screen->w/2, | |
159 points[i].y+screen->h/2, | |
160 rad,col); | |
161 } | |
162 } | |
163 | |
164 float dollarDifference(Point* points,Point* templ,float ang) { | |
165 // Point p[DOLLARNPOINTS]; | |
166 float dist = 0; | |
167 Point p; | |
168 int i; | |
169 for(i = 0; i < DOLLARNPOINTS; i++) { | |
170 p.x = points[i].x * cos(ang) - points[i].y * sin(ang); | |
171 p.y = points[i].x * sin(ang) + points[i].y * cos(ang); | |
172 dist += sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+ | |
173 (p.y-templ[i].y)*(p.y-templ[i].y)); | |
174 } | |
175 return dist/DOLLARNPOINTS; | |
176 | |
177 } | |
178 | |
179 float bestDollarDifference(Point* points,Point* templ) { | |
180 //------------BEGIN DOLLAR BLACKBOX----------------// | |
181 //-TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-// | |
182 //-"http://depts.washington.edu/aimgroup/proj/dollar/"-// | |
183 float ta = -PI/4; | |
184 float tb = PI/4; | |
185 float dt = PI/90; | |
186 float x1 = PHI*ta + (1-PHI)*tb; | |
187 float f1 = dollarDifference(points,templ,x1); | |
188 float x2 = (1-PHI)*ta + PHI*tb; | |
189 float f2 = dollarDifference(points,templ,x2); | |
190 while(abs(ta-tb) > dt) { | |
191 if(f1 < f2) { | |
192 tb = x2; | |
193 x2 = x1; | |
194 f2 = f1; | |
195 x1 = PHI*ta + (1-PHI)*tb; | |
196 f1 = dollarDifference(points,templ,x1); | |
197 } | |
198 else { | |
199 ta = x1; | |
200 x1 = x2; | |
201 f1 = f2; | |
202 x2 = (1-PHI)*ta + PHI*tb; | |
203 f2 = dollarDifference(points,templ,x2); | |
204 } | |
205 } | |
206 return SDL_min(f1,f2); | |
207 | |
208 } | |
209 | |
210 float dollarRecognize(SDL_Surface* screen, DollarPath path,int *bestTempl) { | |
211 | |
212 Point points[DOLLARNPOINTS]; | |
213 int numPoints = dollarNormalize(path,points); | |
214 int i; | |
215 | |
216 int k; | |
217 for(k = 0;k<DOLLARNPOINTS;k++) { | |
218 printf("(%f,%f)\n",points[k].x, | |
219 points[k].y); | |
220 } | |
221 | |
222 drawDollarPath(screen,points,numPoints,-15,0xFF6600); | |
223 | |
224 int bestDiff = 10000; | |
225 *bestTempl = -1; | |
226 for(i = 0;i < numDollarTemplates;i++) { | |
227 int diff = bestDollarDifference(points,dollarTemplate[i]); | |
228 if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;} | |
229 } | |
230 return bestDiff; | |
231 } | |
232 | |
233 //DollarPath contains raw points, plus (possibly) the calculated length | |
234 int dollarNormalize(DollarPath path,Point *points) { | |
235 int i; | |
236 //Calculate length if it hasn't already been done | |
237 if(path.length <= 0) { | |
238 for(i=1;i<path.numPoints;i++) { | |
239 float dx = path.p[i ].x - | |
240 path.p[i-1].x; | |
241 float dy = path.p[i ].y - | |
242 path.p[i-1].y; | |
243 path.length += sqrt(dx*dx+dy*dy); | |
244 } | |
245 } | |
246 | |
247 | |
248 //Resample | |
249 float interval = path.length/(DOLLARNPOINTS - 1); | |
250 float dist = 0; | |
251 | |
252 int numPoints = 0; | |
253 Point centroid; centroid.x = 0;centroid.y = 0; | |
254 //printf("(%f,%f)\n",path.p[path.numPoints-1].x,path.p[path.numPoints-1].y); | |
255 for(i = 1;i < path.numPoints;i++) { | |
256 float d = sqrt((path.p[i-1].x-path.p[i].x)*(path.p[i-1].x-path.p[i].x)+ | |
257 (path.p[i-1].y-path.p[i].y)*(path.p[i-1].y-path.p[i].y)); | |
258 //printf("d = %f dist = %f/%f\n",d,dist,interval); | |
259 while(dist + d > interval) { | |
260 points[numPoints].x = path.p[i-1].x + | |
261 ((interval-dist)/d)*(path.p[i].x-path.p[i-1].x); | |
262 points[numPoints].y = path.p[i-1].y + | |
263 ((interval-dist)/d)*(path.p[i].y-path.p[i-1].y); | |
264 centroid.x += points[numPoints].x; | |
265 centroid.y += points[numPoints].y; | |
266 numPoints++; | |
267 | |
268 dist -= interval; | |
269 } | |
270 dist += d; | |
271 } | |
272 if(numPoints < 1) return 0; | |
273 centroid.x /= numPoints; | |
274 centroid.y /= numPoints; | |
275 | |
276 //printf("Centroid (%f,%f)",centroid.x,centroid.y); | |
277 //Rotate Points so point 0 is left of centroid and solve for the bounding box | |
278 float xmin,xmax,ymin,ymax; | |
279 xmin = centroid.x; | |
280 xmax = centroid.x; | |
281 ymin = centroid.y; | |
282 ymax = centroid.y; | |
283 | |
284 float ang = atan2(centroid.y - points[0].y, | |
285 centroid.x - points[0].x); | |
286 | |
287 for(i = 0;i<numPoints;i++) { | |
288 float px = points[i].x; | |
289 float py = points[i].y; | |
290 points[i].x = (px - centroid.x)*cos(ang) - | |
291 (py - centroid.y)*sin(ang) + centroid.x; | |
292 points[i].y = (px - centroid.x)*sin(ang) + | |
293 (py - centroid.y)*cos(ang) + centroid.y; | |
294 | |
295 | |
296 if(points[i].x < xmin) xmin = points[i].x; | |
297 if(points[i].x > xmax) xmax = points[i].x; | |
298 if(points[i].y < ymin) ymin = points[i].y; | |
299 if(points[i].y > ymax) ymax = points[i].y; | |
300 } | |
301 | |
302 //Scale points to DOLLARSIZE, and translate to the origin | |
303 float w = xmax-xmin; | |
304 float h = ymax-ymin; | |
305 | |
306 for(i=0;i<numPoints;i++) { | |
307 points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w; | |
308 points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h; | |
309 } | |
310 return numPoints; | |
136 } | 311 } |
137 | 312 |
138 void DrawScreen(SDL_Surface* screen, int h) | 313 void DrawScreen(SDL_Surface* screen, int h) |
139 { | 314 { |
140 int x, y, xm,ym,c; | 315 int x, y, xm,ym,c; |
159 drawLine(screen,0,0,screen->w,screen->h,0xFFFFFF); | 334 drawLine(screen,0,0,screen->w,screen->h,0xFFFFFF); |
160 int i; | 335 int i; |
161 //draw Touch History | 336 //draw Touch History |
162 for(i = 0;i < MAXFINGERS;i++) { | 337 for(i = 0;i < MAXFINGERS;i++) { |
163 gestureLast[i].id = -1; | 338 gestureLast[i].id = -1; |
339 #ifdef DRAW_VECTOR_EST | |
164 gestureLine[i].points = 0; | 340 gestureLine[i].points = 0; |
341 #endif | |
165 } | 342 } |
166 for(i = SDL_max(0,eventWrite - EVENT_BUF_SIZE);i != eventWrite;i++) { | 343 for(i = SDL_max(0,eventWrite - EVENT_BUF_SIZE);i != eventWrite;i++) { |
167 SDL_Event event = events[i&(EVENT_BUF_SIZE-1)]; | 344 SDL_Event event = events[i&(EVENT_BUF_SIZE-1)]; |
168 int age = eventWrite - i - 1; | 345 int age = eventWrite - i - 1; |
169 if(event.type == SDL_FINGERMOTION || | 346 if(event.type == SDL_FINGERMOTION || |
173 //SDL_Finger* inFinger = SDL_GetFinger(inTouch,event.tfinger.fingerId); | 350 //SDL_Finger* inFinger = SDL_GetFinger(inTouch,event.tfinger.fingerId); |
174 | 351 |
175 float x = ((float)event.tfinger.x)/inTouch->xres; | 352 float x = ((float)event.tfinger.x)/inTouch->xres; |
176 float y = ((float)event.tfinger.y)/inTouch->yres; | 353 float y = ((float)event.tfinger.y)/inTouch->yres; |
177 int j,empty = -1; | 354 int j,empty = -1; |
355 | |
178 for(j = 0;j<MAXFINGERS;j++) { | 356 for(j = 0;j<MAXFINGERS;j++) { |
179 if(gestureLast[j].id == event.tfinger.fingerId) { | 357 if(gestureLast[j].id == event.tfinger.fingerId) { |
180 if(event.type == SDL_FINGERUP) { | 358 if(event.type == SDL_FINGERUP) { |
359 #ifdef DRAW_VECTOR_EST | |
181 if(gestureLine[j].points > 0) | 360 if(gestureLine[j].points > 0) |
182 drawLine(screen, | 361 drawLine(screen, |
183 gestureLine[j].s.x*screen->w, | 362 gestureLine[j].s.x*screen->w, |
184 gestureLine[j].s.y*screen->h, | 363 gestureLine[j].s.y*screen->h, |
185 (gestureLine[j].s.x +50*gestureLine[j].d.x)*screen->w, | 364 (gestureLine[j].s.x +50*gestureLine[j].d.x)*screen->w, |
186 (gestureLine[j].s.y +50*gestureLine[j].d.y)*screen->h, | 365 (gestureLine[j].s.y +50*gestureLine[j].d.y)*screen->h, |
187 0xFF00); | 366 0xFF00); |
188 | 367 |
189 gestureLine[j].points = 0; | 368 gestureLine[j].points = 0; |
369 #endif | |
370 //ignore last point - probably invalid | |
371 dollarPath[j].numPoints--; | |
372 | |
373 | |
374 float dx = dollarPath[j].p[dollarPath[j].numPoints].x - | |
375 dollarPath[j].p[dollarPath[j].numPoints - 1].x; | |
376 float dy = dollarPath[j].p[dollarPath[j].numPoints].y - | |
377 dollarPath[j].p[dollarPath[j].numPoints - 1].y; | |
378 dollarPath[j].length -= sqrt(dx*dx+dy*dy); | |
379 | |
380 if(!keystat[32]){ //spacebar | |
381 int bestTempl; | |
382 float error = dollarRecognize(screen,dollarPath[j],&bestTempl); | |
383 printf("%i\n",bestTempl); | |
384 if(bestTempl >= 0){ | |
385 drawDollarPath(screen,dollarTemplate[bestTempl] | |
386 ,DOLLARNPOINTS,-15,0x0066FF);\ | |
387 | |
388 printf("ERROR: %f\n",error); | |
389 } | |
390 | |
391 } | |
392 else if(numDollarTemplates < MAXTEMPLATES) { | |
393 | |
394 dollarNormalize(dollarPath[j], | |
395 dollarTemplate[numDollarTemplates]); | |
396 int k; | |
397 /* | |
398 for(k = 0;k<DOLLARNPOINTS;k++) { | |
399 printf("(%f,%f)\n",dollarTemplate[numDollarTemplates][i].x, | |
400 dollarTemplate[numDollarTemplates][i].y); | |
401 }*/ | |
402 numDollarTemplates++; | |
403 } | |
404 | |
190 gestureLast[j].id = -1; | 405 gestureLast[j].id = -1; |
191 break; | 406 break; |
192 } | 407 } |
193 else { | 408 else { |
409 #ifdef DRAW_VECTOR_EST | |
194 if(gestureLine[j].points == 1) { | 410 if(gestureLine[j].points == 1) { |
195 gestureLine[j].d.x = x - gestureLine[j].s.x; | 411 gestureLine[j].d.x = x - gestureLine[j].s.x; |
196 gestureLine[j].d.y = y - gestureLine[j].s.y; | 412 gestureLine[j].d.y = y - gestureLine[j].s.y; |
197 } | 413 } |
198 | 414 |
209 | 425 |
210 gestureLine[j].s.x /= gestureLine[j].points; | 426 gestureLine[j].s.x /= gestureLine[j].points; |
211 gestureLine[j].s.y /= gestureLine[j].points; | 427 gestureLine[j].s.y /= gestureLine[j].points; |
212 | 428 |
213 gestureLine[j].d.x /= gestureLine[j].points; | 429 gestureLine[j].d.x /= gestureLine[j].points; |
214 gestureLine[j].d.y /= gestureLine[j].points; | 430 gestureLine[j].d.y /= gestureLine[j].points; |
215 | 431 #endif |
216 | 432 |
433 dollarPath[j].p[dollarPath[j].numPoints].x = x; | |
434 dollarPath[j].p[dollarPath[j].numPoints].y = y; | |
435 float dx = (dollarPath[j].p[dollarPath[j].numPoints-1].x- | |
436 dollarPath[j].p[dollarPath[j].numPoints ].x); | |
437 float dy = (dollarPath[j].p[dollarPath[j].numPoints-1].y- | |
438 dollarPath[j].p[dollarPath[j].numPoints ].y); | |
439 dollarPath[j].length += sqrt(dx*dx + dy*dy); | |
440 | |
441 dollarPath[j].numPoints++; | |
217 | 442 |
218 | 443 |
219 gestureLast[j].p.x = x; | 444 gestureLast[j].p.x = x; |
220 gestureLast[j].p.y = y; | 445 gestureLast[j].p.y = y; |
221 break; | 446 break; |
224 } | 449 } |
225 else if(gestureLast[j].id == -1 && empty == -1) { | 450 else if(gestureLast[j].id == -1 && empty == -1) { |
226 empty = j; | 451 empty = j; |
227 } | 452 } |
228 } | 453 } |
229 | 454 |
230 if(j >= MAXFINGERS && empty >= 0) { | 455 if(j >= MAXFINGERS && empty >= 0) { |
231 printf("Finger Down!!!\n"); | 456 // printf("Finger Down!!!\n"); |
232 j = empty; //important that j is the index of the added finger | 457 j = empty; //important that j is the index of the added finger |
233 gestureLast[j].id = event.tfinger.fingerId; | 458 gestureLast[j].id = event.tfinger.fingerId; |
234 gestureLast[j].p.x = x; | 459 gestureLast[j].p.x = x; |
235 gestureLast[j].p.y = y; | 460 gestureLast[j].p.y = y; |
236 | 461 #ifdef DRAW_VECTOR_EST |
237 gestureLine[j].s.x = x; | 462 gestureLine[j].s.x = x; |
238 gestureLine[j].s.y = y; | 463 gestureLine[j].s.y = y; |
239 gestureLine[j].points = 1; | 464 gestureLine[j].points = 1; |
465 #endif | |
466 | |
467 dollarPath[j].length = 0; | |
468 dollarPath[j].p[0].x = x; | |
469 dollarPath[j].p[0].y = y; | |
470 dollarPath[j].numPoints = 1; | |
240 } | 471 } |
241 | 472 |
242 //draw the touch && each centroid: | 473 //draw the touch && each centroid: |
243 | 474 |
244 if(gestureLast[j].id < 0) continue; //Finger up. Or some error... | 475 if(gestureLast[j].id < 0) continue; //Finger up. Or some error... |
271 else | 502 else |
272 drawCircle(screen,finger[i].p.x*screen->w,finger[i].p.y*screen->h | 503 drawCircle(screen,finger[i].p.x*screen->w,finger[i].p.y*screen->h |
273 ,20,0xFF); | 504 ,20,0xFF); |
274 | 505 |
275 | 506 |
276 | 507 keystat[32] = 0; |
277 | 508 |
278 if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); | 509 if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); |
279 | 510 |
280 SDL_Flip(screen); | 511 SDL_Flip(screen); |
281 } | 512 } |
398 break; | 629 break; |
399 } | 630 } |
400 } | 631 } |
401 //And draw | 632 //And draw |
402 DrawScreen(screen,h); | 633 DrawScreen(screen,h); |
403 /* | 634 |
404 for(i=0;i<512;i++) | 635 //for(i=0;i<512;i++) |
405 if(keystat[i]) printf("%i\n",i); | 636 // if(keystat[i]) printf("%i\n",i); |
406 printf("Buttons:%i\n",bstatus); | 637 |
407 */ | 638 |
408 } | 639 } |
409 SDL_Quit(); | 640 SDL_Quit(); |
410 | 641 |
411 return 0; | 642 return 0; |
412 } | 643 } |