src/events/SDL_gesture.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 08 Nov 2011 19:45:41 -0500
changeset 6071 72f06ae88e7e
parent 6070 69b6275bb5dc
child 6138 4c64952a58fb
permissions -rw-r--r--
Fixed uninitialized variable.
     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 static 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 = -1;
   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 static 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 static 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 static 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 static 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 static SDL_GestureTouch * SDL_GetGestureTouch(SDL_TouchID id)
   442 {
   443     int i;
   444     for (i = 0; i < SDL_numGestureTouches; i++) {
   445         //printf("%i ?= %i\n",SDL_gestureTouch[i].id,id);
   446         if (SDL_gestureTouch[i].id == id)
   447             return &SDL_gestureTouch[i];
   448     }
   449     return NULL;
   450 }
   451 
   452 int SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist)
   453 {
   454     SDL_Event event;
   455     event.mgesture.type = SDL_MULTIGESTURE;
   456     event.mgesture.touchId = touch->id;
   457     event.mgesture.x = touch->centroid.x;
   458     event.mgesture.y = touch->centroid.y;
   459     event.mgesture.dTheta = dTheta;
   460     event.mgesture.dDist = dDist;
   461     event.mgesture.numFingers = touch->numDownFingers;
   462     return SDL_PushEvent(&event) > 0;
   463 }
   464 
   465 static int SDL_SendGestureDollar(SDL_GestureTouch* touch,
   466                           SDL_GestureID gestureId,float error)
   467 {
   468     SDL_Event event;
   469     event.dgesture.type = SDL_DOLLARGESTURE;
   470     event.dgesture.touchId = touch->id;
   471     /*
   472     //TODO: Add this to give location of gesture?
   473     event.mgesture.x = touch->centroid.x;
   474     event.mgesture.y = touch->centroid.y;
   475     */
   476     event.dgesture.gestureId = gestureId;
   477     event.dgesture.error = error;
   478     //A finger came up to trigger this event.
   479     event.dgesture.numFingers = touch->numDownFingers + 1;
   480     return SDL_PushEvent(&event) > 0;
   481 }
   482 
   483 
   484 static int SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId)
   485 {
   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: */