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