comparison src/events/SDL_gesture.c @ 4658:454385d76845

Moved $1 Gestures into the SDL Library
author Jim Grandpre <jim.tla@gmail.com>
date Fri, 09 Jul 2010 00:50:40 -0700
parents eed063a0bf5b
children 063b9455bd1a
comparison
equal deleted inserted replaced
4657:eed063a0bf5b 4658:454385d76845
28 #include "SDL_gesture_c.h" 28 #include "SDL_gesture_c.h"
29 29
30 //TODO: Replace with malloc 30 //TODO: Replace with malloc
31 #define MAXFINGERS 3 31 #define MAXFINGERS 3
32 #define MAXTOUCHES 2 32 #define MAXTOUCHES 2
33 #define MAXTEMPLATES 4
34 #define MAXPATHSIZE 1024
35
36 #define DOLLARNPOINTS 64
37 #define DOLLARSIZE 256
38
39 //PHI = ((sqrt(5)-1)/2)
40 #define PHI 0.618033989
33 41
34 typedef struct { 42 typedef struct {
35 float x,y; 43 float x,y;
36 } Point; 44 } Point;
37 45
40 Point p; 48 Point p;
41 float pressure; 49 float pressure;
42 int id; 50 int id;
43 } Finger; 51 } Finger;
44 52
53
54 typedef struct {
55 float length;
56
57 int numPoints;
58 Point p[MAXPATHSIZE];
59 } DollarPath;
60
61
45 typedef struct { 62 typedef struct {
46 Finger f; 63 Finger f;
47 Point cv; 64 Point cv;
48 float dtheta,dDist; 65 float dtheta,dDist;
66 DollarPath dollarPath;
49 } TouchPoint; 67 } TouchPoint;
50 68
51 69
52 typedef struct { 70 typedef struct {
53 int id; 71 int id;
54 Point res; 72 Point res;
55 Point centroid; 73 Point centroid;
56 TouchPoint gestureLast[MAXFINGERS]; 74 TouchPoint gestureLast[MAXFINGERS];
57 int numDownFingers; 75 int numDownFingers;
76
77 int numDollarTemplates;
78 Point dollarTemplate[MAXTEMPLATES][DOLLARNPOINTS];
58 } GestureTouch; 79 } GestureTouch;
59 80
60 GestureTouch gestureTouch[MAXTOUCHES]; 81 GestureTouch gestureTouch[MAXTOUCHES];
61 int numGestureTouches = 0; 82 int numGestureTouches = 0;
83
84 float dollarDifference(Point* points,Point* templ,float ang) {
85 // Point p[DOLLARNPOINTS];
86 float dist = 0;
87 Point p;
88 int i;
89 for(i = 0; i < DOLLARNPOINTS; i++) {
90 p.x = points[i].x * cos(ang) - points[i].y * sin(ang);
91 p.y = points[i].x * sin(ang) + points[i].y * cos(ang);
92 dist += sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
93 (p.y-templ[i].y)*(p.y-templ[i].y));
94 }
95 return dist/DOLLARNPOINTS;
96
97 }
98
99 float bestDollarDifference(Point* points,Point* templ) {
100 //------------BEGIN DOLLAR BLACKBOX----------------//
101 //-TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-//
102 //-"http://depts.washington.edu/aimgroup/proj/dollar/"-//
103 float ta = -M_PI/4;
104 float tb = M_PI/4;
105 float dt = M_PI/90;
106 float x1 = PHI*ta + (1-PHI)*tb;
107 float f1 = dollarDifference(points,templ,x1);
108 float x2 = (1-PHI)*ta + PHI*tb;
109 float f2 = dollarDifference(points,templ,x2);
110 while(abs(ta-tb) > dt) {
111 if(f1 < f2) {
112 tb = x2;
113 x2 = x1;
114 f2 = f1;
115 x1 = PHI*ta + (1-PHI)*tb;
116 f1 = dollarDifference(points,templ,x1);
117 }
118 else {
119 ta = x1;
120 x1 = x2;
121 f1 = f2;
122 x2 = (1-PHI)*ta + PHI*tb;
123 f2 = dollarDifference(points,templ,x2);
124 }
125 }
126 /*
127 if(f1 <= f2)
128 printf("Min angle (x1): %f\n",x1);
129 else if(f1 > f2)
130 printf("Min angle (x2): %f\n",x2);
131 */
132 return SDL_min(f1,f2);
133 }
134
135 float dollarRecognize(DollarPath path,int *bestTempl,GestureTouch* touch) {
136
137 Point points[DOLLARNPOINTS];
138 int numPoints = dollarNormalize(path,points);
139 int i;
140
141 int bestDiff = 10000;
142 *bestTempl = -1;
143 for(i = 0;i < touch->numDollarTemplates;i++) {
144 int diff = bestDollarDifference(points,touch->dollarTemplate[i]);
145 if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
146 }
147 return bestDiff;
148 }
149
150 //DollarPath contains raw points, plus (possibly) the calculated length
151 int dollarNormalize(DollarPath path,Point *points) {
152 int i;
153 //Calculate length if it hasn't already been done
154 if(path.length <= 0) {
155 for(i=1;i<path.numPoints;i++) {
156 float dx = path.p[i ].x -
157 path.p[i-1].x;
158 float dy = path.p[i ].y -
159 path.p[i-1].y;
160 path.length += sqrt(dx*dx+dy*dy);
161 }
162 }
163
164
165 //Resample
166 float interval = path.length/(DOLLARNPOINTS - 1);
167 float dist = 0;
168
169 int numPoints = 0;
170 Point centroid; centroid.x = 0;centroid.y = 0;
171 //printf("(%f,%f)\n",path.p[path.numPoints-1].x,path.p[path.numPoints-1].y);
172 for(i = 1;i < path.numPoints;i++) {
173 float d = sqrt((path.p[i-1].x-path.p[i].x)*(path.p[i-1].x-path.p[i].x)+
174 (path.p[i-1].y-path.p[i].y)*(path.p[i-1].y-path.p[i].y));
175 //printf("d = %f dist = %f/%f\n",d,dist,interval);
176 while(dist + d > interval) {
177 points[numPoints].x = path.p[i-1].x +
178 ((interval-dist)/d)*(path.p[i].x-path.p[i-1].x);
179 points[numPoints].y = path.p[i-1].y +
180 ((interval-dist)/d)*(path.p[i].y-path.p[i-1].y);
181 centroid.x += points[numPoints].x;
182 centroid.y += points[numPoints].y;
183 numPoints++;
184
185 dist -= interval;
186 }
187 dist += d;
188 }
189 if(numPoints < 1) return 0;
190 centroid.x /= numPoints;
191 centroid.y /= numPoints;
192
193 //printf("Centroid (%f,%f)",centroid.x,centroid.y);
194 //Rotate Points so point 0 is left of centroid and solve for the bounding box
195 float xmin,xmax,ymin,ymax;
196 xmin = centroid.x;
197 xmax = centroid.x;
198 ymin = centroid.y;
199 ymax = centroid.y;
200
201 float ang = atan2(centroid.y - points[0].y,
202 centroid.x - points[0].x);
203
204 for(i = 0;i<numPoints;i++) {
205 float px = points[i].x;
206 float py = points[i].y;
207 points[i].x = (px - centroid.x)*cos(ang) -
208 (py - centroid.y)*sin(ang) + centroid.x;
209 points[i].y = (px - centroid.x)*sin(ang) +
210 (py - centroid.y)*cos(ang) + centroid.y;
211
212
213 if(points[i].x < xmin) xmin = points[i].x;
214 if(points[i].x > xmax) xmax = points[i].x;
215 if(points[i].y < ymin) ymin = points[i].y;
216 if(points[i].y > ymax) ymax = points[i].y;
217 }
218
219 //Scale points to DOLLARSIZE, and translate to the origin
220 float w = xmax-xmin;
221 float h = ymax-ymin;
222
223 for(i=0;i<numPoints;i++) {
224 points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w;
225 points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h;
226 }
227 return numPoints;
228 }
229
62 int SDL_GestureAddTouch(SDL_Touch* touch) { 230 int SDL_GestureAddTouch(SDL_Touch* touch) {
63 if(numGestureTouches >= MAXTOUCHES) return -1; 231 if(numGestureTouches >= MAXTOUCHES) return -1;
64 232
65 gestureTouch[numGestureTouches].res.x = touch->xres; 233 gestureTouch[numGestureTouches].res.x = touch->xres;
66 gestureTouch[numGestureTouches].res.y = touch->yres; 234 gestureTouch[numGestureTouches].res.y = touch->yres;
67 gestureTouch[numGestureTouches].numDownFingers = 0; 235 gestureTouch[numGestureTouches].numDownFingers = 0;
68 236
69 gestureTouch[numGestureTouches].res.x = touch->xres; 237 gestureTouch[numGestureTouches].res.x = touch->xres;
70 gestureTouch[numGestureTouches].id = touch->id; 238 gestureTouch[numGestureTouches].id = touch->id;
239
240 gestureTouch[numGestureTouches].numDollarTemplates = 0;
71 241
72 numGestureTouches++; 242 numGestureTouches++;
73 return 0; 243 return 0;
74 } 244 }
75 245
91 event.mgesture.dTheta = dTheta; 261 event.mgesture.dTheta = dTheta;
92 event.mgesture.dDist = dDist; 262 event.mgesture.dDist = dDist;
93 return SDL_PushEvent(&event) > 0; 263 return SDL_PushEvent(&event) > 0;
94 } 264 }
95 265
266 int SDL_SendGestureDollar(GestureTouch* touch,int gestureId,float error) {
267 SDL_Event event;
268 event.dgesture.type = SDL_DOLLARGESTURE;
269 event.dgesture.touchId = touch->id;
270 /*
271 //TODO: Add this to give location of gesture?
272 event.mgesture.x = touch->centroid.x;
273 event.mgesture.y = touch->centroid.y;
274 */
275 event.dgesture.gestureId = gestureId;
276 event.dgesture.error = error;
277 return SDL_PushEvent(&event) > 0;
278 }
279
96 void SDL_GestureProcessEvent(SDL_Event* event) 280 void SDL_GestureProcessEvent(SDL_Event* event)
97 { 281 {
98 if(event->type == SDL_FINGERMOTION || 282 if(event->type == SDL_FINGERMOTION ||
99 event->type == SDL_FINGERDOWN || 283 event->type == SDL_FINGERDOWN ||
100 event->type == SDL_FINGERUP) { 284 event->type == SDL_FINGERUP) {
101 GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId); 285 GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
102
103 286
104 //Shouldn't be possible 287 //Shouldn't be possible
105 if(inTouch == NULL) return; 288 if(inTouch == NULL) return;
106 289
107 290
112 for(j = 0;j<inTouch->numDownFingers;j++) { 295 for(j = 0;j<inTouch->numDownFingers;j++) {
113 if(inTouch->gestureLast[j].f.id != event->tfinger.fingerId) continue; 296 if(inTouch->gestureLast[j].f.id != event->tfinger.fingerId) continue;
114 297
115 if(event->type == SDL_FINGERUP) { 298 if(event->type == SDL_FINGERUP) {
116 inTouch->numDownFingers--; 299 inTouch->numDownFingers--;
300
301 int bestTempl;
302 float error;
303 error = dollarRecognize(inTouch->gestureLast[j].dollarPath,
304 &bestTempl,inTouch);
305 if(bestTempl >= 0){
306 //Send Event
307 int gestureId = 0; //?
308 SDL_SendGestureDollar(inTouch->id,gestureId,error);
309
310
311 printf("Dollar error: %f\n",error);
312 }
313
117 inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers]; 314 inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers];
118 break; 315 break;
119 } 316 }
120 else { 317 else {
121 float dx = x - inTouch->gestureLast[j].f.p.x; 318 float dx = x - inTouch->gestureLast[j].f.p.x;
122 float dy = y - inTouch->gestureLast[j].f.p.y; 319 float dy = y - inTouch->gestureLast[j].f.p.y;
320 DollarPath* path = &inTouch->gestureLast[j].dollarPath;
321 if(path->numPoints < MAXPATHSIZE) {
322 path->p[path->numPoints].x = x;
323 path->p[path->numPoints].y = y;
324 path->length += sqrt(dx*dx + dy*dy);
325 path->numPoints++;
326 }
327
328
123 inTouch->centroid.x += dx/inTouch->numDownFingers; 329 inTouch->centroid.x += dx/inTouch->numDownFingers;
124 inTouch->centroid.y += dy/inTouch->numDownFingers; 330 inTouch->centroid.y += dy/inTouch->numDownFingers;
125 if(inTouch->numDownFingers > 1) { 331 if(inTouch->numDownFingers > 1) {
126 Point lv; //Vector from centroid to last x,y position 332 Point lv; //Vector from centroid to last x,y position
127 Point v; //Vector from centroid to current x,y position 333 Point v; //Vector from centroid to current x,y position
179 inTouch->gestureLast[j].f.id = event->tfinger.fingerId; 385 inTouch->gestureLast[j].f.id = event->tfinger.fingerId;
180 inTouch->gestureLast[j].f.p.x = x; 386 inTouch->gestureLast[j].f.p.x = x;
181 inTouch->gestureLast[j].f.p.y = y; 387 inTouch->gestureLast[j].f.p.y = y;
182 inTouch->gestureLast[j].cv.x = 0; 388 inTouch->gestureLast[j].cv.x = 0;
183 inTouch->gestureLast[j].cv.y = 0; 389 inTouch->gestureLast[j].cv.y = 0;
390
391 inTouch->gestureLast[j].dollarPath.length = 0;
392 inTouch->gestureLast[j].dollarPath.p[0].x = x;
393 inTouch->gestureLast[j].dollarPath.p[0].y = y;
394 inTouch->gestureLast[j].dollarPath.numPoints = 1;
184 } 395 }
185 } 396 }
186 } 397 }
187 398
188 /* vi: set ts=4 sw=4 expandtab: */ 399 /* vi: set ts=4 sw=4 expandtab: */