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