Mercurial > sdl-ios-xcode
changeset 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 |
files | include/SDL_events.h src/events/SDL_gesture.c touchTest/touchPong touchTest/touchSimp |
diffstat | 4 files changed, 229 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/include/SDL_events.h Wed Jul 07 04:13:08 2010 -0700 +++ b/include/SDL_events.h Fri Jul 09 00:50:40 2010 -0700 @@ -354,6 +354,22 @@ } SDL_MultiGestureEvent; +typedef struct SDL_DollarGestureEvent +{ + Uint32 type; /**< ::SDL_DOLLARGESTURE */ + Uint32 windowID; /**< The window with mouse focus, if any */ + Uint8 touchId; /**< The touch device index */ + Uint8 gestureId; + Uint8 padding2; + Uint8 padding3; + float error; + /* + //TODO: Enable to give location? + float x; //currently 0...1. Change to screen coords? + float y; + */ +} SDL_DollarGestureEvent; + @@ -443,6 +459,7 @@ SDL_TouchFingerEvent tfinger; /**< Touch finger event data */ SDL_TouchButtonEvent tbutton; /**< Touch button event data */ SDL_MultiGestureEvent mgesture; /**< Multi Finger Gesture data*/ + SDL_DollarGestureEvent dgesture; /**< Multi Finger Gesture data*/ /** Temporarily here for backwards compatibility */ /*@{*/
--- a/src/events/SDL_gesture.c Wed Jul 07 04:13:08 2010 -0700 +++ b/src/events/SDL_gesture.c Fri Jul 09 00:50:40 2010 -0700 @@ -30,6 +30,14 @@ //TODO: Replace with malloc #define MAXFINGERS 3 #define MAXTOUCHES 2 +#define MAXTEMPLATES 4 +#define MAXPATHSIZE 1024 + +#define DOLLARNPOINTS 64 +#define DOLLARSIZE 256 + +//PHI = ((sqrt(5)-1)/2) +#define PHI 0.618033989 typedef struct { float x,y; @@ -42,10 +50,20 @@ int id; } Finger; + +typedef struct { + float length; + + int numPoints; + Point p[MAXPATHSIZE]; +} DollarPath; + + typedef struct { Finger f; Point cv; float dtheta,dDist; + DollarPath dollarPath; } TouchPoint; @@ -55,10 +73,160 @@ Point centroid; TouchPoint gestureLast[MAXFINGERS]; int numDownFingers; + + int numDollarTemplates; + Point dollarTemplate[MAXTEMPLATES][DOLLARNPOINTS]; } GestureTouch; GestureTouch gestureTouch[MAXTOUCHES]; int numGestureTouches = 0; + +float dollarDifference(Point* points,Point* templ,float ang) { + // Point p[DOLLARNPOINTS]; + float dist = 0; + Point p; + int i; + for(i = 0; i < DOLLARNPOINTS; i++) { + p.x = points[i].x * cos(ang) - points[i].y * sin(ang); + p.y = points[i].x * sin(ang) + points[i].y * cos(ang); + dist += sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+ + (p.y-templ[i].y)*(p.y-templ[i].y)); + } + return dist/DOLLARNPOINTS; + +} + +float bestDollarDifference(Point* points,Point* templ) { + //------------BEGIN DOLLAR BLACKBOX----------------// + //-TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-// + //-"http://depts.washington.edu/aimgroup/proj/dollar/"-// + float ta = -M_PI/4; + float tb = M_PI/4; + float dt = M_PI/90; + float x1 = PHI*ta + (1-PHI)*tb; + float f1 = dollarDifference(points,templ,x1); + float x2 = (1-PHI)*ta + PHI*tb; + float f2 = dollarDifference(points,templ,x2); + while(abs(ta-tb) > dt) { + if(f1 < f2) { + tb = x2; + x2 = x1; + f2 = f1; + x1 = PHI*ta + (1-PHI)*tb; + f1 = dollarDifference(points,templ,x1); + } + else { + ta = x1; + x1 = x2; + f1 = f2; + x2 = (1-PHI)*ta + PHI*tb; + f2 = dollarDifference(points,templ,x2); + } + } + /* + if(f1 <= f2) + printf("Min angle (x1): %f\n",x1); + else if(f1 > f2) + printf("Min angle (x2): %f\n",x2); + */ + return SDL_min(f1,f2); +} + +float dollarRecognize(DollarPath path,int *bestTempl,GestureTouch* touch) { + + Point points[DOLLARNPOINTS]; + int numPoints = dollarNormalize(path,points); + int i; + + int bestDiff = 10000; + *bestTempl = -1; + for(i = 0;i < touch->numDollarTemplates;i++) { + int diff = bestDollarDifference(points,touch->dollarTemplate[i]); + if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;} + } + return bestDiff; +} + +//DollarPath contains raw points, plus (possibly) the calculated length +int dollarNormalize(DollarPath path,Point *points) { + int i; + //Calculate length if it hasn't already been done + if(path.length <= 0) { + for(i=1;i<path.numPoints;i++) { + float dx = path.p[i ].x - + path.p[i-1].x; + float dy = path.p[i ].y - + path.p[i-1].y; + path.length += sqrt(dx*dx+dy*dy); + } + } + + + //Resample + float interval = path.length/(DOLLARNPOINTS - 1); + float dist = 0; + + int numPoints = 0; + Point centroid; centroid.x = 0;centroid.y = 0; + //printf("(%f,%f)\n",path.p[path.numPoints-1].x,path.p[path.numPoints-1].y); + for(i = 1;i < path.numPoints;i++) { + float d = sqrt((path.p[i-1].x-path.p[i].x)*(path.p[i-1].x-path.p[i].x)+ + (path.p[i-1].y-path.p[i].y)*(path.p[i-1].y-path.p[i].y)); + //printf("d = %f dist = %f/%f\n",d,dist,interval); + while(dist + d > interval) { + points[numPoints].x = path.p[i-1].x + + ((interval-dist)/d)*(path.p[i].x-path.p[i-1].x); + points[numPoints].y = path.p[i-1].y + + ((interval-dist)/d)*(path.p[i].y-path.p[i-1].y); + centroid.x += points[numPoints].x; + centroid.y += points[numPoints].y; + numPoints++; + + dist -= interval; + } + dist += d; + } + if(numPoints < 1) return 0; + centroid.x /= numPoints; + centroid.y /= numPoints; + + //printf("Centroid (%f,%f)",centroid.x,centroid.y); + //Rotate Points so point 0 is left of centroid and solve for the bounding box + float xmin,xmax,ymin,ymax; + xmin = centroid.x; + xmax = centroid.x; + ymin = centroid.y; + ymax = centroid.y; + + float ang = atan2(centroid.y - points[0].y, + centroid.x - points[0].x); + + for(i = 0;i<numPoints;i++) { + float px = points[i].x; + float py = points[i].y; + points[i].x = (px - centroid.x)*cos(ang) - + (py - centroid.y)*sin(ang) + centroid.x; + points[i].y = (px - centroid.x)*sin(ang) + + (py - centroid.y)*cos(ang) + centroid.y; + + + if(points[i].x < xmin) xmin = points[i].x; + if(points[i].x > xmax) xmax = points[i].x; + if(points[i].y < ymin) ymin = points[i].y; + if(points[i].y > ymax) ymax = points[i].y; + } + + //Scale points to DOLLARSIZE, and translate to the origin + float w = xmax-xmin; + float h = ymax-ymin; + + for(i=0;i<numPoints;i++) { + points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w; + points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h; + } + return numPoints; +} + int SDL_GestureAddTouch(SDL_Touch* touch) { if(numGestureTouches >= MAXTOUCHES) return -1; @@ -69,6 +237,8 @@ gestureTouch[numGestureTouches].res.x = touch->xres; gestureTouch[numGestureTouches].id = touch->id; + gestureTouch[numGestureTouches].numDollarTemplates = 0; + numGestureTouches++; return 0; } @@ -93,6 +263,20 @@ return SDL_PushEvent(&event) > 0; } +int SDL_SendGestureDollar(GestureTouch* touch,int gestureId,float error) { + SDL_Event event; + event.dgesture.type = SDL_DOLLARGESTURE; + event.dgesture.touchId = touch->id; + /* + //TODO: Add this to give location of gesture? + event.mgesture.x = touch->centroid.x; + event.mgesture.y = touch->centroid.y; + */ + event.dgesture.gestureId = gestureId; + event.dgesture.error = error; + return SDL_PushEvent(&event) > 0; +} + void SDL_GestureProcessEvent(SDL_Event* event) { if(event->type == SDL_FINGERMOTION || @@ -100,7 +284,6 @@ event->type == SDL_FINGERUP) { GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId); - //Shouldn't be possible if(inTouch == NULL) return; @@ -114,12 +297,35 @@ if(event->type == SDL_FINGERUP) { inTouch->numDownFingers--; + + int bestTempl; + float error; + error = dollarRecognize(inTouch->gestureLast[j].dollarPath, + &bestTempl,inTouch); + if(bestTempl >= 0){ + //Send Event + int gestureId = 0; //? + SDL_SendGestureDollar(inTouch->id,gestureId,error); + + + printf("Dollar error: %f\n",error); + } + inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers]; break; } else { float dx = x - inTouch->gestureLast[j].f.p.x; float dy = y - inTouch->gestureLast[j].f.p.y; + DollarPath* path = &inTouch->gestureLast[j].dollarPath; + if(path->numPoints < MAXPATHSIZE) { + path->p[path->numPoints].x = x; + path->p[path->numPoints].y = y; + path->length += sqrt(dx*dx + dy*dy); + path->numPoints++; + } + + inTouch->centroid.x += dx/inTouch->numDownFingers; inTouch->centroid.y += dy/inTouch->numDownFingers; if(inTouch->numDownFingers > 1) { @@ -181,6 +387,11 @@ inTouch->gestureLast[j].f.p.y = y; inTouch->gestureLast[j].cv.x = 0; inTouch->gestureLast[j].cv.y = 0; + + inTouch->gestureLast[j].dollarPath.length = 0; + inTouch->gestureLast[j].dollarPath.p[0].x = x; + inTouch->gestureLast[j].dollarPath.p[0].y = y; + inTouch->gestureLast[j].dollarPath.numPoints = 1; } } }