1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 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
SDL_RecordGesture(SDL_TouchID touchId)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
SDL_GestureQuit()106 void SDL_GestureQuit()
107 {
108 SDL_free(SDL_gestureTouch);
109 SDL_gestureTouch = NULL;
110 }
111
SDL_HashDollar(SDL_FloatPoint * points)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
SaveTemplate(SDL_DollarTemplate * templ,SDL_RWops * dst)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
SDL_SaveAllDollarTemplates(SDL_RWops * dst)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
SDL_SaveDollarTemplate(SDL_GestureID gestureId,SDL_RWops * dst)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 */
SDL_AddDollarGesture_one(SDL_GestureTouch * inTouch,SDL_FloatPoint * path)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
SDL_AddDollarGesture(SDL_GestureTouch * inTouch,SDL_FloatPoint * path)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
SDL_LoadDollarTemplates(SDL_TouchID touchId,SDL_RWops * src)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)
dollarDifference(SDL_FloatPoint * points,SDL_FloatPoint * templ,float ang)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
bestDollarDifference(SDL_FloatPoint * points,SDL_FloatPoint * templ)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 */
dollarNormalize(const SDL_DollarPath * path,SDL_FloatPoint * points,SDL_bool is_recording)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
dollarRecognize(const SDL_DollarPath * path,int * bestTempl,SDL_GestureTouch * touch)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
SDL_GestureAddTouch(SDL_TouchID touchId)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
SDL_GestureDelTouch(SDL_TouchID touchId)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
SDL_GetGestureTouch(SDL_TouchID id)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
SDL_SendGestureMulti(SDL_GestureTouch * touch,float dTheta,float dDist)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)
SDL_SendGestureDollar(SDL_GestureTouch * touch,SDL_GestureID gestureId,float error)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
SDL_SendDollarRecord(SDL_GestureTouch * touch,SDL_GestureID gestureId)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
SDL_GestureProcessEvent(SDL_Event * event)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: */
718