src/events/SDL_gesture.c
author Jim Grandpre <jim.tla@gmail.com>
Sun, 15 Aug 2010 00:36:28 -0400
changeset 4689 f9ab8df6d45a
parent 4688 494f71f57a80
child 4865 fff50e86c891
child 4880 27c458e4ae31
permissions -rw-r--r--
Added README.touch and README.gesture. Moved touchtest/gestureSDLTest to test/testgesture
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software    Founation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    17 
    18     Sam Lantinga
    19     slouken@libsdl.org
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* General mouse handling code for SDL */
    24 
    25 #include "SDL_events.h"
    26 #include "SDL_events_c.h"
    27 #include "SDL_gesture_c.h"
    28 
    29 //TODO: Replace with malloc
    30 
    31 #define MAXPATHSIZE 1024
    32 
    33  
    34 
    35 
    36 #define DOLLARNPOINTS 64
    37 #define DOLLARSIZE 256
    38 
    39 #define ENABLE_DOLLAR
    40 
    41 //PHI = ((sqrt(5)-1)/2)
    42 #define PHI 0.618033989 
    43 
    44 typedef struct {
    45   float x,y;
    46 } SDL_FloatPoint;
    47 
    48 typedef struct {
    49   float length;
    50   
    51   int numPoints;
    52   SDL_FloatPoint p[MAXPATHSIZE];
    53 } SDL_DollarPath;
    54 
    55 typedef struct {
    56   SDL_FloatPoint path[DOLLARNPOINTS];
    57   unsigned long hash;
    58 } SDL_DollarTemplate;
    59 
    60 typedef struct {
    61   SDL_GestureID id;
    62   SDL_FloatPoint res;
    63   SDL_FloatPoint centroid;
    64   SDL_DollarPath dollarPath;
    65   Uint16 numDownFingers;
    66 
    67   int numDollarTemplates;
    68   SDL_DollarTemplate *dollarTemplate;
    69 
    70   SDL_bool recording;
    71 } SDL_GestureTouch;
    72 
    73 SDL_GestureTouch *SDL_gestureTouch;
    74 int SDL_numGestureTouches = 0;
    75 SDL_bool recordAll;
    76 
    77 void SDL_PrintPath(SDL_FloatPoint *path) {
    78   int i;
    79   printf("Path:");
    80   for(i=0;i<DOLLARNPOINTS;i++) {
    81     printf(" (%f,%f)",path[i].x,path[i].y);
    82   }
    83   printf("\n");
    84 }
    85 
    86 int SDL_RecordGesture(SDL_TouchID touchId) {
    87   int i;
    88   if(touchId < 0) recordAll = SDL_TRUE;
    89   for(i = 0;i < SDL_numGestureTouches; i++) {
    90     if((touchId < 0) || (SDL_gestureTouch[i].id == touchId)) {
    91       SDL_gestureTouch[i].recording = SDL_TRUE;
    92       if(touchId >= 0)
    93 	return 1;
    94     }      
    95   }
    96   return (touchId < 0);
    97 }
    98 
    99 unsigned long SDL_HashDollar(SDL_FloatPoint* points) {
   100   unsigned long hash = 5381;
   101   int i;
   102   for(i = 0;i < DOLLARNPOINTS; i++) { 
   103     hash = ((hash<<5) + hash) + points[i].x;
   104     hash = ((hash<<5) + hash) + points[i].y;
   105   }
   106   return hash;
   107 }
   108 
   109 
   110 static int SaveTemplate(SDL_DollarTemplate *templ, SDL_RWops * src) {
   111   if(src == NULL) return 0;
   112 
   113   int i;
   114   
   115   //No Longer storing the Hash, rehash on load
   116   //if(SDL_RWops.write(src,&(templ->hash),sizeof(templ->hash),1) != 1) return 0;
   117   
   118   if(SDL_RWwrite(src,templ->path,
   119 		 sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) 
   120     return 0;
   121 
   122   return 1;
   123 }
   124 
   125 
   126 int SDL_SaveAllDollarTemplates(SDL_RWops *src) {  
   127   int i,j,rtrn = 0;
   128   for(i = 0; i < SDL_numGestureTouches; i++) {
   129     SDL_GestureTouch* touch = &SDL_gestureTouch[i];
   130     for(j = 0;j < touch->numDollarTemplates; j++) {
   131 	rtrn += SaveTemplate(&touch->dollarTemplate[i],src);
   132     }
   133   }
   134   return rtrn;  
   135 }
   136 
   137 int SDL_SaveDollarTemplate(SDL_GestureID gestureId, SDL_RWops *src) {
   138   int i,j;
   139   for(i = 0; i < SDL_numGestureTouches; i++) {
   140     SDL_GestureTouch* touch = &SDL_gestureTouch[i];
   141     for(j = 0;j < touch->numDollarTemplates; j++) {
   142       if(touch->dollarTemplate[i].hash == gestureId) {
   143 	return SaveTemplate(&touch->dollarTemplate[i],src);
   144       }
   145     }
   146   }
   147   SDL_SetError("Unknown gestureId");
   148   return -1;
   149 }
   150 
   151 //path is an already sampled set of points
   152 //Returns the index of the gesture on success, or -1
   153 static int SDL_AddDollarGesture(SDL_GestureTouch* inTouch,SDL_FloatPoint* path) {
   154   if(inTouch == NULL) {
   155     if(SDL_numGestureTouches == 0) return -1;
   156     int i = 0;
   157     for(i = 0;i < SDL_numGestureTouches; i++) {
   158       inTouch = &SDL_gestureTouch[i];
   159 
   160       SDL_DollarTemplate* dollarTemplate = 
   161 	SDL_realloc(inTouch->dollarTemplate,
   162 		    (inTouch->numDollarTemplates + 1) * 
   163 		    sizeof(SDL_DollarTemplate));
   164       if(!dollarTemplate) {
   165 	SDL_OutOfMemory();
   166 	return -1;
   167       }
   168 	
   169       inTouch->dollarTemplate = dollarTemplate;
   170 
   171       SDL_DollarTemplate *templ = 
   172 	&inTouch->dollarTemplate[inTouch->numDollarTemplates];
   173       memcpy(templ->path,path,DOLLARNPOINTS*sizeof(SDL_FloatPoint));
   174       templ->hash = SDL_HashDollar(templ->path);
   175       inTouch->numDollarTemplates++;    
   176     }
   177     return inTouch->numDollarTemplates - 1;
   178   } else {
   179     SDL_DollarTemplate* dollarTemplate = 
   180       SDL_realloc(inTouch->dollarTemplate,
   181 		  (inTouch->numDollarTemplates + 1) * 
   182 		  sizeof(SDL_DollarTemplate));
   183     if(!dollarTemplate) {
   184       SDL_OutOfMemory();
   185       return -1;
   186     }
   187     
   188     inTouch->dollarTemplate = dollarTemplate;
   189 
   190     SDL_DollarTemplate *templ = 
   191       &inTouch->dollarTemplate[inTouch->numDollarTemplates];
   192     memcpy(templ->path,path,DOLLARNPOINTS*sizeof(SDL_FloatPoint));
   193     templ->hash = SDL_HashDollar(templ->path);
   194     inTouch->numDollarTemplates++;
   195     return inTouch->numDollarTemplates - 1;
   196   }
   197   return -1;
   198 }
   199 
   200 int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src) {
   201   if(src == NULL) return 0;
   202   int i,loaded = 0;
   203   SDL_GestureTouch *touch = NULL;
   204   if(touchId >= 0) {
   205     for(i = 0;i < SDL_numGestureTouches; i++)
   206       if(SDL_gestureTouch[i].id == touchId)
   207 	touch = &SDL_gestureTouch[i];
   208     if(touch == NULL) return -1;
   209   }
   210 
   211   while(1) {
   212     SDL_DollarTemplate templ;
   213 
   214     if(SDL_RWread(src,templ.path,sizeof(templ.path[0]),DOLLARNPOINTS) < 
   215        DOLLARNPOINTS) break;
   216 
   217     if(touchId >= 0) {
   218       printf("Adding loaded gesture to 1 touch\n");
   219       if(SDL_AddDollarGesture(touch,templ.path)) loaded++;
   220     }
   221     else {
   222       printf("Adding to: %i touches\n",SDL_numGestureTouches);
   223       for(i = 0;i < SDL_numGestureTouches; i++) {
   224 	touch = &SDL_gestureTouch[i];
   225 	printf("Adding loaded gesture to + touches\n");
   226 	//TODO: What if this fails?
   227 	SDL_AddDollarGesture(touch,templ.path);	
   228       }
   229       loaded++;
   230     }
   231   }
   232 
   233   return loaded; 
   234 }
   235 
   236 
   237 float dollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ,float ang) {
   238   //  SDL_FloatPoint p[DOLLARNPOINTS];
   239   float dist = 0;
   240   SDL_FloatPoint p;
   241   int i;
   242   for(i = 0; i < DOLLARNPOINTS; i++) {
   243     p.x = points[i].x * cos(ang) - points[i].y * sin(ang);
   244     p.y = points[i].x * sin(ang) + points[i].y * cos(ang);
   245     dist += sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
   246 		 (p.y-templ[i].y)*(p.y-templ[i].y));
   247   }
   248   return dist/DOLLARNPOINTS;
   249   
   250 }
   251 
   252 float bestDollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ) {
   253   //------------BEGIN DOLLAR BLACKBOX----------------//
   254   //-TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-//
   255   //-"http://depts.washington.edu/aimgroup/proj/dollar/"-//
   256   float ta = -M_PI/4;
   257   float tb = M_PI/4;
   258   float dt = M_PI/90;
   259   float x1 = PHI*ta + (1-PHI)*tb;
   260   float f1 = dollarDifference(points,templ,x1);
   261   float x2 = (1-PHI)*ta + PHI*tb;
   262   float f2 = dollarDifference(points,templ,x2);
   263   while(abs(ta-tb) > dt) {
   264     if(f1 < f2) {
   265       tb = x2;
   266       x2 = x1;
   267       f2 = f1;
   268       x1 = PHI*ta + (1-PHI)*tb;
   269       f1 = dollarDifference(points,templ,x1);
   270     }
   271     else {
   272       ta = x1;
   273       x1 = x2;
   274       f1 = f2;
   275       x2 = (1-PHI)*ta + PHI*tb;
   276       f2 = dollarDifference(points,templ,x2);
   277     }
   278   }
   279   /*
   280   if(f1 <= f2)
   281     printf("Min angle (x1): %f\n",x1);
   282   else if(f1 >  f2)
   283     printf("Min angle (x2): %f\n",x2);
   284   */
   285   return SDL_min(f1,f2);  
   286 }
   287 
   288 //DollarPath contains raw points, plus (possibly) the calculated length
   289 int dollarNormalize(SDL_DollarPath path,SDL_FloatPoint *points) {
   290   int i;
   291   //Calculate length if it hasn't already been done
   292   if(path.length <= 0) {
   293     for(i=1;i<path.numPoints;i++) {
   294       float dx = path.p[i  ].x - 
   295 	         path.p[i-1].x;
   296       float dy = path.p[i  ].y - 
   297 	         path.p[i-1].y;
   298       path.length += sqrt(dx*dx+dy*dy);
   299     }
   300   }
   301 
   302   //Resample
   303   float interval = path.length/(DOLLARNPOINTS - 1);
   304   float dist = interval;
   305 
   306   int numPoints = 0;
   307   SDL_FloatPoint centroid; 
   308   centroid.x = 0;centroid.y = 0;
   309   
   310   //printf("(%f,%f)\n",path.p[path.numPoints-1].x,path.p[path.numPoints-1].y);
   311   for(i = 1;i < path.numPoints;i++) {
   312     float d = sqrt((path.p[i-1].x-path.p[i].x)*(path.p[i-1].x-path.p[i].x)+
   313 		   (path.p[i-1].y-path.p[i].y)*(path.p[i-1].y-path.p[i].y));
   314     //printf("d = %f dist = %f/%f\n",d,dist,interval);
   315     while(dist + d > interval) {
   316       points[numPoints].x = path.p[i-1].x + 
   317 	((interval-dist)/d)*(path.p[i].x-path.p[i-1].x);
   318       points[numPoints].y = path.p[i-1].y + 
   319 	((interval-dist)/d)*(path.p[i].y-path.p[i-1].y);
   320       centroid.x += points[numPoints].x;
   321       centroid.y += points[numPoints].y;
   322       numPoints++;
   323 
   324       dist -= interval;
   325     }
   326     dist += d;
   327   }
   328   if(numPoints < DOLLARNPOINTS-1) {
   329     printf("ERROR: NumPoints = %i\n",numPoints); 
   330     return 0;
   331   }
   332   //copy the last point
   333   points[DOLLARNPOINTS-1] = path.p[path.numPoints-1];
   334   numPoints = DOLLARNPOINTS;
   335 
   336   centroid.x /= numPoints;
   337   centroid.y /= numPoints;
   338  
   339   //printf("Centroid (%f,%f)",centroid.x,centroid.y);
   340   //Rotate Points so point 0 is left of centroid and solve for the bounding box
   341   float xmin,xmax,ymin,ymax;
   342   xmin = centroid.x;
   343   xmax = centroid.x;
   344   ymin = centroid.y;
   345   ymax = centroid.y;
   346   
   347   float ang = atan2(centroid.y - points[0].y,
   348 		    centroid.x - points[0].x);
   349 
   350   for(i = 0;i<numPoints;i++) {					       
   351     float px = points[i].x;
   352     float py = points[i].y;
   353     points[i].x = (px - centroid.x)*cos(ang) - 
   354                   (py - centroid.y)*sin(ang) + centroid.x;
   355     points[i].y = (px - centroid.x)*sin(ang) + 
   356                   (py - centroid.y)*cos(ang) + centroid.y;
   357 
   358 
   359     if(points[i].x < xmin) xmin = points[i].x;
   360     if(points[i].x > xmax) xmax = points[i].x; 
   361     if(points[i].y < ymin) ymin = points[i].y;
   362     if(points[i].y > ymax) ymax = points[i].y;
   363   }
   364 
   365   //Scale points to DOLLARSIZE, and translate to the origin
   366   float w = xmax-xmin;
   367   float h = ymax-ymin;
   368 
   369   for(i=0;i<numPoints;i++) {
   370     points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w;
   371     points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h;
   372   }  
   373   return numPoints;
   374 }
   375 
   376 float dollarRecognize(SDL_DollarPath path,int *bestTempl,SDL_GestureTouch* touch) {
   377 	
   378 	SDL_FloatPoint points[DOLLARNPOINTS];
   379 	int numPoints = dollarNormalize(path,points);
   380 	//SDL_PrintPath(points);
   381 	int i;
   382 	
   383 	int bestDiff = 10000;
   384 	*bestTempl = -1;
   385 	for(i = 0;i < touch->numDollarTemplates;i++) {
   386 		int diff = bestDollarDifference(points,touch->dollarTemplate[i].path);
   387 		if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
   388 	}
   389 	return bestDiff;
   390 }
   391 
   392 int SDL_GestureAddTouch(SDL_Touch* touch) {  
   393   SDL_GestureTouch *gestureTouch = SDL_realloc(SDL_gestureTouch,
   394 					       (SDL_numGestureTouches + 1) *
   395 					       sizeof(SDL_GestureTouch));
   396 
   397   if(!gestureTouch) {
   398     SDL_OutOfMemory();
   399     return -1;
   400   }
   401 
   402   SDL_gestureTouch = gestureTouch;
   403 
   404   SDL_gestureTouch[SDL_numGestureTouches].res.x = touch->xres;
   405   SDL_gestureTouch[SDL_numGestureTouches].res.y = touch->yres;
   406   SDL_gestureTouch[SDL_numGestureTouches].numDownFingers = 0;
   407 
   408   SDL_gestureTouch[SDL_numGestureTouches].res.x = touch->xres;
   409   SDL_gestureTouch[SDL_numGestureTouches].id = touch->id;
   410 
   411   SDL_gestureTouch[SDL_numGestureTouches].numDollarTemplates = 0;
   412 
   413   SDL_gestureTouch[SDL_numGestureTouches].recording = SDL_FALSE;
   414 
   415   SDL_numGestureTouches++;
   416   return 0;
   417 }
   418 
   419 int SDL_GestureRemoveTouch(SDL_TouchID id) {
   420   int i;
   421   for(i = 0;i < SDL_numGestureTouches; i++) {
   422     if(SDL_gestureTouch[i].id == id) {
   423       SDL_numGestureTouches--;
   424       SDL_gestureTouch[i] = SDL_gestureTouch[SDL_numGestureTouches];
   425       return 1;
   426     }
   427   }
   428   return -1;
   429 }
   430 
   431 
   432 SDL_GestureTouch * SDL_GetGestureTouch(SDL_TouchID id) {
   433   int i;
   434   for(i = 0;i < SDL_numGestureTouches; i++) {
   435     //printf("%i ?= %i\n",SDL_gestureTouch[i].id,id);
   436     if(SDL_gestureTouch[i].id == id) return &SDL_gestureTouch[i];
   437   }
   438   return NULL;
   439 }
   440 
   441 int SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist) {
   442   SDL_Event event;
   443   event.mgesture.type = SDL_MULTIGESTURE;
   444   event.mgesture.touchId = touch->id;
   445   event.mgesture.x = touch->centroid.x;
   446   event.mgesture.y = touch->centroid.y;
   447   event.mgesture.dTheta = dTheta;
   448   event.mgesture.dDist = dDist;  
   449   event.mgesture.numFingers = touch->numDownFingers;
   450   return SDL_PushEvent(&event) > 0;
   451 }
   452 
   453 int SDL_SendGestureDollar(SDL_GestureTouch* touch,
   454 			  SDL_GestureID gestureId,float error) {
   455   SDL_Event event;
   456   event.dgesture.type = SDL_DOLLARGESTURE;
   457   event.dgesture.touchId = touch->id;
   458   /*
   459     //TODO: Add this to give location of gesture?
   460   event.mgesture.x = touch->centroid.x;
   461   event.mgesture.y = touch->centroid.y;
   462   */
   463   event.dgesture.gestureId = gestureId;
   464   event.dgesture.error = error;  
   465   //A finger came up to trigger this event.
   466   event.dgesture.numFingers = touch->numDownFingers + 1; 
   467   return SDL_PushEvent(&event) > 0;
   468 }
   469 
   470 
   471 int SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId) {
   472   SDL_Event event;
   473   event.dgesture.type = SDL_DOLLARRECORD;
   474   event.dgesture.touchId = touch->id;
   475   event.dgesture.gestureId = gestureId;
   476   return SDL_PushEvent(&event) > 0;
   477 }
   478 
   479 
   480 void SDL_GestureProcessEvent(SDL_Event* event)
   481 {
   482   if(event->type == SDL_FINGERMOTION || 
   483      event->type == SDL_FINGERDOWN ||
   484      event->type == SDL_FINGERUP) {
   485     SDL_GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
   486     
   487     //Shouldn't be possible
   488     if(inTouch == NULL) return;
   489     
   490     //printf("@ (%i,%i) with res: (%i,%i)\n",(int)event->tfinger.x,
   491     //	   (int)event->tfinger.y,
   492     //   (int)inTouch->res.x,(int)inTouch->res.y);
   493 
   494     
   495     float x = ((float)event->tfinger.x)/(float)inTouch->res.x;
   496     float y = ((float)event->tfinger.y)/(float)inTouch->res.y;   
   497 
   498 
   499     //Finger Up
   500     if(event->type == SDL_FINGERUP) {
   501       inTouch->numDownFingers--;
   502       
   503 #ifdef ENABLE_DOLLAR
   504       if(inTouch->recording) {
   505 	inTouch->recording = SDL_FALSE;
   506 	SDL_FloatPoint path[DOLLARNPOINTS];
   507 	dollarNormalize(inTouch->dollarPath,path);
   508 	//SDL_PrintPath(path);
   509 	int index;
   510 	if(recordAll) {
   511 	  index = SDL_AddDollarGesture(NULL,path);
   512 	  int i;
   513 	  for(i = 0;i < SDL_numGestureTouches; i++)
   514 	    SDL_gestureTouch[i].recording = SDL_FALSE;
   515 	}
   516 	else {
   517 	  index = SDL_AddDollarGesture(inTouch,path);
   518 	}
   519 	
   520 	if(index >= 0) {
   521 	  SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash);
   522 	}
   523 	else {
   524 	  SDL_SendDollarRecord(inTouch,-1);
   525 	}
   526       }
   527       else {	
   528 	int bestTempl;
   529 	float error;
   530 	error = dollarRecognize(inTouch->dollarPath,
   531 				&bestTempl,inTouch);
   532 	if(bestTempl >= 0){
   533 	  //Send Event
   534 	  unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash;
   535 	  SDL_SendGestureDollar(inTouch,gestureId,error);
   536 	  //printf ("%s\n",);("Dollar error: %f\n",error);
   537 	}
   538       }
   539 #endif 
   540       //inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers];
   541       if(inTouch->numDownFingers > 0) {
   542 	inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
   543 			       x)/inTouch->numDownFingers;
   544 	inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
   545 			       y)/inTouch->numDownFingers;
   546       }
   547     }
   548     else if(event->type == SDL_FINGERMOTION) {
   549       float dx = ((float)event->tfinger.dx)/(float)inTouch->res.x;
   550       float dy = ((float)event->tfinger.dy)/(float)inTouch->res.y;
   551       //printf("dx,dy: (%f,%f)\n",dx,dy); 
   552 #ifdef ENABLE_DOLLAR
   553       SDL_DollarPath* path = &inTouch->dollarPath;
   554       if(path->numPoints < MAXPATHSIZE) {
   555 	path->p[path->numPoints].x = inTouch->centroid.x;
   556 	path->p[path->numPoints].y = inTouch->centroid.y;
   557 	float pathDx = 
   558 	  (path->p[path->numPoints].x-path->p[path->numPoints-1].x);
   559 	float pathDy = 
   560 	  (path->p[path->numPoints].y-path->p[path->numPoints-1].y);
   561 	path->length += sqrt(pathDx*pathDx + pathDy*pathDy);
   562 	path->numPoints++;
   563       }
   564 #endif
   565       SDL_FloatPoint lastP;
   566       lastP.x = x - dx;
   567       lastP.y = y - dy;
   568       SDL_FloatPoint lastCentroid;
   569       lastCentroid = inTouch->centroid;
   570       
   571       inTouch->centroid.x += dx/inTouch->numDownFingers;
   572       inTouch->centroid.y += dy/inTouch->numDownFingers;
   573       //printf("Centrid : (%f,%f)\n",inTouch->centroid.x,inTouch->centroid.y);
   574       if(inTouch->numDownFingers > 1) {
   575 	SDL_FloatPoint lv; //Vector from centroid to last x,y position
   576 	SDL_FloatPoint v; //Vector from centroid to current x,y position
   577 	//lv = inTouch->gestureLast[j].cv;
   578 	lv.x = lastP.x - lastCentroid.x;
   579 	lv.y = lastP.y - lastCentroid.y;
   580 	float lDist = sqrt(lv.x*lv.x + lv.y*lv.y);
   581 	//printf("lDist = %f\n",lDist);
   582 	v.x = x - inTouch->centroid.x;
   583 	v.y = y - inTouch->centroid.y;
   584 	//inTouch->gestureLast[j].cv = v;
   585 	float Dist = sqrt(v.x*v.x+v.y*v.y);
   586 	// cos(dTheta) = (v . lv)/(|v| * |lv|)
   587 	
   588 	//Normalize Vectors to simplify angle calculation
   589 	lv.x/=lDist;
   590 	lv.y/=lDist;
   591 	v.x/=Dist;
   592 	v.y/=Dist;
   593 	float dtheta = atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
   594 	
   595 	float dDist = (Dist - lDist);
   596 	if(lDist == 0) {dDist = 0;dtheta = 0;} //To avoid impossible values
   597 	
   598 	//inTouch->gestureLast[j].dDist = dDist;
   599 	//inTouch->gestureLast[j].dtheta = dtheta;
   600 	
   601 	//printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
   602 	//gdtheta = gdtheta*.9 + dtheta*.1;
   603 	//gdDist  =  gdDist*.9 +  dDist*.1
   604 	//knob.r += dDist/numDownFingers;
   605 	//knob.ang += dtheta;
   606 	//printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
   607 	//printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist);
   608 	SDL_SendGestureMulti(inTouch,dtheta,dDist);
   609       }
   610       else {
   611 	//inTouch->gestureLast[j].dDist = 0;
   612 	//inTouch->gestureLast[j].dtheta = 0;
   613 	//inTouch->gestureLast[j].cv.x = 0;
   614 	//inTouch->gestureLast[j].cv.y = 0;
   615       }
   616       //inTouch->gestureLast[j].f.p.x = x;
   617       //inTouch->gestureLast[j].f.p.y = y;
   618       //break;
   619       //pressure?
   620     }
   621     
   622     if(event->type == SDL_FINGERDOWN) {
   623 
   624       inTouch->numDownFingers++;
   625       inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+ 
   626 			     x)/inTouch->numDownFingers;
   627       inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+
   628 			     y)/inTouch->numDownFingers;
   629       //printf("Finger Down: (%f,%f). Centroid: (%f,%f\n",x,y,
   630       //     inTouch->centroid.x,inTouch->centroid.y);
   631 
   632 #ifdef ENABLE_DOLLAR
   633       inTouch->dollarPath.length = 0;
   634       inTouch->dollarPath.p[0].x = x;
   635       inTouch->dollarPath.p[0].y = y;
   636       inTouch->dollarPath.numPoints = 1;
   637 #endif
   638     }
   639   }
   640 }
   641 
   642   /* vi: set ts=4 sw=4 expandtab: */
   643