src/events/SDL_gesture.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 17 Apr 2014 19:52:15 -0700
changeset 8705 fee2f7e242a1
parent 8296 cb13016bf07b
child 8726 9a5a5808aa14
permissions -rw-r--r--
Fixed bug 2503 - Loop indexing and event union errors in SDL_gesture.c

Lasse Öörni

While enabling $1 gesture support in the Urho3D engine which uses SDL2 I detected some errors in the gesture code in SDL_gesture.c:

- In the function SDL_SaveAllDollarTemplates() the following line should use index variable j instead of i:

rtrn += SaveTemplate(&touch->dollarTemplate[i], dst);

- In the function SDL_SaveDollarTemplate() the following code should use index variable j instead of i:

if (touch->dollarTemplate[i].hash == gestureId) {
return SaveTemplate(&touch->dollarTemplate[i], dst);

- In the function SDL_SendGestureDollar() the x & y coordinates are being written to the mgesture structure, which results in garbage due to dgesture and mgesture being different data structures inside the union. The coordinates should be written to dgesture.x & dgesture.y respectively
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_internal.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 #if !defined(__PSP__)
    31 #include <memory.h>
    32 #endif
    33 
    34 #include <string.h>
    35 #include <stdio.h>
    36 #include <math.h>
    37 
    38 /* TODO: Replace with malloc */
    39 
    40 #define MAXPATHSIZE 1024
    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 centroid;
    68     SDL_DollarPath dollarPath;
    69     Uint16 numDownFingers;
    70 
    71     int numDollarTemplates;
    72     SDL_DollarTemplate *dollarTemplate;
    73 
    74     SDL_bool recording;
    75 } SDL_GestureTouch;
    76 
    77 SDL_GestureTouch *SDL_gestureTouch;
    78 int SDL_numGestureTouches = 0;
    79 SDL_bool recordAll;
    80 
    81 #if 0
    82 static void PrintPath(SDL_FloatPoint *path)
    83 {
    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 {
    95     int i;
    96     if (touchId < 0) recordAll = SDL_TRUE;
    97     for (i = 0; i < SDL_numGestureTouches; i++) {
    98         if ((touchId < 0) || (SDL_gestureTouch[i].id == touchId)) {
    99             SDL_gestureTouch[i].recording = SDL_TRUE;
   100             if (touchId >= 0)
   101                 return 1;
   102         }
   103     }
   104     return (touchId < 0);
   105 }
   106 
   107 static unsigned long SDL_HashDollar(SDL_FloatPoint* points)
   108 {
   109     unsigned long hash = 5381;
   110     int i;
   111     for (i = 0; i < DOLLARNPOINTS; i++) {
   112         hash = ((hash<<5) + hash) + (unsigned long)points[i].x;
   113         hash = ((hash<<5) + hash) + (unsigned long)points[i].y;
   114     }
   115     return hash;
   116 }
   117 
   118 
   119 static int SaveTemplate(SDL_DollarTemplate *templ, SDL_RWops *dst)
   120 {
   121     if (dst == NULL) return 0;
   122 
   123     /* No Longer storing the Hash, rehash on load */
   124     /* if (SDL_RWops.write(dst, &(templ->hash), sizeof(templ->hash), 1) != 1) return 0; */
   125 
   126     if (SDL_RWwrite(dst, templ->path,
   127                     sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS)
   128         return 0;
   129 
   130     return 1;
   131 }
   132 
   133 
   134 int SDL_SaveAllDollarTemplates(SDL_RWops *dst)
   135 {
   136     int i,j,rtrn = 0;
   137     for (i = 0; i < SDL_numGestureTouches; i++) {
   138         SDL_GestureTouch* touch = &SDL_gestureTouch[i];
   139         for (j = 0; j < touch->numDollarTemplates; j++) {
   140             rtrn += SaveTemplate(&touch->dollarTemplate[j], dst);
   141         }
   142     }
   143     return rtrn;
   144 }
   145 
   146 int SDL_SaveDollarTemplate(SDL_GestureID gestureId, SDL_RWops *dst)
   147 {
   148     int i,j;
   149     for (i = 0; i < SDL_numGestureTouches; i++) {
   150         SDL_GestureTouch* touch = &SDL_gestureTouch[i];
   151         for (j = 0; j < touch->numDollarTemplates; j++) {
   152             if (touch->dollarTemplate[i].hash == gestureId) {
   153                 return SaveTemplate(&touch->dollarTemplate[j], dst);
   154             }
   155         }
   156     }
   157     return SDL_SetError("Unknown gestureId");
   158 }
   159 
   160 /* path is an already sampled set of points
   161 Returns the index of the gesture on success, or -1 */
   162 static int SDL_AddDollarGesture_one(SDL_GestureTouch* inTouch, SDL_FloatPoint* path)
   163 {
   164     SDL_DollarTemplate* dollarTemplate;
   165     SDL_DollarTemplate *templ;
   166     int index;
   167 
   168     index = inTouch->numDollarTemplates;
   169     dollarTemplate =
   170         (SDL_DollarTemplate *)SDL_realloc(inTouch->dollarTemplate,
   171                                           (index + 1) *
   172                                           sizeof(SDL_DollarTemplate));
   173     if (!dollarTemplate) {
   174         return SDL_OutOfMemory();
   175     }
   176     inTouch->dollarTemplate = dollarTemplate;
   177 
   178     templ = &inTouch->dollarTemplate[index];
   179     SDL_memcpy(templ->path, path, DOLLARNPOINTS*sizeof(SDL_FloatPoint));
   180     templ->hash = SDL_HashDollar(templ->path);
   181     inTouch->numDollarTemplates++;
   182 
   183     return index;
   184 }
   185 
   186 static int SDL_AddDollarGesture(SDL_GestureTouch* inTouch, SDL_FloatPoint* path)
   187 {
   188     int index = -1;
   189     int i = 0;
   190     if (inTouch == NULL) {
   191         if (SDL_numGestureTouches == 0) return -1;
   192         for (i = 0; i < SDL_numGestureTouches; i++) {
   193             inTouch = &SDL_gestureTouch[i];
   194             index = SDL_AddDollarGesture_one(inTouch, path);
   195             if (index < 0)
   196                 return -1;
   197         }
   198         /* Use the index of the last one added. */
   199         return index;
   200     }
   201     return SDL_AddDollarGesture_one(inTouch, path);
   202 }
   203 
   204 int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src)
   205 {
   206     int i,loaded = 0;
   207     SDL_GestureTouch *touch = NULL;
   208     if (src == NULL) return 0;
   209     if (touchId >= 0) {
   210         for (i = 0; i < SDL_numGestureTouches; i++)
   211             if (SDL_gestureTouch[i].id == touchId)
   212                 touch = &SDL_gestureTouch[i];
   213         if (touch == NULL) return -1;
   214     }
   215 
   216     while (1) {
   217         SDL_DollarTemplate templ;
   218 
   219         if (SDL_RWread(src,templ.path,sizeof(templ.path[0]),DOLLARNPOINTS) <
   220            DOLLARNPOINTS) break;
   221 
   222         if (touchId >= 0) {
   223             /* printf("Adding loaded gesture to 1 touch\n"); */
   224             if (SDL_AddDollarGesture(touch, templ.path) >= 0)
   225                 loaded++;
   226         }
   227         else {
   228             /* printf("Adding to: %i touches\n",SDL_numGestureTouches); */
   229             for (i = 0; i < SDL_numGestureTouches; i++) {
   230                 touch = &SDL_gestureTouch[i];
   231                 /* printf("Adding loaded gesture to + touches\n"); */
   232                 /* TODO: What if this fails? */
   233                 SDL_AddDollarGesture(touch,templ.path);
   234             }
   235             loaded++;
   236         }
   237     }
   238 
   239     return loaded;
   240 }
   241 
   242 
   243 static float dollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ,float ang)
   244 {
   245     /*  SDL_FloatPoint p[DOLLARNPOINTS]; */
   246     float dist = 0;
   247     SDL_FloatPoint p;
   248     int i;
   249     for (i = 0; i < DOLLARNPOINTS; i++) {
   250         p.x = (float)(points[i].x * SDL_cos(ang) - points[i].y * SDL_sin(ang));
   251         p.y = (float)(points[i].x * SDL_sin(ang) + points[i].y * SDL_cos(ang));
   252         dist += (float)(SDL_sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
   253                                  (p.y-templ[i].y)*(p.y-templ[i].y)));
   254     }
   255     return dist/DOLLARNPOINTS;
   256 
   257 }
   258 
   259 static float bestDollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ)
   260 {
   261     /*------------BEGIN DOLLAR BLACKBOX------------------
   262       -TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-
   263       -"http://depts.washington.edu/aimgroup/proj/dollar/"
   264     */
   265     double ta = -M_PI/4;
   266     double tb = M_PI/4;
   267     double dt = M_PI/90;
   268     float x1 = (float)(PHI*ta + (1-PHI)*tb);
   269     float f1 = dollarDifference(points,templ,x1);
   270     float x2 = (float)((1-PHI)*ta + PHI*tb);
   271     float f2 = dollarDifference(points,templ,x2);
   272     while (SDL_fabs(ta-tb) > dt) {
   273         if (f1 < f2) {
   274             tb = x2;
   275             x2 = x1;
   276             f2 = f1;
   277             x1 = (float)(PHI*ta + (1-PHI)*tb);
   278             f1 = dollarDifference(points,templ,x1);
   279         }
   280         else {
   281             ta = x1;
   282             x1 = x2;
   283             f1 = f2;
   284             x2 = (float)((1-PHI)*ta + PHI*tb);
   285             f2 = dollarDifference(points,templ,x2);
   286         }
   287     }
   288     /*
   289       if (f1 <= f2)
   290           printf("Min angle (x1): %f\n",x1);
   291       else if (f1 >  f2)
   292           printf("Min angle (x2): %f\n",x2);
   293     */
   294     return SDL_min(f1,f2);
   295 }
   296 
   297 /* DollarPath contains raw points, plus (possibly) the calculated length */
   298 static int dollarNormalize(const SDL_DollarPath *path,SDL_FloatPoint *points)
   299 {
   300     int i;
   301     float interval;
   302     float dist;
   303     int numPoints = 0;
   304     SDL_FloatPoint centroid;
   305     float xmin,xmax,ymin,ymax;
   306     float ang;
   307     float w,h;
   308     float length = path->length;
   309 
   310     /* Calculate length if it hasn't already been done */
   311     if (length <= 0) {
   312         for (i=1;i < path->numPoints; i++) {
   313             float dx = path->p[i  ].x - path->p[i-1].x;
   314             float dy = path->p[i  ].y - 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     SDL_memset(points, 0, sizeof(points));
   397 
   398     dollarNormalize(path,points);
   399 
   400     /* PrintPath(points); */
   401     *bestTempl = -1;
   402     for (i = 0; i < touch->numDollarTemplates; i++) {
   403         float diff = bestDollarDifference(points,touch->dollarTemplate[i].path);
   404         if (diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
   405     }
   406     return bestDiff;
   407 }
   408 
   409 int SDL_GestureAddTouch(SDL_TouchID touchId)
   410 {
   411     SDL_GestureTouch *gestureTouch = (SDL_GestureTouch *)SDL_realloc(SDL_gestureTouch,
   412                                                                      (SDL_numGestureTouches + 1) *
   413                                                                      sizeof(SDL_GestureTouch));
   414 
   415     if (!gestureTouch) {
   416         return SDL_OutOfMemory();
   417     }
   418 
   419     SDL_gestureTouch = gestureTouch;
   420 
   421     SDL_zero(SDL_gestureTouch[SDL_numGestureTouches]);
   422     SDL_gestureTouch[SDL_numGestureTouches].id = touchId;
   423     SDL_numGestureTouches++;
   424     return 0;
   425 }
   426 
   427 static SDL_GestureTouch * SDL_GetGestureTouch(SDL_TouchID id)
   428 {
   429     int i;
   430     for (i = 0; i < SDL_numGestureTouches; i++) {
   431         /* printf("%i ?= %i\n",SDL_gestureTouch[i].id,id); */
   432         if (SDL_gestureTouch[i].id == id)
   433             return &SDL_gestureTouch[i];
   434     }
   435     return NULL;
   436 }
   437 
   438 int SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist)
   439 {
   440     SDL_Event event;
   441     event.mgesture.type = SDL_MULTIGESTURE;
   442     event.mgesture.touchId = touch->id;
   443     event.mgesture.x = touch->centroid.x;
   444     event.mgesture.y = touch->centroid.y;
   445     event.mgesture.dTheta = dTheta;
   446     event.mgesture.dDist = dDist;
   447     event.mgesture.numFingers = touch->numDownFingers;
   448     return SDL_PushEvent(&event) > 0;
   449 }
   450 
   451 static int SDL_SendGestureDollar(SDL_GestureTouch* touch,
   452                           SDL_GestureID gestureId,float error)
   453 {
   454     SDL_Event event;
   455     event.dgesture.type = SDL_DOLLARGESTURE;
   456     event.dgesture.touchId = touch->id;
   457     event.dgesture.x = touch->centroid.x;
   458     event.dgesture.y = touch->centroid.y;
   459     event.dgesture.gestureId = gestureId;
   460     event.dgesture.error = error;
   461     /* A finger came up to trigger this event. */
   462     event.dgesture.numFingers = touch->numDownFingers + 1;
   463     return SDL_PushEvent(&event) > 0;
   464 }
   465 
   466 
   467 static int SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId)
   468 {
   469     SDL_Event event;
   470     event.dgesture.type = SDL_DOLLARRECORD;
   471     event.dgesture.touchId = touch->id;
   472     event.dgesture.gestureId = gestureId;
   473     return SDL_PushEvent(&event) > 0;
   474 }
   475 
   476 
   477 void SDL_GestureProcessEvent(SDL_Event* event)
   478 {
   479     float x,y;
   480     SDL_FloatPoint path[DOLLARNPOINTS];
   481     int index;
   482     int i;
   483     float pathDx, pathDy;
   484     SDL_FloatPoint lastP;
   485     SDL_FloatPoint lastCentroid;
   486     float lDist;
   487     float Dist;
   488     float dtheta;
   489     float dDist;
   490 
   491     if (event->type == SDL_FINGERMOTION ||
   492         event->type == SDL_FINGERDOWN ||
   493         event->type == SDL_FINGERUP) {
   494         SDL_GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
   495 
   496         /* Shouldn't be possible */
   497         if (inTouch == NULL) return;
   498 
   499         x = event->tfinger.x;
   500         y = event->tfinger.y;
   501 
   502         /* Finger Up */
   503         if (event->type == SDL_FINGERUP) {
   504             inTouch->numDownFingers--;
   505 
   506 #ifdef ENABLE_DOLLAR
   507             if (inTouch->recording) {
   508                 inTouch->recording = SDL_FALSE;
   509                 dollarNormalize(&inTouch->dollarPath,path);
   510                 /* PrintPath(path); */
   511                 if (recordAll) {
   512                     index = SDL_AddDollarGesture(NULL,path);
   513                     for (i = 0; i < SDL_numGestureTouches; i++)
   514                         SDL_gestureTouch[i].recording = SDL_FALSE;
   515                 }
   516                 else {
   517                     index = SDL_AddDollarGesture(inTouch,path);
   518                 }
   519 
   520                 if (index >= 0) {
   521                     SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash);
   522                 }
   523                 else {
   524                     SDL_SendDollarRecord(inTouch,-1);
   525                 }
   526             }
   527             else {
   528                 int bestTempl;
   529                 float error;
   530                 error = dollarRecognize(&inTouch->dollarPath,
   531                                         &bestTempl,inTouch);
   532                 if (bestTempl >= 0){
   533                     /* Send Event */
   534                     unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash;
   535                     SDL_SendGestureDollar(inTouch,gestureId,error);
   536                     /* printf ("%s\n",);("Dollar error: %f\n",error); */
   537                 }
   538             }
   539 #endif
   540             /* inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers]; */
   541             if (inTouch->numDownFingers > 0) {
   542                 inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
   543                                        x)/inTouch->numDownFingers;
   544                 inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
   545                                        y)/inTouch->numDownFingers;
   546             }
   547         }
   548         else if (event->type == SDL_FINGERMOTION) {
   549             float dx = event->tfinger.dx;
   550             float dy = event->tfinger.dy;
   551 #ifdef ENABLE_DOLLAR
   552             SDL_DollarPath* path = &inTouch->dollarPath;
   553             if (path->numPoints < MAXPATHSIZE) {
   554                 path->p[path->numPoints].x = inTouch->centroid.x;
   555                 path->p[path->numPoints].y = inTouch->centroid.y;
   556                 pathDx =
   557                     (path->p[path->numPoints].x-path->p[path->numPoints-1].x);
   558                 pathDy =
   559                     (path->p[path->numPoints].y-path->p[path->numPoints-1].y);
   560                 path->length += (float)SDL_sqrt(pathDx*pathDx + pathDy*pathDy);
   561                 path->numPoints++;
   562             }
   563 #endif
   564             lastP.x = x - dx;
   565             lastP.y = y - dy;
   566             lastCentroid = inTouch->centroid;
   567 
   568             inTouch->centroid.x += dx/inTouch->numDownFingers;
   569             inTouch->centroid.y += dy/inTouch->numDownFingers;
   570             /* printf("Centrid : (%f,%f)\n",inTouch->centroid.x,inTouch->centroid.y); */
   571             if (inTouch->numDownFingers > 1) {
   572                 SDL_FloatPoint lv; /* Vector from centroid to last x,y position */
   573                 SDL_FloatPoint v; /* Vector from centroid to current x,y position */
   574                 /* lv = inTouch->gestureLast[j].cv; */
   575                 lv.x = lastP.x - lastCentroid.x;
   576                 lv.y = lastP.y - lastCentroid.y;
   577                 lDist = (float)SDL_sqrt(lv.x*lv.x + lv.y*lv.y);
   578                 /* printf("lDist = %f\n",lDist); */
   579                 v.x = x - inTouch->centroid.x;
   580                 v.y = y - inTouch->centroid.y;
   581                 /* inTouch->gestureLast[j].cv = v; */
   582                 Dist = (float)SDL_sqrt(v.x*v.x+v.y*v.y);
   583                 /* SDL_cos(dTheta) = (v . lv)/(|v| * |lv|) */
   584 
   585                 /* Normalize Vectors to simplify angle calculation */
   586                 lv.x/=lDist;
   587                 lv.y/=lDist;
   588                 v.x/=Dist;
   589                 v.y/=Dist;
   590                 dtheta = (float)SDL_atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
   591 
   592                 dDist = (Dist - lDist);
   593                 if (lDist == 0) {dDist = 0;dtheta = 0;} /* To avoid impossible values */
   594 
   595                 /* inTouch->gestureLast[j].dDist = dDist;
   596                 inTouch->gestureLast[j].dtheta = dtheta;
   597 
   598                 printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
   599                 gdtheta = gdtheta*.9 + dtheta*.1;
   600                 gdDist  =  gdDist*.9 +  dDist*.1
   601                 knob.r += dDist/numDownFingers;
   602                 knob.ang += dtheta;
   603                 printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
   604                 printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist); */
   605                 SDL_SendGestureMulti(inTouch,dtheta,dDist);
   606             }
   607             else {
   608                 /* inTouch->gestureLast[j].dDist = 0;
   609                 inTouch->gestureLast[j].dtheta = 0;
   610                 inTouch->gestureLast[j].cv.x = 0;
   611                 inTouch->gestureLast[j].cv.y = 0; */
   612             }
   613             /* inTouch->gestureLast[j].f.p.x = x;
   614             inTouch->gestureLast[j].f.p.y = y;
   615             break;
   616             pressure? */
   617         }
   618 
   619         if (event->type == SDL_FINGERDOWN) {
   620 
   621             inTouch->numDownFingers++;
   622             inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+
   623                                    x)/inTouch->numDownFingers;
   624             inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+
   625                                    y)/inTouch->numDownFingers;
   626             /* printf("Finger Down: (%f,%f). Centroid: (%f,%f\n",x,y,
   627                  inTouch->centroid.x,inTouch->centroid.y); */
   628 
   629 #ifdef ENABLE_DOLLAR
   630             inTouch->dollarPath.length = 0;
   631             inTouch->dollarPath.p[0].x = x;
   632             inTouch->dollarPath.p[0].y = y;
   633             inTouch->dollarPath.numPoints = 1;
   634 #endif
   635         }
   636     }
   637 }
   638 
   639 /* vi: set ts=4 sw=4 expandtab: */