1.1 --- a/include/SDL_events.h Wed Jul 07 04:13:08 2010 -0700
1.2 +++ b/include/SDL_events.h Fri Jul 09 00:50:40 2010 -0700
1.3 @@ -354,6 +354,22 @@
1.4
1.5 } SDL_MultiGestureEvent;
1.6
1.7 +typedef struct SDL_DollarGestureEvent
1.8 +{
1.9 + Uint32 type; /**< ::SDL_DOLLARGESTURE */
1.10 + Uint32 windowID; /**< The window with mouse focus, if any */
1.11 + Uint8 touchId; /**< The touch device index */
1.12 + Uint8 gestureId;
1.13 + Uint8 padding2;
1.14 + Uint8 padding3;
1.15 + float error;
1.16 + /*
1.17 + //TODO: Enable to give location?
1.18 + float x; //currently 0...1. Change to screen coords?
1.19 + float y;
1.20 + */
1.21 +} SDL_DollarGestureEvent;
1.22 +
1.23
1.24
1.25
1.26 @@ -443,6 +459,7 @@
1.27 SDL_TouchFingerEvent tfinger; /**< Touch finger event data */
1.28 SDL_TouchButtonEvent tbutton; /**< Touch button event data */
1.29 SDL_MultiGestureEvent mgesture; /**< Multi Finger Gesture data*/
1.30 + SDL_DollarGestureEvent dgesture; /**< Multi Finger Gesture data*/
1.31
1.32 /** Temporarily here for backwards compatibility */
1.33 /*@{*/
2.1 --- a/src/events/SDL_gesture.c Wed Jul 07 04:13:08 2010 -0700
2.2 +++ b/src/events/SDL_gesture.c Fri Jul 09 00:50:40 2010 -0700
2.3 @@ -30,6 +30,14 @@
2.4 //TODO: Replace with malloc
2.5 #define MAXFINGERS 3
2.6 #define MAXTOUCHES 2
2.7 +#define MAXTEMPLATES 4
2.8 +#define MAXPATHSIZE 1024
2.9 +
2.10 +#define DOLLARNPOINTS 64
2.11 +#define DOLLARSIZE 256
2.12 +
2.13 +//PHI = ((sqrt(5)-1)/2)
2.14 +#define PHI 0.618033989
2.15
2.16 typedef struct {
2.17 float x,y;
2.18 @@ -42,10 +50,20 @@
2.19 int id;
2.20 } Finger;
2.21
2.22 +
2.23 +typedef struct {
2.24 + float length;
2.25 +
2.26 + int numPoints;
2.27 + Point p[MAXPATHSIZE];
2.28 +} DollarPath;
2.29 +
2.30 +
2.31 typedef struct {
2.32 Finger f;
2.33 Point cv;
2.34 float dtheta,dDist;
2.35 + DollarPath dollarPath;
2.36 } TouchPoint;
2.37
2.38
2.39 @@ -55,10 +73,160 @@
2.40 Point centroid;
2.41 TouchPoint gestureLast[MAXFINGERS];
2.42 int numDownFingers;
2.43 +
2.44 + int numDollarTemplates;
2.45 + Point dollarTemplate[MAXTEMPLATES][DOLLARNPOINTS];
2.46 } GestureTouch;
2.47
2.48 GestureTouch gestureTouch[MAXTOUCHES];
2.49 int numGestureTouches = 0;
2.50 +
2.51 +float dollarDifference(Point* points,Point* templ,float ang) {
2.52 + // Point p[DOLLARNPOINTS];
2.53 + float dist = 0;
2.54 + Point p;
2.55 + int i;
2.56 + for(i = 0; i < DOLLARNPOINTS; i++) {
2.57 + p.x = points[i].x * cos(ang) - points[i].y * sin(ang);
2.58 + p.y = points[i].x * sin(ang) + points[i].y * cos(ang);
2.59 + dist += sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
2.60 + (p.y-templ[i].y)*(p.y-templ[i].y));
2.61 + }
2.62 + return dist/DOLLARNPOINTS;
2.63 +
2.64 +}
2.65 +
2.66 +float bestDollarDifference(Point* points,Point* templ) {
2.67 + //------------BEGIN DOLLAR BLACKBOX----------------//
2.68 + //-TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-//
2.69 + //-"http://depts.washington.edu/aimgroup/proj/dollar/"-//
2.70 + float ta = -M_PI/4;
2.71 + float tb = M_PI/4;
2.72 + float dt = M_PI/90;
2.73 + float x1 = PHI*ta + (1-PHI)*tb;
2.74 + float f1 = dollarDifference(points,templ,x1);
2.75 + float x2 = (1-PHI)*ta + PHI*tb;
2.76 + float f2 = dollarDifference(points,templ,x2);
2.77 + while(abs(ta-tb) > dt) {
2.78 + if(f1 < f2) {
2.79 + tb = x2;
2.80 + x2 = x1;
2.81 + f2 = f1;
2.82 + x1 = PHI*ta + (1-PHI)*tb;
2.83 + f1 = dollarDifference(points,templ,x1);
2.84 + }
2.85 + else {
2.86 + ta = x1;
2.87 + x1 = x2;
2.88 + f1 = f2;
2.89 + x2 = (1-PHI)*ta + PHI*tb;
2.90 + f2 = dollarDifference(points,templ,x2);
2.91 + }
2.92 + }
2.93 + /*
2.94 + if(f1 <= f2)
2.95 + printf("Min angle (x1): %f\n",x1);
2.96 + else if(f1 > f2)
2.97 + printf("Min angle (x2): %f\n",x2);
2.98 + */
2.99 + return SDL_min(f1,f2);
2.100 +}
2.101 +
2.102 +float dollarRecognize(DollarPath path,int *bestTempl,GestureTouch* touch) {
2.103 +
2.104 + Point points[DOLLARNPOINTS];
2.105 + int numPoints = dollarNormalize(path,points);
2.106 + int i;
2.107 +
2.108 + int bestDiff = 10000;
2.109 + *bestTempl = -1;
2.110 + for(i = 0;i < touch->numDollarTemplates;i++) {
2.111 + int diff = bestDollarDifference(points,touch->dollarTemplate[i]);
2.112 + if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
2.113 + }
2.114 + return bestDiff;
2.115 +}
2.116 +
2.117 +//DollarPath contains raw points, plus (possibly) the calculated length
2.118 +int dollarNormalize(DollarPath path,Point *points) {
2.119 + int i;
2.120 + //Calculate length if it hasn't already been done
2.121 + if(path.length <= 0) {
2.122 + for(i=1;i<path.numPoints;i++) {
2.123 + float dx = path.p[i ].x -
2.124 + path.p[i-1].x;
2.125 + float dy = path.p[i ].y -
2.126 + path.p[i-1].y;
2.127 + path.length += sqrt(dx*dx+dy*dy);
2.128 + }
2.129 + }
2.130 +
2.131 +
2.132 + //Resample
2.133 + float interval = path.length/(DOLLARNPOINTS - 1);
2.134 + float dist = 0;
2.135 +
2.136 + int numPoints = 0;
2.137 + Point centroid; centroid.x = 0;centroid.y = 0;
2.138 + //printf("(%f,%f)\n",path.p[path.numPoints-1].x,path.p[path.numPoints-1].y);
2.139 + for(i = 1;i < path.numPoints;i++) {
2.140 + float d = sqrt((path.p[i-1].x-path.p[i].x)*(path.p[i-1].x-path.p[i].x)+
2.141 + (path.p[i-1].y-path.p[i].y)*(path.p[i-1].y-path.p[i].y));
2.142 + //printf("d = %f dist = %f/%f\n",d,dist,interval);
2.143 + while(dist + d > interval) {
2.144 + points[numPoints].x = path.p[i-1].x +
2.145 + ((interval-dist)/d)*(path.p[i].x-path.p[i-1].x);
2.146 + points[numPoints].y = path.p[i-1].y +
2.147 + ((interval-dist)/d)*(path.p[i].y-path.p[i-1].y);
2.148 + centroid.x += points[numPoints].x;
2.149 + centroid.y += points[numPoints].y;
2.150 + numPoints++;
2.151 +
2.152 + dist -= interval;
2.153 + }
2.154 + dist += d;
2.155 + }
2.156 + if(numPoints < 1) return 0;
2.157 + centroid.x /= numPoints;
2.158 + centroid.y /= numPoints;
2.159 +
2.160 + //printf("Centroid (%f,%f)",centroid.x,centroid.y);
2.161 + //Rotate Points so point 0 is left of centroid and solve for the bounding box
2.162 + float xmin,xmax,ymin,ymax;
2.163 + xmin = centroid.x;
2.164 + xmax = centroid.x;
2.165 + ymin = centroid.y;
2.166 + ymax = centroid.y;
2.167 +
2.168 + float ang = atan2(centroid.y - points[0].y,
2.169 + centroid.x - points[0].x);
2.170 +
2.171 + for(i = 0;i<numPoints;i++) {
2.172 + float px = points[i].x;
2.173 + float py = points[i].y;
2.174 + points[i].x = (px - centroid.x)*cos(ang) -
2.175 + (py - centroid.y)*sin(ang) + centroid.x;
2.176 + points[i].y = (px - centroid.x)*sin(ang) +
2.177 + (py - centroid.y)*cos(ang) + centroid.y;
2.178 +
2.179 +
2.180 + if(points[i].x < xmin) xmin = points[i].x;
2.181 + if(points[i].x > xmax) xmax = points[i].x;
2.182 + if(points[i].y < ymin) ymin = points[i].y;
2.183 + if(points[i].y > ymax) ymax = points[i].y;
2.184 + }
2.185 +
2.186 + //Scale points to DOLLARSIZE, and translate to the origin
2.187 + float w = xmax-xmin;
2.188 + float h = ymax-ymin;
2.189 +
2.190 + for(i=0;i<numPoints;i++) {
2.191 + points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w;
2.192 + points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h;
2.193 + }
2.194 + return numPoints;
2.195 +}
2.196 +
2.197 int SDL_GestureAddTouch(SDL_Touch* touch) {
2.198 if(numGestureTouches >= MAXTOUCHES) return -1;
2.199
2.200 @@ -69,6 +237,8 @@
2.201 gestureTouch[numGestureTouches].res.x = touch->xres;
2.202 gestureTouch[numGestureTouches].id = touch->id;
2.203
2.204 + gestureTouch[numGestureTouches].numDollarTemplates = 0;
2.205 +
2.206 numGestureTouches++;
2.207 return 0;
2.208 }
2.209 @@ -93,6 +263,20 @@
2.210 return SDL_PushEvent(&event) > 0;
2.211 }
2.212
2.213 +int SDL_SendGestureDollar(GestureTouch* touch,int gestureId,float error) {
2.214 + SDL_Event event;
2.215 + event.dgesture.type = SDL_DOLLARGESTURE;
2.216 + event.dgesture.touchId = touch->id;
2.217 + /*
2.218 + //TODO: Add this to give location of gesture?
2.219 + event.mgesture.x = touch->centroid.x;
2.220 + event.mgesture.y = touch->centroid.y;
2.221 + */
2.222 + event.dgesture.gestureId = gestureId;
2.223 + event.dgesture.error = error;
2.224 + return SDL_PushEvent(&event) > 0;
2.225 +}
2.226 +
2.227 void SDL_GestureProcessEvent(SDL_Event* event)
2.228 {
2.229 if(event->type == SDL_FINGERMOTION ||
2.230 @@ -100,7 +284,6 @@
2.231 event->type == SDL_FINGERUP) {
2.232 GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
2.233
2.234 -
2.235 //Shouldn't be possible
2.236 if(inTouch == NULL) return;
2.237
2.238 @@ -114,12 +297,35 @@
2.239
2.240 if(event->type == SDL_FINGERUP) {
2.241 inTouch->numDownFingers--;
2.242 +
2.243 + int bestTempl;
2.244 + float error;
2.245 + error = dollarRecognize(inTouch->gestureLast[j].dollarPath,
2.246 + &bestTempl,inTouch);
2.247 + if(bestTempl >= 0){
2.248 + //Send Event
2.249 + int gestureId = 0; //?
2.250 + SDL_SendGestureDollar(inTouch->id,gestureId,error);
2.251 +
2.252 +
2.253 + printf("Dollar error: %f\n",error);
2.254 + }
2.255 +
2.256 inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers];
2.257 break;
2.258 }
2.259 else {
2.260 float dx = x - inTouch->gestureLast[j].f.p.x;
2.261 float dy = y - inTouch->gestureLast[j].f.p.y;
2.262 + DollarPath* path = &inTouch->gestureLast[j].dollarPath;
2.263 + if(path->numPoints < MAXPATHSIZE) {
2.264 + path->p[path->numPoints].x = x;
2.265 + path->p[path->numPoints].y = y;
2.266 + path->length += sqrt(dx*dx + dy*dy);
2.267 + path->numPoints++;
2.268 + }
2.269 +
2.270 +
2.271 inTouch->centroid.x += dx/inTouch->numDownFingers;
2.272 inTouch->centroid.y += dy/inTouch->numDownFingers;
2.273 if(inTouch->numDownFingers > 1) {
2.274 @@ -181,6 +387,11 @@
2.275 inTouch->gestureLast[j].f.p.y = y;
2.276 inTouch->gestureLast[j].cv.x = 0;
2.277 inTouch->gestureLast[j].cv.y = 0;
2.278 +
2.279 + inTouch->gestureLast[j].dollarPath.length = 0;
2.280 + inTouch->gestureLast[j].dollarPath.p[0].x = x;
2.281 + inTouch->gestureLast[j].dollarPath.p[0].y = y;
2.282 + inTouch->gestureLast[j].dollarPath.numPoints = 1;
2.283 }
2.284 }
2.285 }
3.1 Binary file touchTest/touchPong has changed
4.1 Binary file touchTest/touchSimp has changed