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