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