src/events/SDL_gesture.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 03 Jan 2018 10:03:25 -0800
changeset 11811 5d94cb6b24d3
parent 11293 2759ce803a47
child 12479 f2c510ee0f2a
permissions -rw-r--r--
Updated copyright for 2018
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 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 gesture handling code for SDL */
    25 
    26 #include "SDL_events.h"
    27 #include "SDL_endian.h"
    28 #include "SDL_events_c.h"
    29 #include "SDL_gesture_c.h"
    30 
    31 /*
    32 #include <stdio.h>
    33 */
    34 
    35 /* TODO: Replace with malloc */
    36 
    37 #define MAXPATHSIZE 1024
    38 
    39 #define DOLLARNPOINTS 64
    40 #define DOLLARSIZE 256
    41 
    42 #define ENABLE_DOLLAR
    43 
    44 #define PHI 0.618033989
    45 
    46 typedef struct {
    47     float x,y;
    48 } SDL_FloatPoint;
    49 
    50 typedef struct {
    51     float length;
    52 
    53     int numPoints;
    54     SDL_FloatPoint p[MAXPATHSIZE];
    55 } SDL_DollarPath;
    56 
    57 typedef struct {
    58     SDL_FloatPoint path[DOLLARNPOINTS];
    59     unsigned long hash;
    60 } SDL_DollarTemplate;
    61 
    62 typedef struct {
    63     SDL_TouchID id;
    64     SDL_FloatPoint centroid;
    65     SDL_DollarPath dollarPath;
    66     Uint16 numDownFingers;
    67 
    68     int numDollarTemplates;
    69     SDL_DollarTemplate *dollarTemplate;
    70 
    71     SDL_bool recording;
    72 } SDL_GestureTouch;
    73 
    74 static SDL_GestureTouch *SDL_gestureTouch;
    75 static int SDL_numGestureTouches = 0;
    76 static SDL_bool recordAll;
    77 
    78 #if 0
    79 static void PrintPath(SDL_FloatPoint *path)
    80 {
    81     int i;
    82     printf("Path:");
    83     for (i=0; i<DOLLARNPOINTS; i++) {
    84         printf(" (%f,%f)",path[i].x,path[i].y);
    85     }
    86     printf("\n");
    87 }
    88 #endif
    89 
    90 int SDL_RecordGesture(SDL_TouchID touchId)
    91 {
    92     int i;
    93     if (touchId < 0) recordAll = SDL_TRUE;
    94     for (i = 0; i < SDL_numGestureTouches; i++) {
    95         if ((touchId < 0) || (SDL_gestureTouch[i].id == touchId)) {
    96             SDL_gestureTouch[i].recording = SDL_TRUE;
    97             if (touchId >= 0)
    98                 return 1;
    99         }
   100     }
   101     return (touchId < 0);
   102 }
   103 
   104 void SDL_GestureQuit()
   105 {
   106     SDL_free(SDL_gestureTouch);
   107     SDL_gestureTouch = NULL;
   108 }
   109 
   110 static unsigned long SDL_HashDollar(SDL_FloatPoint* points)
   111 {
   112     unsigned long hash = 5381;
   113     int i;
   114     for (i = 0; i < DOLLARNPOINTS; i++) {
   115         hash = ((hash<<5) + hash) + (unsigned long)points[i].x;
   116         hash = ((hash<<5) + hash) + (unsigned long)points[i].y;
   117     }
   118     return hash;
   119 }
   120 
   121 
   122 static int SaveTemplate(SDL_DollarTemplate *templ, SDL_RWops *dst)
   123 {
   124     if (dst == NULL) {
   125         return 0;
   126     }
   127 
   128     /* No Longer storing the Hash, rehash on load */
   129     /* if (SDL_RWops.write(dst, &(templ->hash), sizeof(templ->hash), 1) != 1) return 0; */
   130 
   131 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   132     if (SDL_RWwrite(dst, templ->path,
   133                     sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) {
   134         return 0;
   135     }
   136 #else
   137     {
   138         SDL_DollarTemplate copy = *templ;
   139         SDL_FloatPoint *p = copy.path;
   140         int i;
   141         for (i = 0; i < DOLLARNPOINTS; i++, p++) {
   142             p->x = SDL_SwapFloatLE(p->x);
   143             p->y = SDL_SwapFloatLE(p->y);
   144         }
   145 
   146         if (SDL_RWwrite(dst, copy.path,
   147                         sizeof(copy.path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) {
   148             return 0;
   149         }
   150     }
   151 #endif
   152 
   153     return 1;
   154 }
   155 
   156 
   157 int SDL_SaveAllDollarTemplates(SDL_RWops *dst)
   158 {
   159     int i,j,rtrn = 0;
   160     for (i = 0; i < SDL_numGestureTouches; i++) {
   161         SDL_GestureTouch* touch = &SDL_gestureTouch[i];
   162         for (j = 0; j < touch->numDollarTemplates; j++) {
   163             rtrn += SaveTemplate(&touch->dollarTemplate[j], dst);
   164         }
   165     }
   166     return rtrn;
   167 }
   168 
   169 int SDL_SaveDollarTemplate(SDL_GestureID gestureId, SDL_RWops *dst)
   170 {
   171     int i,j;
   172     for (i = 0; i < SDL_numGestureTouches; i++) {
   173         SDL_GestureTouch* touch = &SDL_gestureTouch[i];
   174         for (j = 0; j < touch->numDollarTemplates; j++) {
   175             if (touch->dollarTemplate[j].hash == gestureId) {
   176                 return SaveTemplate(&touch->dollarTemplate[j], dst);
   177             }
   178         }
   179     }
   180     return SDL_SetError("Unknown gestureId");
   181 }
   182 
   183 /* path is an already sampled set of points
   184 Returns the index of the gesture on success, or -1 */
   185 static int SDL_AddDollarGesture_one(SDL_GestureTouch* inTouch, SDL_FloatPoint* path)
   186 {
   187     SDL_DollarTemplate* dollarTemplate;
   188     SDL_DollarTemplate *templ;
   189     int index;
   190 
   191     index = inTouch->numDollarTemplates;
   192     dollarTemplate =
   193         (SDL_DollarTemplate *)SDL_realloc(inTouch->dollarTemplate,
   194                                           (index + 1) *
   195                                           sizeof(SDL_DollarTemplate));
   196     if (!dollarTemplate) {
   197         return SDL_OutOfMemory();
   198     }
   199     inTouch->dollarTemplate = dollarTemplate;
   200 
   201     templ = &inTouch->dollarTemplate[index];
   202     SDL_memcpy(templ->path, path, DOLLARNPOINTS*sizeof(SDL_FloatPoint));
   203     templ->hash = SDL_HashDollar(templ->path);
   204     inTouch->numDollarTemplates++;
   205 
   206     return index;
   207 }
   208 
   209 static int SDL_AddDollarGesture(SDL_GestureTouch* inTouch, SDL_FloatPoint* path)
   210 {
   211     int index = -1;
   212     int i = 0;
   213     if (inTouch == NULL) {
   214         if (SDL_numGestureTouches == 0) return SDL_SetError("no gesture touch devices registered");
   215         for (i = 0; i < SDL_numGestureTouches; i++) {
   216             inTouch = &SDL_gestureTouch[i];
   217             index = SDL_AddDollarGesture_one(inTouch, path);
   218             if (index < 0)
   219                 return -1;
   220         }
   221         /* Use the index of the last one added. */
   222         return index;
   223     }
   224     return SDL_AddDollarGesture_one(inTouch, path);
   225 }
   226 
   227 int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src)
   228 {
   229     int i,loaded = 0;
   230     SDL_GestureTouch *touch = NULL;
   231     if (src == NULL) return 0;
   232     if (touchId >= 0) {
   233         for (i = 0; i < SDL_numGestureTouches; i++) {
   234             if (SDL_gestureTouch[i].id == touchId) {
   235                 touch = &SDL_gestureTouch[i];
   236             }
   237         }
   238         if (touch == NULL) {
   239             return SDL_SetError("given touch id not found");
   240         }
   241     }
   242 
   243     while (1) {
   244         SDL_DollarTemplate templ;
   245 
   246         if (SDL_RWread(src,templ.path,sizeof(templ.path[0]),DOLLARNPOINTS) < DOLLARNPOINTS) {
   247             if (loaded == 0) {
   248                 return SDL_SetError("could not read any dollar gesture from rwops");
   249             }
   250             break;
   251         }
   252 
   253 #if SDL_BYTEORDER != SDL_LIL_ENDIAN
   254         for (i = 0; i < DOLLARNPOINTS; i++) {
   255             SDL_FloatPoint *p = &templ.path[i];
   256             p->x = SDL_SwapFloatLE(p->x);
   257             p->y = SDL_SwapFloatLE(p->y);
   258         }
   259 #endif
   260 
   261         if (touchId >= 0) {
   262             /* printf("Adding loaded gesture to 1 touch\n"); */
   263             if (SDL_AddDollarGesture(touch, templ.path) >= 0)
   264                 loaded++;
   265         }
   266         else {
   267             /* printf("Adding to: %i touches\n",SDL_numGestureTouches); */
   268             for (i = 0; i < SDL_numGestureTouches; i++) {
   269                 touch = &SDL_gestureTouch[i];
   270                 /* printf("Adding loaded gesture to + touches\n"); */
   271                 /* TODO: What if this fails? */
   272                 SDL_AddDollarGesture(touch,templ.path);
   273             }
   274             loaded++;
   275         }
   276     }
   277 
   278     return loaded;
   279 }
   280 
   281 
   282 static float dollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ,float ang)
   283 {
   284     /*  SDL_FloatPoint p[DOLLARNPOINTS]; */
   285     float dist = 0;
   286     SDL_FloatPoint p;
   287     int i;
   288     for (i = 0; i < DOLLARNPOINTS; i++) {
   289         p.x = (float)(points[i].x * SDL_cos(ang) - points[i].y * SDL_sin(ang));
   290         p.y = (float)(points[i].x * SDL_sin(ang) + points[i].y * SDL_cos(ang));
   291         dist += (float)(SDL_sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
   292                                  (p.y-templ[i].y)*(p.y-templ[i].y)));
   293     }
   294     return dist/DOLLARNPOINTS;
   295 
   296 }
   297 
   298 static float bestDollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ)
   299 {
   300     /*------------BEGIN DOLLAR BLACKBOX------------------
   301       -TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-
   302       -"http://depts.washington.edu/aimgroup/proj/dollar/"
   303     */
   304     double ta = -M_PI/4;
   305     double tb = M_PI/4;
   306     double dt = M_PI/90;
   307     float x1 = (float)(PHI*ta + (1-PHI)*tb);
   308     float f1 = dollarDifference(points,templ,x1);
   309     float x2 = (float)((1-PHI)*ta + PHI*tb);
   310     float f2 = dollarDifference(points,templ,x2);
   311     while (SDL_fabs(ta-tb) > dt) {
   312         if (f1 < f2) {
   313             tb = x2;
   314             x2 = x1;
   315             f2 = f1;
   316             x1 = (float)(PHI*ta + (1-PHI)*tb);
   317             f1 = dollarDifference(points,templ,x1);
   318         }
   319         else {
   320             ta = x1;
   321             x1 = x2;
   322             f1 = f2;
   323             x2 = (float)((1-PHI)*ta + PHI*tb);
   324             f2 = dollarDifference(points,templ,x2);
   325         }
   326     }
   327     /*
   328       if (f1 <= f2)
   329           printf("Min angle (x1): %f\n",x1);
   330       else if (f1 >  f2)
   331           printf("Min angle (x2): %f\n",x2);
   332     */
   333     return SDL_min(f1,f2);
   334 }
   335 
   336 /* DollarPath contains raw points, plus (possibly) the calculated length */
   337 static int dollarNormalize(const SDL_DollarPath *path,SDL_FloatPoint *points)
   338 {
   339     int i;
   340     float interval;
   341     float dist;
   342     int numPoints = 0;
   343     SDL_FloatPoint centroid;
   344     float xmin,xmax,ymin,ymax;
   345     float ang;
   346     float w,h;
   347     float length = path->length;
   348 
   349     /* Calculate length if it hasn't already been done */
   350     if (length <= 0) {
   351         for (i=1;i < path->numPoints; i++) {
   352             float dx = path->p[i  ].x - path->p[i-1].x;
   353             float dy = path->p[i  ].y - path->p[i-1].y;
   354             length += (float)(SDL_sqrt(dx*dx+dy*dy));
   355         }
   356     }
   357 
   358     /* Resample */
   359     interval = length/(DOLLARNPOINTS - 1);
   360     dist = interval;
   361 
   362     centroid.x = 0;centroid.y = 0;
   363 
   364     /* printf("(%f,%f)\n",path->p[path->numPoints-1].x,path->p[path->numPoints-1].y); */
   365     for (i = 1; i < path->numPoints; i++) {
   366         float d = (float)(SDL_sqrt((path->p[i-1].x-path->p[i].x)*(path->p[i-1].x-path->p[i].x)+
   367                                    (path->p[i-1].y-path->p[i].y)*(path->p[i-1].y-path->p[i].y)));
   368         /* printf("d = %f dist = %f/%f\n",d,dist,interval); */
   369         while (dist + d > interval) {
   370             points[numPoints].x = path->p[i-1].x +
   371                 ((interval-dist)/d)*(path->p[i].x-path->p[i-1].x);
   372             points[numPoints].y = path->p[i-1].y +
   373                 ((interval-dist)/d)*(path->p[i].y-path->p[i-1].y);
   374             centroid.x += points[numPoints].x;
   375             centroid.y += points[numPoints].y;
   376             numPoints++;
   377 
   378             dist -= interval;
   379         }
   380         dist += d;
   381     }
   382     if (numPoints < DOLLARNPOINTS-1) {
   383         SDL_SetError("ERROR: NumPoints = %i", numPoints);
   384         return 0;
   385     }
   386     /* copy the last point */
   387     points[DOLLARNPOINTS-1] = path->p[path->numPoints-1];
   388     numPoints = DOLLARNPOINTS;
   389 
   390     centroid.x /= numPoints;
   391     centroid.y /= numPoints;
   392 
   393     /* printf("Centroid (%f,%f)",centroid.x,centroid.y); */
   394     /* Rotate Points so point 0 is left of centroid and solve for the bounding box */
   395     xmin = centroid.x;
   396     xmax = centroid.x;
   397     ymin = centroid.y;
   398     ymax = centroid.y;
   399 
   400     ang = (float)(SDL_atan2(centroid.y - points[0].y,
   401                             centroid.x - points[0].x));
   402 
   403     for (i = 0; i<numPoints; i++) {
   404         float px = points[i].x;
   405         float py = points[i].y;
   406         points[i].x = (float)((px - centroid.x)*SDL_cos(ang) -
   407                               (py - centroid.y)*SDL_sin(ang) + centroid.x);
   408         points[i].y = (float)((px - centroid.x)*SDL_sin(ang) +
   409                               (py - centroid.y)*SDL_cos(ang) + centroid.y);
   410 
   411 
   412         if (points[i].x < xmin) xmin = points[i].x;
   413         if (points[i].x > xmax) xmax = points[i].x;
   414         if (points[i].y < ymin) ymin = points[i].y;
   415         if (points[i].y > ymax) ymax = points[i].y;
   416     }
   417 
   418     /* Scale points to DOLLARSIZE, and translate to the origin */
   419     w = xmax-xmin;
   420     h = ymax-ymin;
   421 
   422     for (i=0; i<numPoints; i++) {
   423         points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w;
   424         points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h;
   425     }
   426     return numPoints;
   427 }
   428 
   429 static float dollarRecognize(const SDL_DollarPath *path,int *bestTempl,SDL_GestureTouch* touch)
   430 {
   431     SDL_FloatPoint points[DOLLARNPOINTS];
   432     int i;
   433     float bestDiff = 10000;
   434 
   435     SDL_memset(points, 0, sizeof(points));
   436 
   437     dollarNormalize(path,points);
   438 
   439     /* PrintPath(points); */
   440     *bestTempl = -1;
   441     for (i = 0; i < touch->numDollarTemplates; i++) {
   442         float diff = bestDollarDifference(points,touch->dollarTemplate[i].path);
   443         if (diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
   444     }
   445     return bestDiff;
   446 }
   447 
   448 int SDL_GestureAddTouch(SDL_TouchID touchId)
   449 {
   450     SDL_GestureTouch *gestureTouch = (SDL_GestureTouch *)SDL_realloc(SDL_gestureTouch,
   451                                                                      (SDL_numGestureTouches + 1) *
   452                                                                      sizeof(SDL_GestureTouch));
   453 
   454     if (!gestureTouch) {
   455         return SDL_OutOfMemory();
   456     }
   457 
   458     SDL_gestureTouch = gestureTouch;
   459 
   460     SDL_zero(SDL_gestureTouch[SDL_numGestureTouches]);
   461     SDL_gestureTouch[SDL_numGestureTouches].id = touchId;
   462     SDL_numGestureTouches++;
   463     return 0;
   464 }
   465 
   466 int SDL_GestureDelTouch(SDL_TouchID touchId)
   467 {
   468     int i;
   469     for (i = 0; i < SDL_numGestureTouches; i++) {
   470         if (SDL_gestureTouch[i].id == touchId) {
   471             break;
   472         }
   473     }
   474 
   475     if (i == SDL_numGestureTouches) {
   476         /* not found */
   477         return -1;
   478     }
   479 
   480     SDL_free(SDL_gestureTouch[i].dollarTemplate);
   481     SDL_zero(SDL_gestureTouch[i]);
   482 
   483     SDL_numGestureTouches--;
   484     SDL_memcpy(&SDL_gestureTouch[i], &SDL_gestureTouch[SDL_numGestureTouches], sizeof(SDL_gestureTouch[i]));
   485     return 0;
   486 }
   487 
   488 static SDL_GestureTouch * SDL_GetGestureTouch(SDL_TouchID id)
   489 {
   490     int i;
   491     for (i = 0; i < SDL_numGestureTouches; i++) {
   492         /* printf("%i ?= %i\n",SDL_gestureTouch[i].id,id); */
   493         if (SDL_gestureTouch[i].id == id)
   494             return &SDL_gestureTouch[i];
   495     }
   496     return NULL;
   497 }
   498 
   499 static int SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist)
   500 {
   501     SDL_Event event;
   502     event.mgesture.type = SDL_MULTIGESTURE;
   503     event.mgesture.touchId = touch->id;
   504     event.mgesture.x = touch->centroid.x;
   505     event.mgesture.y = touch->centroid.y;
   506     event.mgesture.dTheta = dTheta;
   507     event.mgesture.dDist = dDist;
   508     event.mgesture.numFingers = touch->numDownFingers;
   509     return SDL_PushEvent(&event) > 0;
   510 }
   511 
   512 static int SDL_SendGestureDollar(SDL_GestureTouch* touch,
   513                           SDL_GestureID gestureId,float error)
   514 {
   515     SDL_Event event;
   516     event.dgesture.type = SDL_DOLLARGESTURE;
   517     event.dgesture.touchId = touch->id;
   518     event.dgesture.x = touch->centroid.x;
   519     event.dgesture.y = touch->centroid.y;
   520     event.dgesture.gestureId = gestureId;
   521     event.dgesture.error = error;
   522     /* A finger came up to trigger this event. */
   523     event.dgesture.numFingers = touch->numDownFingers + 1;
   524     return SDL_PushEvent(&event) > 0;
   525 }
   526 
   527 
   528 static int SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId)
   529 {
   530     SDL_Event event;
   531     event.dgesture.type = SDL_DOLLARRECORD;
   532     event.dgesture.touchId = touch->id;
   533     event.dgesture.gestureId = gestureId;
   534     return SDL_PushEvent(&event) > 0;
   535 }
   536 
   537 
   538 void SDL_GestureProcessEvent(SDL_Event* event)
   539 {
   540     float x,y;
   541     int index;
   542     int i;
   543     float pathDx, pathDy;
   544     SDL_FloatPoint lastP;
   545     SDL_FloatPoint lastCentroid;
   546     float lDist;
   547     float Dist;
   548     float dtheta;
   549     float dDist;
   550 
   551     if (event->type == SDL_FINGERMOTION ||
   552         event->type == SDL_FINGERDOWN ||
   553         event->type == SDL_FINGERUP) {
   554         SDL_GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
   555 
   556         /* Shouldn't be possible */
   557         if (inTouch == NULL) return;
   558 
   559         x = event->tfinger.x;
   560         y = event->tfinger.y;
   561 
   562         /* Finger Up */
   563         if (event->type == SDL_FINGERUP) {
   564             SDL_FloatPoint path[DOLLARNPOINTS];
   565 
   566             inTouch->numDownFingers--;
   567 
   568 #ifdef ENABLE_DOLLAR
   569             if (inTouch->recording) {
   570                 inTouch->recording = SDL_FALSE;
   571                 dollarNormalize(&inTouch->dollarPath,path);
   572                 /* PrintPath(path); */
   573                 if (recordAll) {
   574                     index = SDL_AddDollarGesture(NULL,path);
   575                     for (i = 0; i < SDL_numGestureTouches; i++)
   576                         SDL_gestureTouch[i].recording = SDL_FALSE;
   577                 }
   578                 else {
   579                     index = SDL_AddDollarGesture(inTouch,path);
   580                 }
   581 
   582                 if (index >= 0) {
   583                     SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash);
   584                 }
   585                 else {
   586                     SDL_SendDollarRecord(inTouch,-1);
   587                 }
   588             }
   589             else {
   590                 int bestTempl;
   591                 float error;
   592                 error = dollarRecognize(&inTouch->dollarPath,
   593                                         &bestTempl,inTouch);
   594                 if (bestTempl >= 0){
   595                     /* Send Event */
   596                     unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash;
   597                     SDL_SendGestureDollar(inTouch,gestureId,error);
   598                     /* printf ("%s\n",);("Dollar error: %f\n",error); */
   599                 }
   600             }
   601 #endif
   602             /* inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers]; */
   603             if (inTouch->numDownFingers > 0) {
   604                 inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
   605                                        x)/inTouch->numDownFingers;
   606                 inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
   607                                        y)/inTouch->numDownFingers;
   608             }
   609         }
   610         else if (event->type == SDL_FINGERMOTION) {
   611             float dx = event->tfinger.dx;
   612             float dy = event->tfinger.dy;
   613 #ifdef ENABLE_DOLLAR
   614             SDL_DollarPath* path = &inTouch->dollarPath;
   615             if (path->numPoints < MAXPATHSIZE) {
   616                 path->p[path->numPoints].x = inTouch->centroid.x;
   617                 path->p[path->numPoints].y = inTouch->centroid.y;
   618                 pathDx =
   619                     (path->p[path->numPoints].x-path->p[path->numPoints-1].x);
   620                 pathDy =
   621                     (path->p[path->numPoints].y-path->p[path->numPoints-1].y);
   622                 path->length += (float)SDL_sqrt(pathDx*pathDx + pathDy*pathDy);
   623                 path->numPoints++;
   624             }
   625 #endif
   626             lastP.x = x - dx;
   627             lastP.y = y - dy;
   628             lastCentroid = inTouch->centroid;
   629 
   630             inTouch->centroid.x += dx/inTouch->numDownFingers;
   631             inTouch->centroid.y += dy/inTouch->numDownFingers;
   632             /* printf("Centrid : (%f,%f)\n",inTouch->centroid.x,inTouch->centroid.y); */
   633             if (inTouch->numDownFingers > 1) {
   634                 SDL_FloatPoint lv; /* Vector from centroid to last x,y position */
   635                 SDL_FloatPoint v; /* Vector from centroid to current x,y position */
   636                 /* lv = inTouch->gestureLast[j].cv; */
   637                 lv.x = lastP.x - lastCentroid.x;
   638                 lv.y = lastP.y - lastCentroid.y;
   639                 lDist = (float)SDL_sqrt(lv.x*lv.x + lv.y*lv.y);
   640                 /* printf("lDist = %f\n",lDist); */
   641                 v.x = x - inTouch->centroid.x;
   642                 v.y = y - inTouch->centroid.y;
   643                 /* inTouch->gestureLast[j].cv = v; */
   644                 Dist = (float)SDL_sqrt(v.x*v.x+v.y*v.y);
   645                 /* SDL_cos(dTheta) = (v . lv)/(|v| * |lv|) */
   646 
   647                 /* Normalize Vectors to simplify angle calculation */
   648                 lv.x/=lDist;
   649                 lv.y/=lDist;
   650                 v.x/=Dist;
   651                 v.y/=Dist;
   652                 dtheta = (float)SDL_atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
   653 
   654                 dDist = (Dist - lDist);
   655                 if (lDist == 0) {dDist = 0;dtheta = 0;} /* To avoid impossible values */
   656 
   657                 /* inTouch->gestureLast[j].dDist = dDist;
   658                 inTouch->gestureLast[j].dtheta = dtheta;
   659 
   660                 printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
   661                 gdtheta = gdtheta*.9 + dtheta*.1;
   662                 gdDist  =  gdDist*.9 +  dDist*.1
   663                 knob.r += dDist/numDownFingers;
   664                 knob.ang += dtheta;
   665                 printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
   666                 printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist); */
   667                 SDL_SendGestureMulti(inTouch,dtheta,dDist);
   668             }
   669             else {
   670                 /* inTouch->gestureLast[j].dDist = 0;
   671                 inTouch->gestureLast[j].dtheta = 0;
   672                 inTouch->gestureLast[j].cv.x = 0;
   673                 inTouch->gestureLast[j].cv.y = 0; */
   674             }
   675             /* inTouch->gestureLast[j].f.p.x = x;
   676             inTouch->gestureLast[j].f.p.y = y;
   677             break;
   678             pressure? */
   679         }
   680         else if (event->type == SDL_FINGERDOWN) {
   681 
   682             inTouch->numDownFingers++;
   683             inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+
   684                                    x)/inTouch->numDownFingers;
   685             inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+
   686                                    y)/inTouch->numDownFingers;
   687             /* printf("Finger Down: (%f,%f). Centroid: (%f,%f\n",x,y,
   688                  inTouch->centroid.x,inTouch->centroid.y); */
   689 
   690 #ifdef ENABLE_DOLLAR
   691             inTouch->dollarPath.length = 0;
   692             inTouch->dollarPath.p[0].x = x;
   693             inTouch->dollarPath.p[0].y = y;
   694             inTouch->dollarPath.numPoints = 1;
   695 #endif
   696         }
   697     }
   698 }
   699 
   700 /* vi: set ts=4 sw=4 expandtab: */