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