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