Ver código fonte

Added linear flick movement to test application.

UVA Multi-touch 13 anos atrás
pai
commit
32a381b9f5
4 arquivos alterados com 89 adições e 6 exclusões
  1. 1 1
      src/geometry.py
  2. 25 1
      src/trackers/transform.py
  3. 22 4
      tests/testapp.py
  4. 41 0
      tests/utils.py

+ 1 - 1
src/geometry.py

@@ -123,7 +123,7 @@ class MovingPositionable(Positionable):
         positionable.
         """
         px, py = self.prev
-        return self.x - px, self.y - py
+        return Positionable(self.x - px, self.y - py)
 
     def translation_distance(self):
         return self.distance_to(self.prev)

+ 25 - 1
src/trackers/transform.py

@@ -68,12 +68,31 @@ class DragGesture(Gesture, Positionable):
         return self.translation
 
 
+class FlickGesture(Gesture, Positionable):
+    _type = 'flick'
+
+    def __init__(self, event, initial_position, translation):
+        Gesture.__init__(self, event)
+        Positionable.__init__(self, *initial_position.get_position())
+        self.translation = translation
+
+    def __str__(self):
+        x, y = self.get_position()
+        tx, ty = self.translation
+        return '<FlickGesture at (%s, %s) translation=(%s, %s)>' \
+               % (x, y, tx, ty)
+
+    def get_translation(self):
+        return self.translation
+
+
 class TransformationTracker(GestureTracker):
     """
     Tracker for linear transformations. This implementation detects rotation,
     scaling and translation using the centroid of all touch points.
     """
-    supported_gestures = [RotationGesture, PinchGesture, DragGesture]
+    supported_gestures = [RotationGesture, PinchGesture, DragGesture,
+                          FlickGesture]
 
     def __init__(self, area):
         super(TransformationTracker, self).__init__(area)
@@ -151,9 +170,14 @@ class TransformationTracker(GestureTracker):
     def on_point_up(self, event):
         if event.point in self.points:
             self.points.remove(event.point)
+
+            if not self.points:
+                self.trigger(FlickGesture(event, self.centroid,
+                                          self.centroid.translation()))
             self.update_centroid()
             event.stop_propagation()
 
+
     def invalidate_points(self):
         """
         Check if all points are still in the corresponding area, and remove

+ 22 - 4
tests/testapp.py

@@ -5,7 +5,7 @@ from threading import Thread
 from math import pi, tan
 
 import src as mt
-from utils import BoundingBoxArea
+from utils import BoundingBoxArea, Flick, FlickThread
 
 
 RED = 1, 0, 0
@@ -42,6 +42,20 @@ class Polygon(BoundingBoxArea):
         self.on_drag(self.handle_drag)
         self.on_pinch(self.handle_pinch)
         self.on_rotate(self.handle_rotate)
+        self.on_flick(self.handle_flick)
+
+    def flick_drag(self, amt):
+        tx, ty = self.flick_direction
+        self.translate(tx * amt, ty * amt)
+        refresh()
+
+    def handle_flick(self, g):
+        trans = g.get_translation()
+
+        print trans.distance_to((0, 0))
+        if trans.distance_to((0, 0)) > 10:
+            self.flick_direction = trans
+            flicks.add(Flick(self.flick_drag, 0.7, 0.4))
 
     def handle_drag(self, g):
         tx, ty = g.get_translation()
@@ -217,7 +231,7 @@ def quit(*args):
 
 
 # Global variables
-window = cr = root = overlay = None
+window = cr = root = overlay = flicks = None
 draw_objects = []
 touch_hands = []
 
@@ -247,7 +261,7 @@ def on_show(window):
     draw_objects.append(triangle)
     root.add_area(triangle)
 
-    # Overlay catches basic events
+    # Overlay catches finger events to be able to draw touch points
     def handle_down(gesture):
         if gesture.is_first():
             touch_hands.append(gesture.get_hand())
@@ -279,7 +293,6 @@ if __name__ == '__main__':
 
     fullscreen = args.fullscreen
 
-
     # Create a window with a Cairo context in it and a multi-touch area
     # syncronized with it
     create_context_window(800, 600, on_show)
@@ -290,6 +303,11 @@ if __name__ == '__main__':
     mt_thread.daemon = True
     mt_thread.start()
 
+    # Flick movement is also handled in a separate thread
+    flicks = FlickThread()
+    flicks.daemon = True
+    flicks.start()
+
     # Initialize threads in GTK so that the thread started above will work
     gtk.gdk.threads_init()
 

+ 41 - 0
tests/utils.py

@@ -1,4 +1,8 @@
+from __future__ import division
+from time import sleep
+from threading import Thread
 from numpy import array, diag, dot, cos, sin
+
 from src import RectangularArea
 
 
@@ -33,3 +37,40 @@ class BoundingBoxArea(RectangularArea):
         if min_x or min_y:
             self.translate(min_x, min_y)
             self.translate_points(-min_x, -min_y)
+
+
+FLICK_UPDATE_RATE = 30
+
+
+class Flick(object):
+    def __init__(self, callback, seconds, start_amount=1.0):
+        self.callback = callback
+        self.amount = start_amount
+        self.iterations = int(seconds * FLICK_UPDATE_RATE)
+        self.reduce_rate = start_amount / self.iterations
+
+    def iteration(self):
+        self.callback(self.amount)
+        self.amount -= self.reduce_rate
+        self.iterations -= 1
+        return self.is_not_done()
+
+    def is_not_done(self):
+        return self.iterations > 0
+
+    def is_done(self):
+        return self.iterations <= 0
+
+
+class FlickThread(Thread):
+    def __init__(self):
+        super(FlickThread, self).__init__()
+        self.flicks = []
+
+    def run(self):
+        while True:
+            self.flicks = filter(Flick.iteration, self.flicks)
+            sleep(1 / FLICK_UPDATE_RATE)
+
+    def add(self, flick):
+        self.flicks.append(flick)