ソースを参照

Started fixing cairo test program.

UVA Multi-touch 13 年 前
コミット
3c8c49a4fa
7 ファイル変更103 行追加86 行削除
  1. 23 16
      src/area.py
  2. 2 1
      src/driver.py
  3. 0 17
      src/event.py
  4. 15 6
      src/geometry.py
  5. 1 1
      src/trackers/tap.py
  6. 17 20
      src/trackers/transform.py
  7. 45 25
      tests/cairotest.py

+ 23 - 16
src/area.py

@@ -27,6 +27,8 @@ class Area(Positionable, Logger):
         self.parent = None
         self.children = []
 
+        self.delegate_queue = {}
+
     def get_root_area(self):
         """
         Traverse up in the area tree to find the root area.
@@ -36,24 +38,24 @@ class Area(Positionable, Logger):
 
         return self
 
-    def get_screen_position(self):
+    def get_screen_offset(self):
         """
         Get the position relative to the screen.
         """
         if not self.parent:
             return self.get_position()
 
-        ox, oy = self.parent.get_screen_position()
+        ox, oy = self.parent.get_screen_offset()
         return ox + self.x, oy + self.y
 
-    def get_root_position(self):
+    def get_root_offset(self):
         """
         Get the position relative to the root area.
         """
         if not self.parent:
             return 0, 0
 
-        ox, oy = self.parent.get_root_position()
+        ox, oy = self.parent.get_root_offset()
         return ox + self.x, oy + self.y
 
     def get_offset(self, offset_area):
@@ -178,23 +180,19 @@ class Area(Positionable, Logger):
         propagation, return so that its siblings and the parent area will not
         delegate the event to their trackers.
         """
-        child_found = False
+        event.add_offset(*self.get_position())
+        #print 'delegated in %s: %s' % (self, event)
 
         if self.children:
             # Delegate to children in reverse order because areas that are
             # added later, should be placed over previously added siblings
-            for child in reversed(self.children):
-                event.set_area(self)
-
-                if child.contains_event(event):
-                    child_found = True
-                    child.delegate_event(event)
+            delegate_to = [c for c in self.children
+                           if c.contains_event(event)]
 
-                    if event.is_propagation_stopped():
-                        return
+            if delegate_to:
+                self.delegate_queue[event] = delegate_to
 
-        if not child_found:
-            self.propagate_event(event)
+        self.propagate_event(event)
 
     def propagate_event(self, event):
         """
@@ -202,7 +200,14 @@ class Area(Positionable, Logger):
         propagate it to the parent area (if any). Propagation can be stopped by
         a tracker.
         """
-        event.set_area(self)
+        if event in self.delegate_queue:
+            child = self.delegate_queue[event].pop()
+
+            if not self.delegate_queue[event]:
+                del self.delegate_queue[event]
+
+            child.delegate_event(event)
+            return
 
         for tracker in self.trackers:
             tracker.handle_event(event)
@@ -211,6 +216,8 @@ class Area(Positionable, Logger):
                 return
 
         if self.parent and not event.is_propagation_stopped():
+            event.add_offset(-self.x, -self.y)
+            #print 'propagated to %s: %s' % (self.parent, event)
             self.parent.propagate_event(event)
 
     def handle_gesture(self, gesture):

+ 2 - 1
src/driver.py

@@ -21,7 +21,8 @@ class EventDriver(Logger):
         Delegate an event that has been triggered by the event driver to the
         area tree.
         """
-        self.root_area.delegate_event(event)
+        if self.root_area.contains_event(event):
+            self.root_area.delegate_event(event)
 
     def start(self):
         """

+ 0 - 17
src/event.py

@@ -18,7 +18,6 @@ class Event(Positionable):
         super(Event, self).__init__(*touch_object)
         self.touch_object = touch_object
         self.stopped = self.stopped_immidiate = False
-        self.area = None
 
     def __getattr__(self, name):
         if name in OBJECT_NAMES \
@@ -28,22 +27,6 @@ class Event(Positionable):
         raise AttributeError("'%s' object has no attribute '%s'"
                              % (self.__class__.__name__, name))
 
-    def set_area(self, area):
-        self.area = area
-
-    def get_area(self):
-        return self.area
-
-    def get_root_position(self):
-        return self.get_offset(self.area.get_root_area())
-
-    def get_position(self):
-        return self.get_offset(self.area)
-
-    def get_offset(self, area):
-        ox, oy = area.get_screen_position()
-        return self.x - ox, self.y - oy
-
     def get_type(self):
         return self._type
 

+ 15 - 6
src/geometry.py

@@ -19,7 +19,7 @@ class Positionable(object):
         return repr(self)
 
     def __iter__(self):
-        return iter((self.x, self.y))
+        return iter(self.get_position())
 
     def __add__(self, other):
         ox, oy = other
@@ -38,19 +38,24 @@ class Positionable(object):
     def __pow__(self, exp):
         return Positionable(self.x ** exp, self.y ** exp)
 
+    def get_position(self):
+        return self.x, self.y
+
     def set_position(self, x, y):
         self.x = x
         self.y = y
 
-    def get_position(self):
-        return self.x, self.y
+    def add_offset(self, add_x, add_y):
+        self.x -= add_x
+        self.y -= add_y
 
     def distance_to(self, other):
         """
         Calculate the Pythagorian distance from this positionable to another.
         """
+        x, y = self.get_position()
         ox, oy = other
-        return ((ox - self.x) ** 2 + (oy - self.y) ** 2) ** .5
+        return ((ox - x) ** 2 + (oy - y) ** 2) ** .5
 
     def translate(self, x, y):
         self.set_position(self.x + x, self.y + y)
@@ -78,6 +83,10 @@ class MovingPositionable(Positionable):
 
         Positionable.set_position(self, x, y)
 
+    def add_offset(self, add_x, add_y):
+        Positionable.add_offset(self, add_x, add_y)
+        self.prev.add_offset(add_x, add_y)
+
     def get_previous_position(self):
         return self.prev
 
@@ -106,9 +115,9 @@ class MovingPositionable(Positionable):
         positionable.
         """
         px, py = self.prev
-        return Positionable(self.x - px, self.y - py)
+        return self.x - px, self.y - py
 
-    def movement_distance(self):
+    def translation_distance(self):
         return self.distance_to(self.prev)
 
 

+ 1 - 1
src/trackers/tap.py

@@ -86,7 +86,7 @@ class TapTracker(GestureTracker):
         self.last_tap = None
 
     def on_point_down(self, event):
-        self.reg[event.point.get_id()] = time.time(), event
+        self.reg[event.point.get_id()] = time.time(), event.get_position()
 
     def on_point_move(self, event):
         oid = event.point.get_id()

+ 17 - 20
src/trackers/transform.py

@@ -10,10 +10,11 @@ class RotationGesture(Gesture, Positionable):
     """
     _type = 'rotate'
 
-    def __init__(self, event, centroid, angle):
+    def __init__(self, event, centroid, angle, n=1):
         Gesture.__init__(self, event)
         Positionable.__init__(self, *centroid.get_position())
         self.angle = angle
+        self.n = n
 
     def __str__(self):
         return '<RotationGesture at (%s, %s) angle=%s>' \
@@ -30,10 +31,11 @@ class PinchGesture(Gesture, Positionable):
     """
     _type = 'pinch'
 
-    def __init__(self, event, centroid, scale):
+    def __init__(self, event, centroid, scale, n=1):
         Gesture.__init__(self, event)
         Positionable.__init__(self, *centroid.get_position())
         self.scale = scale
+        self.n = n
 
     def __str__(self):
         return '<PinchGesture at (%s, %s) scale=%s>' \
@@ -80,11 +82,9 @@ class TransformationTracker(GestureTracker):
         self.points = []
 
         # Current and previous centroid of all touch points
-        self.prev_centroid = self.centroid = None
+        self.centroid = None
 
     def update_centroid(self):
-        self.prev_centroid = self.centroid
-
         if not self.points:
             self.centroid = None
             return
@@ -102,9 +102,6 @@ class TransformationTracker(GestureTracker):
         else:
             self.centroid = MovingPositionable(x, y)
 
-        #wx, wy = self.area.get_screen_offset()
-        #self.centroid.translate(-wx, -wy)
-
     def on_point_down(self, event):
         self.points.append(event.point)
         self.update_centroid()
@@ -118,26 +115,26 @@ class TransformationTracker(GestureTracker):
         l = len(self.points)
 
         if l > 1:
+            offset_centroid = self.centroid - self.area.get_screen_offset()
+            print self.centroid, self.area, offset_centroid
+
             # Rotation (around the previous centroid)
             rotation = point.rotation_around(self.centroid) / l
-            self.trigger(RotationGesture(event, self.centroid, rotation))
+            self.trigger(RotationGesture(event, offset_centroid, rotation, l))
 
             # Scale
-            prev = point.get_previous_position().distance_to(self.centroid)
-            dist = point.distance_to(self.centroid)
+            prev = self.centroid.distance_to(point.get_previous_position())
+            dist = self.centroid.distance_to(point)
             dist = prev + (dist - prev) / l
             scale = dist / prev
-            self.trigger(PinchGesture(event, self.centroid, scale))
+            self.trigger(PinchGesture(event, offset_centroid, scale, l))
 
-            # Update centroid before movement can be detected
-            self.update_centroid()
+        # Update centroid before movement can be detected
+        self.update_centroid()
 
-            # Movement using multiple touch points
-            self.trigger(DragGesture(event, self.centroid,
-                                     self.centroid.translation(), l))
-        else:
-            # Movement using one touch point
-            self.trigger(DragGesture(event, point, point.translation()))
+        # Movement using multiple touch points
+        self.trigger(DragGesture(event, self.centroid,
+                                 self.centroid.translation(), l))
 
     def on_point_up(self, event):
         if event.point not in self.points:

+ 45 - 25
tests/cairotest.py

@@ -8,54 +8,70 @@ from threading import Thread
 import src as mt
 
 
-def quit(*args):
-    gtk.main_quit()
-
-
 class Rectangle(mt.RectangularArea):
     def __init__(self, x, y, width, height, color=(1, 0, 0)):
         super(Rectangle, self).__init__(x, y, width, height)
-        self.angle = 1.0
+        self.w = width
+        self.h = height
+        self.scale = 1
+        self.angle = 0
         self.color = color
         self.t = cairo.Matrix()
-        self.t.translate(*self)
+        self.t.translate(x, y)
 
         self.on_drag(self.move)
         self.on_pinch(self.resize)
-        #self.on_rotate(self.rotate)
+        self.on_rotate(self.rotate)
 
     def move(self, g):
+        print 'move:', g
         self.translate(*g.get_translation())
-        print 'drag rectangle', self
+        self.ttrans(*g.get_translation())
         refresh()
 
     def resize(self, g):
-        print 'resize:', g.get_scale()
-        self.t.scale(g.get_scale(), g.get_scale())
+        print 'resize:', g
+
+        x, y = g.get_position()
+        scale = g.get_scale()
+        self.ttrans(x, y)
+        self.tscale(scale)
+        self.ttrans(-x, -y)
+
+        self.width *= scale
+        self.height *= scale
+
         refresh()
 
     def rotate(self, g):
-        w, h = self.get_size()
-        #self.t.translate(-w / 2, -h / 2)
-        self.t.rotate(-g.get_angle())
-        #self.t.translate(w / 2, h / 2)
-        print tuple(g)
-        x, y = g * .01
-        print x, y
-        #self.rot.translate(-x, -y)
+        print 'rotate:', g
+
+        x, y = g.get_position()
+        self.ttrans(x, y)
+        self.trot(-g.get_angle())
+        self.ttrans(-x, -y)
+
         refresh()
 
-    def get_transformation_matrix(self):
+    def ttrans(self, tx, ty):
         t = cairo.Matrix()
-        t.translate(*self)
-        t.rotate(self.angle)
-        t.scale(self.scale, self.scale)
-        return t
+        t.translate(tx, ty)
+        self.t = t * self.t
+        #self.t = self.t * t
+
+    def tscale(self, s):
+        t = cairo.Matrix()
+        t.scale(s, s)
+        self.t = t * self.t
+
+    def trot(self, a):
+        t = cairo.Matrix()
+        t.rotate(a)
+        self.t = t * self.t
 
     def draw(self, cr):
-        w, h = self.get_size()
         cr.transform(self.t)
-        cr.rectangle(0, 0, w, h)
+        cr.rectangle(0, 0, self.w, self.h)
         cr.set_source_rgb(*self.color)
         cr.fill()
 
@@ -134,6 +150,10 @@ def refresh():
     window.queue_draw()
 
 
+def quit(*args):
+    gtk.main_quit()
+
+
 # Initialization
 window = cr = root = None
 draw_objects = []