src/events/SDL_gesture.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 31 Oct 2011 05:56:58 -0400
changeset 6044 35448a5ea044
parent 5981 75caa8a7d559
child 6070 69b6275bb5dc
permissions -rw-r--r--
Lots of fixes importing SDL source wholesale into a new iOS project
     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 static 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 static 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 static 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 static 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 static 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 static SDL_GestureTouch * SDL_GetGestureTouch(SDL_TouchID id) {
   435   int i;
   436   for(i = 0;i < SDL_numGestureTouches; i++) {
   437     //printf("%i ?= %i\n",SDL_gestureTouch[i].id,id);
   438     if(SDL_gestureTouch[i].id == id) return &SDL_gestureTouch[i];
   439   }
   440   return NULL;
   441 }
   442 
   443 static int SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist) {
   444   SDL_Event event;
   445   event.mgesture.type = SDL_MULTIGESTURE;
   446   event.mgesture.touchId = touch->id;
   447   event.mgesture.x = touch->centroid.x;
   448   event.mgesture.y = touch->centroid.y;
   449   event.mgesture.dTheta = dTheta;
   450   event.mgesture.dDist = dDist;  
   451   event.mgesture.numFingers = touch->numDownFingers;
   452   return SDL_PushEvent(&event) > 0;
   453 }
   454 
   455 static int SDL_SendGestureDollar(SDL_GestureTouch* touch,
   456                           SDL_GestureID gestureId,float error) {
   457   SDL_Event event;
   458   event.dgesture.type = SDL_DOLLARGESTURE;
   459   event.dgesture.touchId = touch->id;
   460   /*
   461     //TODO: Add this to give location of gesture?
   462   event.mgesture.x = touch->centroid.x;
   463   event.mgesture.y = touch->centroid.y;
   464   */
   465   event.dgesture.gestureId = gestureId;
   466   event.dgesture.error = error;  
   467   //A finger came up to trigger this event.
   468   event.dgesture.numFingers = touch->numDownFingers + 1; 
   469   return SDL_PushEvent(&event) > 0;
   470 }
   471 
   472 
   473 static int SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId) {
   474   SDL_Event event;
   475   event.dgesture.type = SDL_DOLLARRECORD;
   476   event.dgesture.touchId = touch->id;
   477   event.dgesture.gestureId = gestureId;
   478   return SDL_PushEvent(&event) > 0;
   479 }
   480 
   481 
   482 void SDL_GestureProcessEvent(SDL_Event* event)
   483 {
   484   float x,y; 
   485   SDL_FloatPoint path[DOLLARNPOINTS];
   486   int index;
   487   int i;
   488   float pathDx, pathDy;
   489   SDL_FloatPoint lastP;
   490   SDL_FloatPoint lastCentroid;
   491   float lDist;
   492   float Dist;
   493   float dtheta;
   494   float dDist;
   495 
   496   if(event->type == SDL_FINGERMOTION || 
   497      event->type == SDL_FINGERDOWN ||
   498      event->type == SDL_FINGERUP) {
   499     SDL_GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
   500     
   501     //Shouldn't be possible
   502     if(inTouch == NULL) return;
   503     
   504     //printf("@ (%i,%i) with res: (%i,%i)\n",(int)event->tfinger.x,
   505     //           (int)event->tfinger.y,
   506     //   (int)inTouch->res.x,(int)inTouch->res.y);
   507 
   508     
   509     x = ((float)event->tfinger.x)/(float)inTouch->res.x;
   510     y = ((float)event->tfinger.y)/(float)inTouch->res.y;   
   511 
   512 
   513     //Finger Up
   514     if(event->type == SDL_FINGERUP) {
   515       inTouch->numDownFingers--;
   516       
   517 #ifdef ENABLE_DOLLAR
   518       if(inTouch->recording) {
   519         inTouch->recording = SDL_FALSE;        
   520         dollarNormalize(&inTouch->dollarPath,path);
   521         //PrintPath(path);
   522         if(recordAll) {
   523           index = SDL_AddDollarGesture(NULL,path);
   524           for(i = 0;i < SDL_numGestureTouches; i++)
   525             SDL_gestureTouch[i].recording = SDL_FALSE;
   526         }
   527         else {
   528           index = SDL_AddDollarGesture(inTouch,path);
   529         }
   530         
   531         if(index >= 0) {
   532           SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash);
   533         }
   534         else {
   535           SDL_SendDollarRecord(inTouch,-1);
   536         }
   537       }
   538       else {        
   539         int bestTempl;
   540         float error;
   541         error = dollarRecognize(&inTouch->dollarPath,
   542                                 &bestTempl,inTouch);
   543         if(bestTempl >= 0){
   544           //Send Event
   545           unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash;
   546           SDL_SendGestureDollar(inTouch,gestureId,error);
   547           //printf ("%s\n",);("Dollar error: %f\n",error);
   548         }
   549       }
   550 #endif 
   551       //inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers];
   552       if(inTouch->numDownFingers > 0) {
   553         inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
   554                                x)/inTouch->numDownFingers;
   555         inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
   556                                y)/inTouch->numDownFingers;
   557       }
   558     }
   559     else if(event->type == SDL_FINGERMOTION) {
   560       float dx = ((float)event->tfinger.dx)/(float)inTouch->res.x;
   561       float dy = ((float)event->tfinger.dy)/(float)inTouch->res.y;
   562       //printf("dx,dy: (%f,%f)\n",dx,dy); 
   563 #ifdef ENABLE_DOLLAR
   564       SDL_DollarPath* path = &inTouch->dollarPath;
   565       if(path->numPoints < MAXPATHSIZE) {
   566         path->p[path->numPoints].x = inTouch->centroid.x;
   567         path->p[path->numPoints].y = inTouch->centroid.y;
   568         pathDx = 
   569           (path->p[path->numPoints].x-path->p[path->numPoints-1].x);
   570         pathDy = 
   571           (path->p[path->numPoints].y-path->p[path->numPoints-1].y);
   572         path->length += (float)SDL_sqrt(pathDx*pathDx + pathDy*pathDy);
   573         path->numPoints++;
   574       }
   575 #endif
   576       lastP.x = x - dx;
   577       lastP.y = y - dy;
   578       lastCentroid = inTouch->centroid;
   579       
   580       inTouch->centroid.x += dx/inTouch->numDownFingers;
   581       inTouch->centroid.y += dy/inTouch->numDownFingers;
   582       //printf("Centrid : (%f,%f)\n",inTouch->centroid.x,inTouch->centroid.y);
   583       if(inTouch->numDownFingers > 1) {
   584         SDL_FloatPoint lv; //Vector from centroid to last x,y position
   585         SDL_FloatPoint v; //Vector from centroid to current x,y position
   586         //lv = inTouch->gestureLast[j].cv;
   587         lv.x = lastP.x - lastCentroid.x;
   588         lv.y = lastP.y - lastCentroid.y;
   589         lDist = (float)SDL_sqrt(lv.x*lv.x + lv.y*lv.y);
   590         //printf("lDist = %f\n",lDist);
   591         v.x = x - inTouch->centroid.x;
   592         v.y = y - inTouch->centroid.y;
   593         //inTouch->gestureLast[j].cv = v;
   594         Dist = (float)SDL_sqrt(v.x*v.x+v.y*v.y);
   595         // SDL_cos(dTheta) = (v . lv)/(|v| * |lv|)
   596         
   597         //Normalize Vectors to simplify angle calculation
   598         lv.x/=lDist;
   599         lv.y/=lDist;
   600         v.x/=Dist;
   601         v.y/=Dist;
   602         dtheta = (float)SDL_atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
   603         
   604         dDist = (Dist - lDist);
   605         if(lDist == 0) {dDist = 0;dtheta = 0;} //To avoid impossible values
   606         
   607         //inTouch->gestureLast[j].dDist = dDist;
   608         //inTouch->gestureLast[j].dtheta = dtheta;
   609         
   610         //printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
   611         //gdtheta = gdtheta*.9 + dtheta*.1;
   612         //gdDist  =  gdDist*.9 +  dDist*.1
   613         //knob.r += dDist/numDownFingers;
   614         //knob.ang += dtheta;
   615         //printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
   616         //printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist);
   617         SDL_SendGestureMulti(inTouch,dtheta,dDist);
   618       }
   619       else {
   620         //inTouch->gestureLast[j].dDist = 0;
   621         //inTouch->gestureLast[j].dtheta = 0;
   622         //inTouch->gestureLast[j].cv.x = 0;
   623         //inTouch->gestureLast[j].cv.y = 0;
   624       }
   625       //inTouch->gestureLast[j].f.p.x = x;
   626       //inTouch->gestureLast[j].f.p.y = y;
   627       //break;
   628       //pressure?
   629     }
   630     
   631     if(event->type == SDL_FINGERDOWN) {
   632 
   633       inTouch->numDownFingers++;
   634       inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+ 
   635                              x)/inTouch->numDownFingers;
   636       inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+
   637                              y)/inTouch->numDownFingers;
   638       //printf("Finger Down: (%f,%f). Centroid: (%f,%f\n",x,y,
   639       //     inTouch->centroid.x,inTouch->centroid.y);
   640 
   641 #ifdef ENABLE_DOLLAR
   642       inTouch->dollarPath.length = 0;
   643       inTouch->dollarPath.p[0].x = x;
   644       inTouch->dollarPath.p[0].y = y;
   645       inTouch->dollarPath.numPoints = 1;
   646 #endif
   647     }
   648   }
   649 }
   650 
   651   /* vi: set ts=4 sw=4 expandtab: */
   652