src/events/SDL_gesture.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 08 Apr 2011 13:03:26 -0700
changeset 5535 96594ac5fd1a
parent 5262 b530ef003506
child 5981 75caa8a7d559
permissions -rw-r--r--
SDL 1.3 is now under the zlib license.
     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 numPoints = dollarNormalize(path,points);
   394         int i;
   395         float bestDiff = 10000;
   396 
   397         //PrintPath(points);
   398         *bestTempl = -1;
   399         for(i = 0;i < touch->numDollarTemplates;i++) {
   400                 float diff = bestDollarDifference(points,touch->dollarTemplate[i].path);
   401                 if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
   402         }
   403         return bestDiff;
   404 }
   405 
   406 int SDL_GestureAddTouch(SDL_Touch* touch) {  
   407   SDL_GestureTouch *gestureTouch = (SDL_GestureTouch *)SDL_realloc(SDL_gestureTouch,
   408                                                (SDL_numGestureTouches + 1) *
   409                                                sizeof(SDL_GestureTouch));
   410 
   411   if(!gestureTouch) {
   412     SDL_OutOfMemory();
   413     return -1;
   414   }
   415 
   416   SDL_gestureTouch = gestureTouch;
   417 
   418   SDL_gestureTouch[SDL_numGestureTouches].res.x = touch->xres;
   419   SDL_gestureTouch[SDL_numGestureTouches].res.y = touch->yres;
   420   SDL_gestureTouch[SDL_numGestureTouches].numDownFingers = 0;
   421 
   422   SDL_gestureTouch[SDL_numGestureTouches].res.x = touch->xres;
   423   SDL_gestureTouch[SDL_numGestureTouches].id = touch->id;
   424 
   425   SDL_gestureTouch[SDL_numGestureTouches].numDollarTemplates = 0;
   426 
   427   SDL_gestureTouch[SDL_numGestureTouches].recording = SDL_FALSE;
   428 
   429   SDL_numGestureTouches++;
   430   return 0;
   431 }
   432 
   433 int SDL_GestureRemoveTouch(SDL_TouchID id) {
   434   int i;
   435   for (i = 0; i < SDL_numGestureTouches; i++) {
   436     if (SDL_gestureTouch[i].id == id) {
   437       SDL_numGestureTouches--;
   438       SDL_memcpy(&SDL_gestureTouch[i], &SDL_gestureTouch[SDL_numGestureTouches], sizeof(SDL_gestureTouch[i]));
   439       return 1;
   440     }
   441   }
   442   return -1;
   443 }
   444 
   445 
   446 SDL_GestureTouch * SDL_GetGestureTouch(SDL_TouchID id) {
   447   int i;
   448   for(i = 0;i < SDL_numGestureTouches; i++) {
   449     //printf("%i ?= %i\n",SDL_gestureTouch[i].id,id);
   450     if(SDL_gestureTouch[i].id == id) return &SDL_gestureTouch[i];
   451   }
   452   return NULL;
   453 }
   454 
   455 int SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist) {
   456   SDL_Event event;
   457   event.mgesture.type = SDL_MULTIGESTURE;
   458   event.mgesture.touchId = touch->id;
   459   event.mgesture.x = touch->centroid.x;
   460   event.mgesture.y = touch->centroid.y;
   461   event.mgesture.dTheta = dTheta;
   462   event.mgesture.dDist = dDist;  
   463   event.mgesture.numFingers = touch->numDownFingers;
   464   return SDL_PushEvent(&event) > 0;
   465 }
   466 
   467 int SDL_SendGestureDollar(SDL_GestureTouch* touch,
   468                           SDL_GestureID gestureId,float error) {
   469   SDL_Event event;
   470   event.dgesture.type = SDL_DOLLARGESTURE;
   471   event.dgesture.touchId = touch->id;
   472   /*
   473     //TODO: Add this to give location of gesture?
   474   event.mgesture.x = touch->centroid.x;
   475   event.mgesture.y = touch->centroid.y;
   476   */
   477   event.dgesture.gestureId = gestureId;
   478   event.dgesture.error = error;  
   479   //A finger came up to trigger this event.
   480   event.dgesture.numFingers = touch->numDownFingers + 1; 
   481   return SDL_PushEvent(&event) > 0;
   482 }
   483 
   484 
   485 int SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId) {
   486   SDL_Event event;
   487   event.dgesture.type = SDL_DOLLARRECORD;
   488   event.dgesture.touchId = touch->id;
   489   event.dgesture.gestureId = gestureId;
   490   return SDL_PushEvent(&event) > 0;
   491 }
   492 
   493 
   494 void SDL_GestureProcessEvent(SDL_Event* event)
   495 {
   496   float x,y; 
   497   SDL_FloatPoint path[DOLLARNPOINTS];
   498   int index;
   499   int i;
   500   float pathDx, pathDy;
   501   SDL_FloatPoint lastP;
   502   SDL_FloatPoint lastCentroid;
   503   float lDist;
   504   float Dist;
   505   float dtheta;
   506   float dDist;
   507 
   508   if(event->type == SDL_FINGERMOTION || 
   509      event->type == SDL_FINGERDOWN ||
   510      event->type == SDL_FINGERUP) {
   511     SDL_GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
   512     
   513     //Shouldn't be possible
   514     if(inTouch == NULL) return;
   515     
   516     //printf("@ (%i,%i) with res: (%i,%i)\n",(int)event->tfinger.x,
   517     //           (int)event->tfinger.y,
   518     //   (int)inTouch->res.x,(int)inTouch->res.y);
   519 
   520     
   521     x = ((float)event->tfinger.x)/(float)inTouch->res.x;
   522     y = ((float)event->tfinger.y)/(float)inTouch->res.y;   
   523 
   524 
   525     //Finger Up
   526     if(event->type == SDL_FINGERUP) {
   527       inTouch->numDownFingers--;
   528       
   529 #ifdef ENABLE_DOLLAR
   530       if(inTouch->recording) {
   531         inTouch->recording = SDL_FALSE;        
   532         dollarNormalize(&inTouch->dollarPath,path);
   533         //PrintPath(path);
   534         if(recordAll) {
   535           index = SDL_AddDollarGesture(NULL,path);
   536           for(i = 0;i < SDL_numGestureTouches; i++)
   537             SDL_gestureTouch[i].recording = SDL_FALSE;
   538         }
   539         else {
   540           index = SDL_AddDollarGesture(inTouch,path);
   541         }
   542         
   543         if(index >= 0) {
   544           SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash);
   545         }
   546         else {
   547           SDL_SendDollarRecord(inTouch,-1);
   548         }
   549       }
   550       else {        
   551         int bestTempl;
   552         float error;
   553         error = dollarRecognize(&inTouch->dollarPath,
   554                                 &bestTempl,inTouch);
   555         if(bestTempl >= 0){
   556           //Send Event
   557           unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash;
   558           SDL_SendGestureDollar(inTouch,gestureId,error);
   559           //printf ("%s\n",);("Dollar error: %f\n",error);
   560         }
   561       }
   562 #endif 
   563       //inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers];
   564       if(inTouch->numDownFingers > 0) {
   565         inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
   566                                x)/inTouch->numDownFingers;
   567         inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
   568                                y)/inTouch->numDownFingers;
   569       }
   570     }
   571     else if(event->type == SDL_FINGERMOTION) {
   572       float dx = ((float)event->tfinger.dx)/(float)inTouch->res.x;
   573       float dy = ((float)event->tfinger.dy)/(float)inTouch->res.y;
   574       //printf("dx,dy: (%f,%f)\n",dx,dy); 
   575 #ifdef ENABLE_DOLLAR
   576       SDL_DollarPath* path = &inTouch->dollarPath;
   577       if(path->numPoints < MAXPATHSIZE) {
   578         path->p[path->numPoints].x = inTouch->centroid.x;
   579         path->p[path->numPoints].y = inTouch->centroid.y;
   580         pathDx = 
   581           (path->p[path->numPoints].x-path->p[path->numPoints-1].x);
   582         pathDy = 
   583           (path->p[path->numPoints].y-path->p[path->numPoints-1].y);
   584         path->length += (float)SDL_sqrt(pathDx*pathDx + pathDy*pathDy);
   585         path->numPoints++;
   586       }
   587 #endif
   588       lastP.x = x - dx;
   589       lastP.y = y - dy;
   590       lastCentroid = inTouch->centroid;
   591       
   592       inTouch->centroid.x += dx/inTouch->numDownFingers;
   593       inTouch->centroid.y += dy/inTouch->numDownFingers;
   594       //printf("Centrid : (%f,%f)\n",inTouch->centroid.x,inTouch->centroid.y);
   595       if(inTouch->numDownFingers > 1) {
   596         SDL_FloatPoint lv; //Vector from centroid to last x,y position
   597         SDL_FloatPoint v; //Vector from centroid to current x,y position
   598         //lv = inTouch->gestureLast[j].cv;
   599         lv.x = lastP.x - lastCentroid.x;
   600         lv.y = lastP.y - lastCentroid.y;
   601         lDist = (float)SDL_sqrt(lv.x*lv.x + lv.y*lv.y);
   602         //printf("lDist = %f\n",lDist);
   603         v.x = x - inTouch->centroid.x;
   604         v.y = y - inTouch->centroid.y;
   605         //inTouch->gestureLast[j].cv = v;
   606         Dist = (float)SDL_sqrt(v.x*v.x+v.y*v.y);
   607         // SDL_cos(dTheta) = (v . lv)/(|v| * |lv|)
   608         
   609         //Normalize Vectors to simplify angle calculation
   610         lv.x/=lDist;
   611         lv.y/=lDist;
   612         v.x/=Dist;
   613         v.y/=Dist;
   614         dtheta = (float)SDL_atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
   615         
   616         dDist = (Dist - lDist);
   617         if(lDist == 0) {dDist = 0;dtheta = 0;} //To avoid impossible values
   618         
   619         //inTouch->gestureLast[j].dDist = dDist;
   620         //inTouch->gestureLast[j].dtheta = dtheta;
   621         
   622         //printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
   623         //gdtheta = gdtheta*.9 + dtheta*.1;
   624         //gdDist  =  gdDist*.9 +  dDist*.1
   625         //knob.r += dDist/numDownFingers;
   626         //knob.ang += dtheta;
   627         //printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
   628         //printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist);
   629         SDL_SendGestureMulti(inTouch,dtheta,dDist);
   630       }
   631       else {
   632         //inTouch->gestureLast[j].dDist = 0;
   633         //inTouch->gestureLast[j].dtheta = 0;
   634         //inTouch->gestureLast[j].cv.x = 0;
   635         //inTouch->gestureLast[j].cv.y = 0;
   636       }
   637       //inTouch->gestureLast[j].f.p.x = x;
   638       //inTouch->gestureLast[j].f.p.y = y;
   639       //break;
   640       //pressure?
   641     }
   642     
   643     if(event->type == SDL_FINGERDOWN) {
   644 
   645       inTouch->numDownFingers++;
   646       inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+ 
   647                              x)/inTouch->numDownFingers;
   648       inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+
   649                              y)/inTouch->numDownFingers;
   650       //printf("Finger Down: (%f,%f). Centroid: (%f,%f\n",x,y,
   651       //     inTouch->centroid.x,inTouch->centroid.y);
   652 
   653 #ifdef ENABLE_DOLLAR
   654       inTouch->dollarPath.length = 0;
   655       inTouch->dollarPath.p[0].x = x;
   656       inTouch->dollarPath.p[0].y = y;
   657       inTouch->dollarPath.numPoints = 1;
   658 #endif
   659     }
   660   }
   661 }
   662 
   663   /* vi: set ts=4 sw=4 expandtab: */
   664