Added $1 gesture recognition.
authorJim Grandpre
Thu, 17 Jun 2010 03:41:27 -0400
changeset 46547dbcd71216df
parent 4653 744b75ad18b8
child 4655 4c94f2023d62
Added $1 gesture recognition.
Functional.
src/events/SDL_touch.c
touchTest/gestureTest.c
     1.1 --- a/src/events/SDL_touch.c	Tue Jun 15 02:12:16 2010 -0400
     1.2 +++ b/src/events/SDL_touch.c	Thu Jun 17 03:41:27 2010 -0400
     1.3 @@ -322,7 +322,7 @@
     1.4  	nf.last_y = y;
     1.5  	nf.last_pressure = pressure;
     1.6  	SDL_AddFinger(touch,&nf);
     1.7 -
     1.8 +	//if(x < 0 || y < 0) return 0; //should defer if only a partial input
     1.9  	posted = 0;
    1.10  	if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
    1.11  	    SDL_Event event;
    1.12 @@ -364,15 +364,14 @@
    1.13      int xrel;
    1.14      int yrel;
    1.15      int x_max = 0, y_max = 0;
    1.16 -
    1.17 +	
    1.18      if (!touch || touch->flush_motion) {
    1.19 -        return 0;
    1.20 +		return 0;
    1.21      }
    1.22 -
    1.23 -	if(finger == NULL) {
    1.24 -		SDL_SendFingerDown(id,fingerid,SDL_TRUE,x,y,pressure);
    1.25 -		return 0;
    1.26 -	} else {
    1.27 +    
    1.28 +    if(finger == NULL) {
    1.29 +		return SDL_SendFingerDown(id,fingerid,SDL_TRUE,x,y,pressure);	
    1.30 +    } else {
    1.31  		/* the relative motion is calculated regarding the last position */
    1.32  		if (relative) {
    1.33  			xrel = x;
    1.34 @@ -389,9 +388,9 @@
    1.35  		
    1.36  		/* Drop events that don't change state */
    1.37  		if (!xrel && !yrel) {
    1.38 -	#if 0
    1.39 +#if 0
    1.40  			printf("Touch event didn't change state - dropped!\n");
    1.41 -	#endif
    1.42 +#endif
    1.43  			return 0;
    1.44  		}
    1.45  		
     2.1 --- a/touchTest/gestureTest.c	Tue Jun 15 02:12:16 2010 -0400
     2.2 +++ b/touchTest/gestureTest.c	Thu Jun 17 03:41:27 2010 -0400
     2.3 @@ -4,6 +4,7 @@
     2.4  #include <SDL_touch.h>
     2.5  
     2.6  #define PI 3.1415926535897
     2.7 +#define PHI ((sqrt(5)-1)/2)
     2.8  #define WIDTH 640
     2.9  #define HEIGHT 480
    2.10  #define BPP 4
    2.11 @@ -11,8 +12,8 @@
    2.12  
    2.13  #define MAXFINGERS 3
    2.14  
    2.15 -
    2.16 -
    2.17 +#define DOLLARNPOINTS 64
    2.18 +#define DOLLARSIZE 256
    2.19  
    2.20  //MUST BE A POWER OF 2!
    2.21  #define EVENT_BUF_SIZE 256
    2.22 @@ -45,10 +46,26 @@
    2.23  } Line;
    2.24  
    2.25  
    2.26 +typedef struct {
    2.27 +  float length;
    2.28 +  
    2.29 +  int numPoints;
    2.30 +  Point p[EVENT_BUF_SIZE]; //To be safe
    2.31 +} DollarPath;
    2.32 +
    2.33 +
    2.34  Finger finger[MAXFINGERS];
    2.35  
    2.36  Finger gestureLast[MAXFINGERS];
    2.37 +DollarPath dollarPath[MAXFINGERS];
    2.38 +
    2.39 +#define MAXTEMPLATES 4
    2.40 +
    2.41 +Point dollarTemplate[MAXTEMPLATES][DOLLARNPOINTS];
    2.42 +int numDollarTemplates = 0;
    2.43 +#ifdef DRAW_VECTOR_EST
    2.44  Line gestureLine[MAXFINGERS];
    2.45 +#endif
    2.46  
    2.47  void handler (int sig)
    2.48  {
    2.49 @@ -110,8 +127,7 @@
    2.50  	setpix(screen,tx,(int)(y+r*sin(a)),c);
    2.51  	setpix(screen,tx,(int)(y-r*sin(a)),c);
    2.52        }
    2.53 -    }
    2.54 -    else {
    2.55 +    }    else {
    2.56        //Draw Outline
    2.57        setpix(screen,(int)(x+r*cos(a)),(int)(y+r*sin(a)),c);
    2.58        setpix(screen,(int)(x-r*cos(a)),(int)(y+r*sin(a)),c);
    2.59 @@ -135,6 +151,165 @@
    2.60    }
    2.61  }
    2.62  
    2.63 +void drawDollarPath(SDL_Surface* screen,Point* points,int numPoints,
    2.64 +		    int rad,unsigned int col){
    2.65 +  int i;
    2.66 +  for(i=0;i<numPoints;i++) {
    2.67 +    drawCircle(screen,points[i].x+screen->w/2,
    2.68 +	       points[i].y+screen->h/2,
    2.69 +	       rad,col);
    2.70 +  }
    2.71 +}
    2.72 +
    2.73 +float dollarDifference(Point* points,Point* templ,float ang) {
    2.74 +  //  Point p[DOLLARNPOINTS];
    2.75 +  float dist = 0;
    2.76 +  Point p;
    2.77 +  int i;
    2.78 +  for(i = 0; i < DOLLARNPOINTS; i++) {
    2.79 +    p.x = points[i].x * cos(ang) - points[i].y * sin(ang);
    2.80 +    p.y = points[i].x * sin(ang) + points[i].y * cos(ang);
    2.81 +    dist += sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
    2.82 +		 (p.y-templ[i].y)*(p.y-templ[i].y));
    2.83 +  }
    2.84 +  return dist/DOLLARNPOINTS;
    2.85 +  
    2.86 +}
    2.87 +
    2.88 +float bestDollarDifference(Point* points,Point* templ) {
    2.89 +  //------------BEGIN DOLLAR BLACKBOX----------------//
    2.90 +  //-TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-//
    2.91 +  //-"http://depts.washington.edu/aimgroup/proj/dollar/"-//
    2.92 +  float ta = -PI/4;
    2.93 +  float tb = PI/4;
    2.94 +  float dt = PI/90;
    2.95 +  float x1 = PHI*ta + (1-PHI)*tb;
    2.96 +  float f1 = dollarDifference(points,templ,x1);
    2.97 +  float x2 = (1-PHI)*ta + PHI*tb;
    2.98 +  float f2 = dollarDifference(points,templ,x2);
    2.99 +  while(abs(ta-tb) > dt) {
   2.100 +    if(f1 < f2) {
   2.101 +      tb = x2;
   2.102 +      x2 = x1;
   2.103 +      f2 = f1;
   2.104 +      x1 = PHI*ta + (1-PHI)*tb;
   2.105 +      f1 = dollarDifference(points,templ,x1);
   2.106 +    }
   2.107 +    else {
   2.108 +      ta = x1;
   2.109 +      x1 = x2;
   2.110 +      f1 = f2;
   2.111 +      x2 = (1-PHI)*ta + PHI*tb;
   2.112 +      f2 = dollarDifference(points,templ,x2);
   2.113 +    }
   2.114 +  }
   2.115 +  return SDL_min(f1,f2);
   2.116 +  
   2.117 +}
   2.118 +
   2.119 +float dollarRecognize(SDL_Surface* screen, DollarPath path,int *bestTempl) {
   2.120 +
   2.121 +  Point points[DOLLARNPOINTS];
   2.122 +  int numPoints = dollarNormalize(path,points);
   2.123 +  int i;
   2.124 +  
   2.125 +  int k;
   2.126 +  for(k = 0;k<DOLLARNPOINTS;k++) {
   2.127 +    printf("(%f,%f)\n",points[k].x,
   2.128 +	   points[k].y);
   2.129 +  }
   2.130 +
   2.131 +  drawDollarPath(screen,points,numPoints,-15,0xFF6600);
   2.132 +
   2.133 +  int bestDiff = 10000;
   2.134 +  *bestTempl = -1;
   2.135 +  for(i = 0;i < numDollarTemplates;i++) {
   2.136 +    int diff = bestDollarDifference(points,dollarTemplate[i]);
   2.137 +    if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
   2.138 +  }
   2.139 +  return bestDiff;
   2.140 +}
   2.141 +
   2.142 +//DollarPath contains raw points, plus (possibly) the calculated length
   2.143 +int dollarNormalize(DollarPath path,Point *points) {
   2.144 +  int i;
   2.145 +  //Calculate length if it hasn't already been done
   2.146 +  if(path.length <= 0) {
   2.147 +    for(i=1;i<path.numPoints;i++) {
   2.148 +      float dx = path.p[i  ].x - 
   2.149 +	         path.p[i-1].x;
   2.150 +      float dy = path.p[i  ].y - 
   2.151 +	         path.p[i-1].y;
   2.152 +      path.length += sqrt(dx*dx+dy*dy);
   2.153 +    }
   2.154 +  }
   2.155 +
   2.156 +
   2.157 +  //Resample
   2.158 +  float interval = path.length/(DOLLARNPOINTS - 1);
   2.159 +  float dist = 0;
   2.160 +
   2.161 +  int numPoints = 0;
   2.162 +  Point centroid; centroid.x = 0;centroid.y = 0;
   2.163 +  //printf("(%f,%f)\n",path.p[path.numPoints-1].x,path.p[path.numPoints-1].y);
   2.164 +  for(i = 1;i < path.numPoints;i++) {
   2.165 +    float d = sqrt((path.p[i-1].x-path.p[i].x)*(path.p[i-1].x-path.p[i].x)+
   2.166 +		   (path.p[i-1].y-path.p[i].y)*(path.p[i-1].y-path.p[i].y));
   2.167 +    //printf("d = %f dist = %f/%f\n",d,dist,interval);
   2.168 +    while(dist + d > interval) {
   2.169 +      points[numPoints].x = path.p[i-1].x + 
   2.170 +	((interval-dist)/d)*(path.p[i].x-path.p[i-1].x);
   2.171 +      points[numPoints].y = path.p[i-1].y + 
   2.172 +	((interval-dist)/d)*(path.p[i].y-path.p[i-1].y);
   2.173 +      centroid.x += points[numPoints].x;
   2.174 +      centroid.y += points[numPoints].y;
   2.175 +      numPoints++;
   2.176 +
   2.177 +      dist -= interval;
   2.178 +    }
   2.179 +    dist += d;
   2.180 +  }
   2.181 +  if(numPoints < 1) return 0;
   2.182 +  centroid.x /= numPoints;
   2.183 +  centroid.y /= numPoints;
   2.184 + 
   2.185 +  //printf("Centroid (%f,%f)",centroid.x,centroid.y);
   2.186 +  //Rotate Points so point 0 is left of centroid and solve for the bounding box
   2.187 +  float xmin,xmax,ymin,ymax;
   2.188 +  xmin = centroid.x;
   2.189 +  xmax = centroid.x;
   2.190 +  ymin = centroid.y;
   2.191 +  ymax = centroid.y;
   2.192 +  
   2.193 +  float ang = atan2(centroid.y - points[0].y,
   2.194 +		    centroid.x - points[0].x);
   2.195 +
   2.196 +  for(i = 0;i<numPoints;i++) {					       
   2.197 +    float px = points[i].x;
   2.198 +    float py = points[i].y;
   2.199 +    points[i].x = (px - centroid.x)*cos(ang) - 
   2.200 +                  (py - centroid.y)*sin(ang) + centroid.x;
   2.201 +    points[i].y = (px - centroid.x)*sin(ang) + 
   2.202 +                  (py - centroid.y)*cos(ang) + centroid.y;
   2.203 +
   2.204 +
   2.205 +    if(points[i].x < xmin) xmin = points[i].x;
   2.206 +    if(points[i].x > xmax) xmax = points[i].x; 
   2.207 +    if(points[i].y < ymin) ymin = points[i].y;
   2.208 +    if(points[i].y > ymax) ymax = points[i].y;
   2.209 +  }
   2.210 +
   2.211 +  //Scale points to DOLLARSIZE, and translate to the origin
   2.212 +  float w = xmax-xmin;
   2.213 +  float h = ymax-ymin;
   2.214 +
   2.215 +  for(i=0;i<numPoints;i++) {
   2.216 +    points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w;
   2.217 +    points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h;
   2.218 +  }  
   2.219 +  return numPoints;
   2.220 +}
   2.221 +
   2.222  void DrawScreen(SDL_Surface* screen, int h)
   2.223  {
   2.224    int x, y, xm,ym,c;
   2.225 @@ -161,7 +336,9 @@
   2.226  //draw Touch History
   2.227    for(i = 0;i < MAXFINGERS;i++) {
   2.228      gestureLast[i].id = -1;
   2.229 +#ifdef DRAW_VECTOR_EST
   2.230      gestureLine[i].points = 0;
   2.231 +#endif
   2.232    }
   2.233    for(i = SDL_max(0,eventWrite - EVENT_BUF_SIZE);i != eventWrite;i++) {
   2.234      SDL_Event event = events[i&(EVENT_BUF_SIZE-1)];
   2.235 @@ -175,11 +352,13 @@
   2.236        float x = ((float)event.tfinger.x)/inTouch->xres;
   2.237        float y = ((float)event.tfinger.y)/inTouch->yres;
   2.238        int j,empty = -1;
   2.239 +      
   2.240        for(j = 0;j<MAXFINGERS;j++) {
   2.241  	if(gestureLast[j].id == event.tfinger.fingerId) {
   2.242  	  if(event.type == SDL_FINGERUP) {
   2.243 +#ifdef DRAW_VECTOR_EST
   2.244  	    if(gestureLine[j].points > 0)
   2.245 -	    drawLine(screen,
   2.246 +	      drawLine(screen,
   2.247  		     gestureLine[j].s.x*screen->w,
   2.248  		     gestureLine[j].s.y*screen->h,
   2.249  		     (gestureLine[j].s.x +50*gestureLine[j].d.x)*screen->w,
   2.250 @@ -187,10 +366,47 @@
   2.251  		     0xFF00);
   2.252  
   2.253  	    gestureLine[j].points = 0;
   2.254 +#endif
   2.255 +	    //ignore last point - probably invalid
   2.256 +	    dollarPath[j].numPoints--;
   2.257 +	    
   2.258 +	    
   2.259 +	    float dx = dollarPath[j].p[dollarPath[j].numPoints].x - 
   2.260 +	      dollarPath[j].p[dollarPath[j].numPoints - 1].x;
   2.261 +	    float dy = dollarPath[j].p[dollarPath[j].numPoints].y - 
   2.262 +	      dollarPath[j].p[dollarPath[j].numPoints - 1].y;
   2.263 +	    dollarPath[j].length -= sqrt(dx*dx+dy*dy);
   2.264 +
   2.265 +	    if(!keystat[32]){ //spacebar
   2.266 +	      int bestTempl;
   2.267 +	      float error = dollarRecognize(screen,dollarPath[j],&bestTempl);
   2.268 +	      printf("%i\n",bestTempl);
   2.269 +	      if(bestTempl >= 0){
   2.270 +		drawDollarPath(screen,dollarTemplate[bestTempl]
   2.271 +			       ,DOLLARNPOINTS,-15,0x0066FF);\
   2.272 +		
   2.273 +		printf("ERROR: %f\n",error);
   2.274 +	      }
   2.275 +	      
   2.276 +	    }
   2.277 +	    else if(numDollarTemplates < MAXTEMPLATES) {
   2.278 +	      
   2.279 +	      dollarNormalize(dollarPath[j],
   2.280 +			      dollarTemplate[numDollarTemplates]);
   2.281 +	      int k;
   2.282 +	      /*
   2.283 +	      for(k = 0;k<DOLLARNPOINTS;k++) {
   2.284 +		printf("(%f,%f)\n",dollarTemplate[numDollarTemplates][i].x,
   2.285 +		       dollarTemplate[numDollarTemplates][i].y);
   2.286 +		       }*/
   2.287 +	      numDollarTemplates++;	      
   2.288 +	    }
   2.289 +
   2.290  	    gestureLast[j].id = -1;
   2.291  	    break;
   2.292  	  }
   2.293  	  else {
   2.294 +#ifdef DRAW_VECTOR_EST
   2.295  	    if(gestureLine[j].points == 1) {
   2.296  	      gestureLine[j].d.x = x - gestureLine[j].s.x;
   2.297  	      gestureLine[j].d.y = y - gestureLine[j].s.y;
   2.298 @@ -211,9 +427,18 @@
   2.299  	    gestureLine[j].s.y /= gestureLine[j].points;
   2.300  
   2.301  	    gestureLine[j].d.x /= gestureLine[j].points;
   2.302 -	    gestureLine[j].d.y /= gestureLine[j].points;
   2.303 +	    gestureLine[j].d.y /= gestureLine[j].points;	    
   2.304 +#endif
   2.305  
   2.306 -	    
   2.307 +	    dollarPath[j].p[dollarPath[j].numPoints].x = x;
   2.308 +	    dollarPath[j].p[dollarPath[j].numPoints].y = y;
   2.309 +	    float dx = (dollarPath[j].p[dollarPath[j].numPoints-1].x-
   2.310 +		      dollarPath[j].p[dollarPath[j].numPoints  ].x);
   2.311 +	    float dy = (dollarPath[j].p[dollarPath[j].numPoints-1].y-
   2.312 +		      dollarPath[j].p[dollarPath[j].numPoints  ].y);
   2.313 +	    dollarPath[j].length += sqrt(dx*dx + dy*dy);
   2.314 +
   2.315 +	    dollarPath[j].numPoints++;
   2.316  	    
   2.317  
   2.318  	    gestureLast[j].p.x = x;
   2.319 @@ -226,17 +451,23 @@
   2.320  	  empty = j;
   2.321  	}
   2.322        }
   2.323 -
   2.324 +      
   2.325        if(j >= MAXFINGERS && empty >= 0) {
   2.326 -	printf("Finger Down!!!\n");
   2.327 +	//	printf("Finger Down!!!\n");
   2.328  	j = empty; //important that j is the index of the added finger
   2.329  	gestureLast[j].id = event.tfinger.fingerId;
   2.330  	gestureLast[j].p.x  = x;
   2.331  	gestureLast[j].p.y  = y;
   2.332 -
   2.333 +#ifdef DRAW_VECTOR_EST
   2.334  	gestureLine[j].s.x = x;
   2.335  	gestureLine[j].s.y = y;
   2.336  	gestureLine[j].points = 1;
   2.337 +#endif
   2.338 +
   2.339 +	dollarPath[j].length = 0;
   2.340 +	dollarPath[j].p[0].x = x;
   2.341 +	dollarPath[j].p[0].y = y;
   2.342 +	dollarPath[j].numPoints = 1;
   2.343        }
   2.344  
   2.345        //draw the touch && each centroid:
   2.346 @@ -273,7 +504,7 @@
   2.347  		   ,20,0xFF);
   2.348  
   2.349    
   2.350 -  
   2.351 +  keystat[32] = 0;	      
   2.352  
   2.353    if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
   2.354    
   2.355 @@ -400,11 +631,11 @@
   2.356        }
   2.357      //And draw
   2.358      DrawScreen(screen,h);
   2.359 -    /*
   2.360 -      for(i=0;i<512;i++) 
   2.361 -      if(keystat[i]) printf("%i\n",i);
   2.362 -      printf("Buttons:%i\n",bstatus);
   2.363 -    */
   2.364 +    
   2.365 +    //for(i=0;i<512;i++) 
   2.366 +    // if(keystat[i]) printf("%i\n",i);
   2.367 +    
   2.368 +    
   2.369    }  
   2.370    SDL_Quit();
   2.371