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