Procházet zdrojové kódy

Added linear flick movement to test application.

UVA Multi-touch před 13 roky
rodič
revize
32a381b9f5
4 změnil soubory, kde provedl 89 přidání a 6 odebrání
  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.
         positionable.
         """
         """
         px, py = self.prev
         px, py = self.prev
-        return self.x - px, self.y - py
+        return Positionable(self.x - px, self.y - py)
 
 
     def translation_distance(self):
     def translation_distance(self):
         return self.distance_to(self.prev)
         return self.distance_to(self.prev)

+ 25 - 1
src/trackers/transform.py

@@ -68,12 +68,31 @@ class DragGesture(Gesture, Positionable):
         return self.translation
         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):
 class TransformationTracker(GestureTracker):
     """
     """
     Tracker for linear transformations. This implementation detects rotation,
     Tracker for linear transformations. This implementation detects rotation,
     scaling and translation using the centroid of all touch points.
     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):
     def __init__(self, area):
         super(TransformationTracker, self).__init__(area)
         super(TransformationTracker, self).__init__(area)
@@ -151,9 +170,14 @@ class TransformationTracker(GestureTracker):
     def on_point_up(self, event):
     def on_point_up(self, event):
         if event.point in self.points:
         if event.point in self.points:
             self.points.remove(event.point)
             self.points.remove(event.point)
+
+            if not self.points:
+                self.trigger(FlickGesture(event, self.centroid,
+                                          self.centroid.translation()))
             self.update_centroid()
             self.update_centroid()
             event.stop_propagation()
             event.stop_propagation()
 
 
+
     def invalidate_points(self):
     def invalidate_points(self):
         """
         """
         Check if all points are still in the corresponding area, and remove
         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
 from math import pi, tan
 
 
 import src as mt
 import src as mt
-from utils import BoundingBoxArea
+from utils import BoundingBoxArea, Flick, FlickThread
 
 
 
 
 RED = 1, 0, 0
 RED = 1, 0, 0
@@ -42,6 +42,20 @@ class Polygon(BoundingBoxArea):
         self.on_drag(self.handle_drag)
         self.on_drag(self.handle_drag)
         self.on_pinch(self.handle_pinch)
         self.on_pinch(self.handle_pinch)
         self.on_rotate(self.handle_rotate)
         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):
     def handle_drag(self, g):
         tx, ty = g.get_translation()
         tx, ty = g.get_translation()
@@ -217,7 +231,7 @@ def quit(*args):
 
 
 
 
 # Global variables
 # Global variables
-window = cr = root = overlay = None
+window = cr = root = overlay = flicks = None
 draw_objects = []
 draw_objects = []
 touch_hands = []
 touch_hands = []
 
 
@@ -247,7 +261,7 @@ def on_show(window):
     draw_objects.append(triangle)
     draw_objects.append(triangle)
     root.add_area(triangle)
     root.add_area(triangle)
 
 
-    # Overlay catches basic events
+    # Overlay catches finger events to be able to draw touch points
     def handle_down(gesture):
     def handle_down(gesture):
         if gesture.is_first():
         if gesture.is_first():
             touch_hands.append(gesture.get_hand())
             touch_hands.append(gesture.get_hand())
@@ -279,7 +293,6 @@ if __name__ == '__main__':
 
 
     fullscreen = args.fullscreen
     fullscreen = args.fullscreen
 
 
-
     # Create a window with a Cairo context in it and a multi-touch area
     # Create a window with a Cairo context in it and a multi-touch area
     # syncronized with it
     # syncronized with it
     create_context_window(800, 600, on_show)
     create_context_window(800, 600, on_show)
@@ -290,6 +303,11 @@ if __name__ == '__main__':
     mt_thread.daemon = True
     mt_thread.daemon = True
     mt_thread.start()
     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
     # Initialize threads in GTK so that the thread started above will work
     gtk.gdk.threads_init()
     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 numpy import array, diag, dot, cos, sin
+
 from src import RectangularArea
 from src import RectangularArea
 
 
 
 
@@ -33,3 +37,40 @@ class BoundingBoxArea(RectangularArea):
         if min_x or min_y:
         if min_x or min_y:
             self.translate(min_x, min_y)
             self.translate(min_x, min_y)
             self.translate_points(-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)