src/events/SDL_gesture.c
author Ozkan Sezer
Mon, 25 Jan 2021 04:11:40 +0300
changeset 14792 d01593bd58d9
parent 14706 17d911637a65
permissions -rw-r--r--
better check for clock_gettime_nsec_np() -- cf. bug #5467.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2021 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     if (i != SDL_numGestureTouches) {
   491         SDL_memcpy(&SDL_gestureTouch[i], &SDL_gestureTouch[SDL_numGestureTouches], sizeof(SDL_gestureTouch[i]));
   492     }
   493     return 0;
   494 }
   495 
   496 static SDL_GestureTouch * SDL_GetGestureTouch(SDL_TouchID id)
   497 {
   498     int i;
   499     for (i = 0; i < SDL_numGestureTouches; i++) {
   500         /* printf("%i ?= %i\n",SDL_gestureTouch[i].id,id); */
   501         if (SDL_gestureTouch[i].id == id)
   502             return &SDL_gestureTouch[i];
   503     }
   504     return NULL;
   505 }
   506 
   507 static void SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist)
   508 {
   509     if (SDL_GetEventState(SDL_MULTIGESTURE) == SDL_ENABLE) {
   510         SDL_Event event;
   511         event.mgesture.type = SDL_MULTIGESTURE;
   512         event.mgesture.touchId = touch->id;
   513         event.mgesture.x = touch->centroid.x;
   514         event.mgesture.y = touch->centroid.y;
   515         event.mgesture.dTheta = dTheta;
   516         event.mgesture.dDist = dDist;
   517         event.mgesture.numFingers = touch->numDownFingers;
   518         SDL_PushEvent(&event);
   519     }
   520 }
   521 
   522 #if defined(ENABLE_DOLLAR)
   523 static void SDL_SendGestureDollar(SDL_GestureTouch* touch,
   524                           SDL_GestureID gestureId,float error)
   525 {
   526     if (SDL_GetEventState(SDL_DOLLARGESTURE) == SDL_ENABLE) {
   527         SDL_Event event;
   528         event.dgesture.type = SDL_DOLLARGESTURE;
   529         event.dgesture.touchId = touch->id;
   530         event.dgesture.x = touch->centroid.x;
   531         event.dgesture.y = touch->centroid.y;
   532         event.dgesture.gestureId = gestureId;
   533         event.dgesture.error = error;
   534         /* A finger came up to trigger this event. */
   535         event.dgesture.numFingers = touch->numDownFingers + 1;
   536         SDL_PushEvent(&event);
   537     }
   538 }
   539 
   540 static void SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId)
   541 {
   542     if (SDL_GetEventState(SDL_DOLLARRECORD) == SDL_ENABLE) {
   543         SDL_Event event;
   544         event.dgesture.type = SDL_DOLLARRECORD;
   545         event.dgesture.touchId = touch->id;
   546         event.dgesture.gestureId = gestureId;
   547         SDL_PushEvent(&event);
   548     }
   549 }
   550 #endif
   551 
   552 
   553 void SDL_GestureProcessEvent(SDL_Event* event)
   554 {
   555     float x,y;
   556 #if defined(ENABLE_DOLLAR)
   557     int index;
   558     int i;
   559     float pathDx, pathDy;
   560 #endif
   561     SDL_FloatPoint lastP;
   562     SDL_FloatPoint lastCentroid;
   563     float lDist;
   564     float Dist;
   565     float dtheta;
   566     float dDist;
   567 
   568     if (event->type == SDL_FINGERMOTION ||
   569         event->type == SDL_FINGERDOWN ||
   570         event->type == SDL_FINGERUP) {
   571         SDL_GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
   572 
   573         /* Shouldn't be possible */
   574         if (inTouch == NULL) return;
   575 
   576         x = event->tfinger.x;
   577         y = event->tfinger.y;
   578 
   579         /* Finger Up */
   580         if (event->type == SDL_FINGERUP) {
   581 #if defined(ENABLE_DOLLAR)
   582             SDL_FloatPoint path[DOLLARNPOINTS];
   583 #endif
   584 
   585             inTouch->numDownFingers--;
   586 
   587 #if defined(ENABLE_DOLLAR)
   588             if (inTouch->recording) {
   589                 inTouch->recording = SDL_FALSE;
   590                 dollarNormalize(&inTouch->dollarPath, path, SDL_TRUE);
   591                 /* PrintPath(path); */
   592                 if (recordAll) {
   593                     index = SDL_AddDollarGesture(NULL,path);
   594                     for (i = 0; i < SDL_numGestureTouches; i++)
   595                         SDL_gestureTouch[i].recording = SDL_FALSE;
   596                 }
   597                 else {
   598                     index = SDL_AddDollarGesture(inTouch,path);
   599                 }
   600 
   601                 if (index >= 0) {
   602                     SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash);
   603                 }
   604                 else {
   605                     SDL_SendDollarRecord(inTouch,-1);
   606                 }
   607             }
   608             else {
   609                 int bestTempl;
   610                 float error;
   611                 error = dollarRecognize(&inTouch->dollarPath,
   612                                         &bestTempl,inTouch);
   613                 if (bestTempl >= 0){
   614                     /* Send Event */
   615                     unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash;
   616                     SDL_SendGestureDollar(inTouch,gestureId,error);
   617                     /* printf ("%s\n",);("Dollar error: %f\n",error); */
   618                 }
   619             }
   620 #endif
   621             /* inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers]; */
   622             if (inTouch->numDownFingers > 0) {
   623                 inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
   624                                        x)/inTouch->numDownFingers;
   625                 inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
   626                                        y)/inTouch->numDownFingers;
   627             }
   628         }
   629         else if (event->type == SDL_FINGERMOTION) {
   630             float dx = event->tfinger.dx;
   631             float dy = event->tfinger.dy;
   632 #if defined(ENABLE_DOLLAR)
   633             SDL_DollarPath* path = &inTouch->dollarPath;
   634             if (path->numPoints < MAXPATHSIZE) {
   635                 path->p[path->numPoints].x = inTouch->centroid.x;
   636                 path->p[path->numPoints].y = inTouch->centroid.y;
   637                 pathDx =
   638                     (path->p[path->numPoints].x-path->p[path->numPoints-1].x);
   639                 pathDy =
   640                     (path->p[path->numPoints].y-path->p[path->numPoints-1].y);
   641                 path->length += (float)SDL_sqrt(pathDx*pathDx + pathDy*pathDy);
   642                 path->numPoints++;
   643             }
   644 #endif
   645             lastP.x = x - dx;
   646             lastP.y = y - dy;
   647             lastCentroid = inTouch->centroid;
   648 
   649             inTouch->centroid.x += dx/inTouch->numDownFingers;
   650             inTouch->centroid.y += dy/inTouch->numDownFingers;
   651             /* printf("Centrid : (%f,%f)\n",inTouch->centroid.x,inTouch->centroid.y); */
   652             if (inTouch->numDownFingers > 1) {
   653                 SDL_FloatPoint lv; /* Vector from centroid to last x,y position */
   654                 SDL_FloatPoint v; /* Vector from centroid to current x,y position */
   655                 /* lv = inTouch->gestureLast[j].cv; */
   656                 lv.x = lastP.x - lastCentroid.x;
   657                 lv.y = lastP.y - lastCentroid.y;
   658                 lDist = (float)SDL_sqrt(lv.x*lv.x + lv.y*lv.y);
   659                 /* printf("lDist = %f\n",lDist); */
   660                 v.x = x - inTouch->centroid.x;
   661                 v.y = y - inTouch->centroid.y;
   662                 /* inTouch->gestureLast[j].cv = v; */
   663                 Dist = (float)SDL_sqrt(v.x*v.x+v.y*v.y);
   664                 /* SDL_cos(dTheta) = (v . lv)/(|v| * |lv|) */
   665 
   666                 /* Normalize Vectors to simplify angle calculation */
   667                 lv.x/=lDist;
   668                 lv.y/=lDist;
   669                 v.x/=Dist;
   670                 v.y/=Dist;
   671                 dtheta = (float)SDL_atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
   672 
   673                 dDist = (Dist - lDist);
   674                 if (lDist == 0) {dDist = 0;dtheta = 0;} /* To avoid impossible values */
   675 
   676                 /* inTouch->gestureLast[j].dDist = dDist;
   677                 inTouch->gestureLast[j].dtheta = dtheta;
   678 
   679                 printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
   680                 gdtheta = gdtheta*.9 + dtheta*.1;
   681                 gdDist  =  gdDist*.9 +  dDist*.1
   682                 knob.r += dDist/numDownFingers;
   683                 knob.ang += dtheta;
   684                 printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
   685                 printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist); */
   686                 SDL_SendGestureMulti(inTouch,dtheta,dDist);
   687             }
   688             else {
   689                 /* inTouch->gestureLast[j].dDist = 0;
   690                 inTouch->gestureLast[j].dtheta = 0;
   691                 inTouch->gestureLast[j].cv.x = 0;
   692                 inTouch->gestureLast[j].cv.y = 0; */
   693             }
   694             /* inTouch->gestureLast[j].f.p.x = x;
   695             inTouch->gestureLast[j].f.p.y = y;
   696             break;
   697             pressure? */
   698         }
   699         else if (event->type == SDL_FINGERDOWN) {
   700 
   701             inTouch->numDownFingers++;
   702             inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+
   703                                    x)/inTouch->numDownFingers;
   704             inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+
   705                                    y)/inTouch->numDownFingers;
   706             /* printf("Finger Down: (%f,%f). Centroid: (%f,%f\n",x,y,
   707                  inTouch->centroid.x,inTouch->centroid.y); */
   708 
   709 #if defined(ENABLE_DOLLAR)
   710             inTouch->dollarPath.length = 0;
   711             inTouch->dollarPath.p[0].x = x;
   712             inTouch->dollarPath.p[0].y = y;
   713             inTouch->dollarPath.numPoints = 1;
   714 #endif
   715         }
   716     }
   717 }
   718 
   719 /* vi: set ts=4 sw=4 expandtab: */