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