src/events/SDL_gesture.c
author Jim Grandpre <jim.tla@gmail.com>
Fri, 06 Aug 2010 01:55:38 -0400
changeset 4684 f47c2640c667
parent 4683 15dfe42edbfd
child 4685 e0c3b09368a6
permissions -rw-r--r--
Re-enabled dollar gesture
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software    Founation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    17 
    18     Sam Lantinga
    19     slouken@libsdl.org
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* General mouse handling code for SDL */
    24 
    25 #include "SDL_events.h"
    26 #include "SDL_events_c.h"
    27 #include "SDL_gesture_c.h"
    28 
    29 //TODO: Replace with malloc
    30 #define MAXFINGERS 5
    31 #define MAXTOUCHES 2
    32 #define MAXTEMPLATES 4
    33 #define MAXPATHSIZE 1024
    34 
    35 #define DOLLARNPOINTS 64
    36 #define DOLLARSIZE 256
    37 
    38 #define ENABLE_DOLLAR
    39 
    40 //PHI = ((sqrt(5)-1)/2)
    41 #define PHI 0.618033989 
    42 
    43 typedef struct {
    44   float x,y;
    45 } Point;
    46 
    47 
    48 typedef struct {
    49   Point p;
    50   float pressure;
    51   SDL_FingerID id;
    52 } Finger;
    53 
    54 
    55 typedef struct {
    56   float length;
    57   
    58   int numPoints;
    59   Point p[MAXPATHSIZE];
    60 } DollarPath;
    61 
    62 /*
    63 typedef struct {
    64   Finger f;
    65   Point cv;
    66   float dtheta,dDist;
    67   DollarPath dollarPath;
    68 } TouchPoint;
    69 */
    70 typedef struct {
    71   Point path[DOLLARNPOINTS];
    72   unsigned long hash;
    73 } DollarTemplate;
    74 
    75 typedef struct {
    76   SDL_GestureID id;
    77   Point res;
    78   Point centroid;
    79   //TouchPoint gestureLast[MAXFINGERS];
    80   DollarPath dollarPath;
    81   Uint16 numDownFingers;
    82 
    83   int numDollarTemplates;
    84   DollarTemplate dollarTemplate[MAXTEMPLATES];
    85 
    86   SDL_bool recording;
    87 } GestureTouch;
    88 
    89 GestureTouch gestureTouch[MAXTOUCHES];
    90 int numGestureTouches = 0;
    91 SDL_bool recordAll;
    92 
    93 int SDL_RecordGesture(SDL_TouchID touchId) {
    94   int i;
    95   if(touchId < 0) recordAll = SDL_TRUE;
    96   for(i = 0;i < numGestureTouches; i++) {
    97     if((touchId < 0) || (gestureTouch[i].id == touchId)) {
    98       gestureTouch[i].recording = SDL_TRUE;
    99       if(touchId >= 0)
   100 	return 1;
   101     }      
   102   }
   103   return (touchId < 0);
   104 }
   105 
   106 unsigned long SDL_HashDollar(Point* points) {
   107   unsigned long hash = 5381;
   108   int i;
   109   for(i = 0;i < DOLLARNPOINTS; i++) { 
   110     hash = ((hash<<5) + hash) + points[i].x;
   111     hash = ((hash<<5) + hash) + points[i].y;
   112   }
   113   return hash;
   114 }
   115 
   116 
   117 static int SaveTemplate(DollarTemplate *templ, SDL_RWops * src) {
   118   if(src == NULL) return 0;
   119 
   120   int i;
   121   
   122   //No Longer storing the Hash, rehash on load
   123   //if(SDL_RWops.write(src,&(templ->hash),sizeof(templ->hash),1) != 1) return 0;
   124 
   125   if(SDL_RWwrite(src,templ->path,
   126 		 sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) 
   127     return 0;
   128 
   129   return 1;
   130 }
   131 
   132 
   133 int SDL_SaveAllDollarTemplates(SDL_RWops *src) {  
   134   int i,j,rtrn = 0;
   135   for(i = 0; i < numGestureTouches; i++) {
   136     GestureTouch* touch = &gestureTouch[i];
   137     for(j = 0;j < touch->numDollarTemplates; j++) {
   138 	rtrn += SaveTemplate(&touch->dollarTemplate[i],src);
   139     }
   140   }
   141   return rtrn;  
   142 }
   143 
   144 int SDL_SaveDollarTemplate(SDL_GestureID gestureId, SDL_RWops *src) {
   145   int i,j;
   146   for(i = 0; i < numGestureTouches; i++) {
   147     GestureTouch* touch = &gestureTouch[i];
   148     for(j = 0;j < touch->numDollarTemplates; j++) {
   149       if(touch->dollarTemplate[i].hash == gestureId) {
   150 	return SaveTemplate(&touch->dollarTemplate[i],src);
   151       }
   152     }
   153   }
   154   SDL_SetError("Unknown gestureId");
   155   return -1;
   156 }
   157 
   158 //path is an already sampled set of points
   159 //Returns the index of the gesture on success, or -1
   160 static int SDL_AddDollarGesture(GestureTouch* inTouch,Point* path) {
   161   if(inTouch == NULL) {
   162     if(numGestureTouches == 0) return -1;
   163     int i = 0;
   164     for(i = 0;i < numGestureTouches; i++) {
   165       inTouch = &gestureTouch[i];
   166       if(inTouch->numDollarTemplates < MAXTEMPLATES) {
   167 	DollarTemplate *templ = 
   168 	  &inTouch->dollarTemplate[inTouch->numDollarTemplates];
   169 	memcpy(templ->path,path,DOLLARNPOINTS*sizeof(Point));
   170 	templ->hash = SDL_HashDollar(templ->path);
   171 	inTouch->numDollarTemplates++;
   172       }
   173     }
   174     return inTouch->numDollarTemplates - 1;
   175   }else if(inTouch->numDollarTemplates < MAXTEMPLATES) {
   176     DollarTemplate *templ = 
   177       &inTouch->dollarTemplate[inTouch->numDollarTemplates];
   178     memcpy(templ->path,path,DOLLARNPOINTS*sizeof(Point));
   179     templ->hash = SDL_HashDollar(templ->path);
   180     inTouch->numDollarTemplates++;
   181     return inTouch->numDollarTemplates - 1;
   182   }
   183   return -1;
   184 }
   185 
   186 int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src) {
   187   if(src == NULL) return 0;
   188   int i,loaded = 0;
   189   GestureTouch *touch = NULL;
   190   if(touchId >= 0) {
   191     for(i = 0;i < numGestureTouches; i++)
   192       if(gestureTouch[i].id == touchId)
   193 	touch = &gestureTouch[i];
   194     if(touch == NULL) return -1;
   195   }
   196 
   197   while(1) {
   198     DollarTemplate templ;
   199     //fscanf(fp,"%lu ",&templ.hash);
   200     /*
   201     for(i = 0;i < DOLLARNPOINTS; i++) {		
   202       int x,y;
   203       if(fscanf(fp,"%i %i ",&x,&y) != 2) break;
   204       templ.path[i].x = x;
   205       templ.path[i].y = y;
   206     }
   207     fscanf(fp,"\n");
   208     */
   209     if(SDL_RWread(src,templ.path,sizeof(templ.path[0]),DOLLARNPOINTS) < DOLLARNPOINTS) break;
   210 
   211     if(touchId >= 0) {
   212       printf("Adding loaded gesture to 1 touch\n");
   213       if(SDL_AddDollarGesture(touch,templ.path)) loaded++;
   214     }
   215     else {
   216       printf("Adding to: %i touches\n",numGestureTouches);
   217       for(i = 0;i < numGestureTouches; i++) {
   218 	touch = &gestureTouch[i];
   219 	printf("Adding loaded gesture to + touches\n");
   220 	//TODO: What if this fails?
   221 	SDL_AddDollarGesture(touch,templ.path);	
   222       }
   223       loaded++;
   224     }
   225   }
   226 
   227   return loaded; 
   228 }
   229 
   230 
   231 float dollarDifference(Point* points,Point* templ,float ang) {
   232   //  Point p[DOLLARNPOINTS];
   233   float dist = 0;
   234   Point p;
   235   int i;
   236   for(i = 0; i < DOLLARNPOINTS; i++) {
   237     p.x = points[i].x * cos(ang) - points[i].y * sin(ang);
   238     p.y = points[i].x * sin(ang) + points[i].y * cos(ang);
   239     dist += sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
   240 		 (p.y-templ[i].y)*(p.y-templ[i].y));
   241   }
   242   return dist/DOLLARNPOINTS;
   243   
   244 }
   245 
   246 float bestDollarDifference(Point* points,Point* templ) {
   247   //------------BEGIN DOLLAR BLACKBOX----------------//
   248   //-TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-//
   249   //-"http://depts.washington.edu/aimgroup/proj/dollar/"-//
   250   float ta = -M_PI/4;
   251   float tb = M_PI/4;
   252   float dt = M_PI/90;
   253   float x1 = PHI*ta + (1-PHI)*tb;
   254   float f1 = dollarDifference(points,templ,x1);
   255   float x2 = (1-PHI)*ta + PHI*tb;
   256   float f2 = dollarDifference(points,templ,x2);
   257   while(abs(ta-tb) > dt) {
   258     if(f1 < f2) {
   259       tb = x2;
   260       x2 = x1;
   261       f2 = f1;
   262       x1 = PHI*ta + (1-PHI)*tb;
   263       f1 = dollarDifference(points,templ,x1);
   264     }
   265     else {
   266       ta = x1;
   267       x1 = x2;
   268       f1 = f2;
   269       x2 = (1-PHI)*ta + PHI*tb;
   270       f2 = dollarDifference(points,templ,x2);
   271     }
   272   }
   273   /*
   274   if(f1 <= f2)
   275     printf("Min angle (x1): %f\n",x1);
   276   else if(f1 >  f2)
   277     printf("Min angle (x2): %f\n",x2);
   278   */
   279   return SDL_min(f1,f2);  
   280 }
   281 
   282 //DollarPath contains raw points, plus (possibly) the calculated length
   283 int dollarNormalize(DollarPath path,Point *points) {
   284   int i;
   285   //Calculate length if it hasn't already been done
   286   if(path.length <= 0) {
   287     for(i=1;i<path.numPoints;i++) {
   288       float dx = path.p[i  ].x - 
   289 	         path.p[i-1].x;
   290       float dy = path.p[i  ].y - 
   291 	         path.p[i-1].y;
   292       path.length += sqrt(dx*dx+dy*dy);
   293     }
   294   }
   295 
   296 
   297   //Resample
   298   float interval = path.length/(DOLLARNPOINTS - 1);
   299   float dist = 0;
   300 
   301   int numPoints = 0;
   302   Point centroid; centroid.x = 0;centroid.y = 0;
   303   //printf("(%f,%f)\n",path.p[path.numPoints-1].x,path.p[path.numPoints-1].y);
   304   for(i = 1;i < path.numPoints;i++) {
   305     float d = sqrt((path.p[i-1].x-path.p[i].x)*(path.p[i-1].x-path.p[i].x)+
   306 		   (path.p[i-1].y-path.p[i].y)*(path.p[i-1].y-path.p[i].y));
   307     //printf("d = %f dist = %f/%f\n",d,dist,interval);
   308     while(dist + d > interval) {
   309       points[numPoints].x = path.p[i-1].x + 
   310 	((interval-dist)/d)*(path.p[i].x-path.p[i-1].x);
   311       points[numPoints].y = path.p[i-1].y + 
   312 	((interval-dist)/d)*(path.p[i].y-path.p[i-1].y);
   313       centroid.x += points[numPoints].x;
   314       centroid.y += points[numPoints].y;
   315       numPoints++;
   316 
   317       dist -= interval;
   318     }
   319     dist += d;
   320   }
   321   if(numPoints < 1) return 0;
   322   centroid.x /= numPoints;
   323   centroid.y /= numPoints;
   324  
   325   //printf("Centroid (%f,%f)",centroid.x,centroid.y);
   326   //Rotate Points so point 0 is left of centroid and solve for the bounding box
   327   float xmin,xmax,ymin,ymax;
   328   xmin = centroid.x;
   329   xmax = centroid.x;
   330   ymin = centroid.y;
   331   ymax = centroid.y;
   332   
   333   float ang = atan2(centroid.y - points[0].y,
   334 		    centroid.x - points[0].x);
   335 
   336   for(i = 0;i<numPoints;i++) {					       
   337     float px = points[i].x;
   338     float py = points[i].y;
   339     points[i].x = (px - centroid.x)*cos(ang) - 
   340                   (py - centroid.y)*sin(ang) + centroid.x;
   341     points[i].y = (px - centroid.x)*sin(ang) + 
   342                   (py - centroid.y)*cos(ang) + centroid.y;
   343 
   344 
   345     if(points[i].x < xmin) xmin = points[i].x;
   346     if(points[i].x > xmax) xmax = points[i].x; 
   347     if(points[i].y < ymin) ymin = points[i].y;
   348     if(points[i].y > ymax) ymax = points[i].y;
   349   }
   350 
   351   //Scale points to DOLLARSIZE, and translate to the origin
   352   float w = xmax-xmin;
   353   float h = ymax-ymin;
   354 
   355   for(i=0;i<numPoints;i++) {
   356     points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w;
   357     points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h;
   358   }  
   359   return numPoints;
   360 }
   361 
   362 float dollarRecognize(DollarPath path,int *bestTempl,GestureTouch* touch) {
   363 	
   364 	Point points[DOLLARNPOINTS];
   365 	int numPoints = dollarNormalize(path,points);
   366 	int i;
   367 	
   368 	int bestDiff = 10000;
   369 	*bestTempl = -1;
   370 	for(i = 0;i < touch->numDollarTemplates;i++) {
   371 		int diff = bestDollarDifference(points,touch->dollarTemplate[i].path);
   372 		if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
   373 	}
   374 	return bestDiff;
   375 }
   376 
   377 int SDL_GestureAddTouch(SDL_Touch* touch) { 
   378   if(numGestureTouches >= MAXTOUCHES) return -1;
   379   
   380   gestureTouch[numGestureTouches].res.x = touch->xres;
   381   gestureTouch[numGestureTouches].res.y = touch->yres;
   382   gestureTouch[numGestureTouches].numDownFingers = 0;
   383 
   384   gestureTouch[numGestureTouches].res.x = touch->xres;
   385   gestureTouch[numGestureTouches].id = touch->id;
   386 
   387   gestureTouch[numGestureTouches].numDollarTemplates = 0;
   388 
   389   gestureTouch[numGestureTouches].recording = SDL_FALSE;
   390 
   391   numGestureTouches++;
   392   return 0;
   393 }
   394 
   395 GestureTouch * SDL_GetGestureTouch(SDL_TouchID id) {
   396   int i;
   397   for(i = 0;i < numGestureTouches; i++) {
   398     //printf("%i ?= %i\n",gestureTouch[i].id,id);
   399     if(gestureTouch[i].id == id) return &gestureTouch[i];
   400   }
   401   return NULL;
   402 }
   403 
   404 int SDL_SendGestureMulti(GestureTouch* touch,float dTheta,float dDist) {
   405   SDL_Event event;
   406   event.mgesture.type = SDL_MULTIGESTURE;
   407   event.mgesture.touchId = touch->id;
   408   event.mgesture.x = touch->centroid.x;
   409   event.mgesture.y = touch->centroid.y;
   410   event.mgesture.dTheta = dTheta;
   411   event.mgesture.dDist = dDist;  
   412   event.mgesture.numFingers = touch->numDownFingers;
   413   return SDL_PushEvent(&event) > 0;
   414 }
   415 
   416 int SDL_SendGestureDollar(GestureTouch* touch,
   417 			  SDL_GestureID gestureId,float error) {
   418   SDL_Event event;
   419   event.dgesture.type = SDL_DOLLARGESTURE;
   420   event.dgesture.touchId = touch->id;
   421   /*
   422     //TODO: Add this to give location of gesture?
   423   event.mgesture.x = touch->centroid.x;
   424   event.mgesture.y = touch->centroid.y;
   425   */
   426   event.dgesture.gestureId = gestureId;
   427   event.dgesture.error = error;  
   428   return SDL_PushEvent(&event) > 0;
   429 }
   430 
   431 
   432 int SDL_SendDollarRecord(GestureTouch* touch,SDL_GestureID gestureId) {
   433   SDL_Event event;
   434   event.dgesture.type = SDL_DOLLARRECORD;
   435   event.dgesture.touchId = touch->id;
   436   event.dgesture.gestureId = gestureId;
   437 
   438   return SDL_PushEvent(&event) > 0;
   439 }
   440 
   441 
   442 void SDL_GestureProcessEvent(SDL_Event* event)
   443 {
   444   if(event->type == SDL_FINGERMOTION || 
   445      event->type == SDL_FINGERDOWN ||
   446      event->type == SDL_FINGERUP) {
   447     GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
   448     
   449     //Shouldn't be possible
   450     if(inTouch == NULL) return;
   451     
   452     //printf("@ (%i,%i) with res: (%i,%i)\n",(int)event->tfinger.x,
   453     //	   (int)event->tfinger.y,
   454     //   (int)inTouch->res.x,(int)inTouch->res.y);
   455 
   456     
   457     float x = ((float)event->tfinger.x)/(float)inTouch->res.x;
   458     float y = ((float)event->tfinger.y)/(float)inTouch->res.y;   
   459 
   460 
   461     //Finger Up
   462     if(event->type == SDL_FINGERUP) {
   463       inTouch->numDownFingers--;
   464       
   465 #ifdef ENABLE_DOLLAR
   466       if(inTouch->recording) {
   467 	inTouch->recording = SDL_FALSE;
   468 	Point path[DOLLARNPOINTS];
   469 	dollarNormalize(inTouch->dollarPath,path);
   470 	int index;
   471 	if(recordAll) {
   472 	  index = SDL_AddDollarGesture(NULL,path);
   473 	  int i;
   474 	  for(i = 0;i < numGestureTouches; i++)
   475 	    gestureTouch[i].recording = SDL_FALSE;
   476 	}
   477 	else {
   478 	  index = SDL_AddDollarGesture(inTouch,path);
   479 	}
   480 	
   481 	if(index >= 0) {
   482 	  SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash);
   483 	}
   484 	else {
   485 	  SDL_SendDollarRecord(inTouch,-1);
   486 	}
   487       }
   488       else {	
   489 	int bestTempl;
   490 	float error;
   491 	error = dollarRecognize(inTouch->dollarPath,
   492 				&bestTempl,inTouch);
   493 	if(bestTempl >= 0){
   494 	  //Send Event
   495 	  unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash;
   496 	  SDL_SendGestureDollar(inTouch,gestureId,error);
   497 	  //printf ("%s\n",);("Dollar error: %f\n",error);
   498 	}
   499       }
   500 #endif 
   501       //inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers];
   502       if(inTouch->numDownFingers > 0) {
   503 	inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
   504 			       x)/inTouch->numDownFingers;
   505 	inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
   506 			       y)/inTouch->numDownFingers;
   507       }
   508     }
   509     else if(event->type == SDL_FINGERMOTION) {
   510       float dx = ((float)event->tfinger.dx)/(float)inTouch->res.x;
   511       float dy = ((float)event->tfinger.dy)/(float)inTouch->res.y;
   512       //printf("dx,dy: (%f,%f)\n",dx,dy); 
   513 #ifdef ENABLE_DOLLAR
   514       DollarPath* path = &inTouch->dollarPath;
   515       if(path->numPoints < MAXPATHSIZE) {
   516 	path->p[path->numPoints].x = inTouch->centroid.x;
   517 	path->p[path->numPoints].y = inTouch->centroid.y;
   518 	path->length += sqrt(dx*dx + dy*dy);
   519 	path->numPoints++;
   520       }
   521 #endif
   522       Point lastP;
   523       lastP.x = x - dx;
   524       lastP.y = y - dy;
   525       Point lastCentroid;
   526       lastCentroid = inTouch->centroid;
   527       
   528       inTouch->centroid.x += dx/inTouch->numDownFingers;
   529       inTouch->centroid.y += dy/inTouch->numDownFingers;    
   530       if(inTouch->numDownFingers > 1) {
   531 	Point lv; //Vector from centroid to last x,y position
   532 	Point v; //Vector from centroid to current x,y position
   533 	//lv = inTouch->gestureLast[j].cv;
   534 	lv.x = lastP.x - lastCentroid.x;
   535 	lv.y = lastP.y - lastCentroid.y;
   536 	float lDist = sqrt(lv.x*lv.x + lv.y*lv.y);
   537 	//printf("lDist = %f\n",lDist);
   538 	v.x = x - inTouch->centroid.x;
   539 	v.y = y - inTouch->centroid.y;
   540 	//inTouch->gestureLast[j].cv = v;
   541 	float Dist = sqrt(v.x*v.x+v.y*v.y);
   542 	// cos(dTheta) = (v . lv)/(|v| * |lv|)
   543 	
   544 	//Normalize Vectors to simplify angle calculation
   545 	lv.x/=lDist;
   546 	lv.y/=lDist;
   547 	v.x/=Dist;
   548 	v.y/=Dist;
   549 	float dtheta = atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
   550 	
   551 	float dDist = (Dist - lDist);
   552 	if(lDist == 0) {dDist = 0;dtheta = 0;} //To avoid impossible values
   553 	
   554 	//inTouch->gestureLast[j].dDist = dDist;
   555 	//inTouch->gestureLast[j].dtheta = dtheta;
   556 	
   557 	//printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
   558 	//gdtheta = gdtheta*.9 + dtheta*.1;
   559 	//gdDist  =  gdDist*.9 +  dDist*.1
   560 	//knob.r += dDist/numDownFingers;
   561 	//knob.ang += dtheta;
   562 	//printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
   563 	//printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist);
   564 	SDL_SendGestureMulti(inTouch,dtheta,dDist);
   565       }
   566       else {
   567 	//inTouch->gestureLast[j].dDist = 0;
   568 	//inTouch->gestureLast[j].dtheta = 0;
   569 	//inTouch->gestureLast[j].cv.x = 0;
   570 	//inTouch->gestureLast[j].cv.y = 0;
   571       }
   572       //inTouch->gestureLast[j].f.p.x = x;
   573       //inTouch->gestureLast[j].f.p.y = y;
   574       //break;
   575       //pressure?
   576     }
   577     
   578     if(event->type == SDL_FINGERDOWN) {
   579 
   580       inTouch->numDownFingers++;
   581       inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+ 
   582 			     x)/inTouch->numDownFingers;
   583       inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+
   584 			     y)/inTouch->numDownFingers;
   585       printf("Finger Down: (%f,%f). Centroid: (%f,%f\n",x,y,
   586 	     inTouch->centroid.x,inTouch->centroid.y);
   587       /*
   588 	inTouch->gestureLast[j].f.id = event->tfinger.fingerId;
   589 	inTouch->gestureLast[j].f.p.x  = x;
   590 	inTouch->gestureLast[j].f.p.y  = y;	
   591 	inTouch->gestureLast[j].cv.x = 0;
   592 	inTouch->gestureLast[j].cv.y = 0;
   593       */
   594 #ifdef ENABLE_DOLLAR
   595       inTouch->dollarPath.length = 0;
   596       inTouch->dollarPath.p[0].x = x;
   597       inTouch->dollarPath.p[0].y = y;
   598       inTouch->dollarPath.numPoints = 1;
   599 #endif
   600     }
   601   }
   602 }
   603 
   604   /* vi: set ts=4 sw=4 expandtab: */
   605