Prechádzať zdrojové kódy

Started fixing cairo test program.

UVA Multi-touch 13 rokov pred
rodič
commit
3c8c49a4fa
7 zmenil súbory, kde vykonal 103 pridanie a 86 odobranie
  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.parent = None
         self.children = []
         self.children = []
 
 
+        self.delegate_queue = {}
+
     def get_root_area(self):
     def get_root_area(self):
         """
         """
         Traverse up in the area tree to find the root area.
         Traverse up in the area tree to find the root area.
@@ -36,24 +38,24 @@ class Area(Positionable, Logger):
 
 
         return self
         return self
 
 
-    def get_screen_position(self):
+    def get_screen_offset(self):
         """
         """
         Get the position relative to the screen.
         Get the position relative to the screen.
         """
         """
         if not self.parent:
         if not self.parent:
             return self.get_position()
             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
         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.
         Get the position relative to the root area.
         """
         """
         if not self.parent:
         if not self.parent:
             return 0, 0
             return 0, 0
 
 
-        ox, oy = self.parent.get_root_position()
+        ox, oy = self.parent.get_root_offset()
         return ox + self.x, oy + self.y
         return ox + self.x, oy + self.y
 
 
     def get_offset(self, offset_area):
     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
         propagation, return so that its siblings and the parent area will not
         delegate the event to their trackers.
         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:
         if self.children:
             # Delegate to children in reverse order because areas that are
             # Delegate to children in reverse order because areas that are
             # added later, should be placed over previously added siblings
             # 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):
     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
         propagate it to the parent area (if any). Propagation can be stopped by
         a tracker.
         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:
         for tracker in self.trackers:
             tracker.handle_event(event)
             tracker.handle_event(event)
@@ -211,6 +216,8 @@ class Area(Positionable, Logger):
                 return
                 return
 
 
         if self.parent and not event.is_propagation_stopped():
         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)
             self.parent.propagate_event(event)
 
 
     def handle_gesture(self, gesture):
     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
         Delegate an event that has been triggered by the event driver to the
         area tree.
         area tree.
         """
         """
-        self.root_area.delegate_event(event)
+        if self.root_area.contains_event(event):
+            self.root_area.delegate_event(event)
 
 
     def start(self):
     def start(self):
         """
         """

+ 0 - 17
src/event.py

@@ -18,7 +18,6 @@ class Event(Positionable):
         super(Event, self).__init__(*touch_object)
         super(Event, self).__init__(*touch_object)
         self.touch_object = touch_object
         self.touch_object = touch_object
         self.stopped = self.stopped_immidiate = False
         self.stopped = self.stopped_immidiate = False
-        self.area = None
 
 
     def __getattr__(self, name):
     def __getattr__(self, name):
         if name in OBJECT_NAMES \
         if name in OBJECT_NAMES \
@@ -28,22 +27,6 @@ class Event(Positionable):
         raise AttributeError("'%s' object has no attribute '%s'"
         raise AttributeError("'%s' object has no attribute '%s'"
                              % (self.__class__.__name__, name))
                              % (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):
     def get_type(self):
         return self._type
         return self._type
 
 

+ 15 - 6
src/geometry.py

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

+ 1 - 1
src/trackers/tap.py

@@ -86,7 +86,7 @@ class TapTracker(GestureTracker):
         self.last_tap = None
         self.last_tap = None
 
 
     def on_point_down(self, event):
     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):
     def on_point_move(self, event):
         oid = event.point.get_id()
         oid = event.point.get_id()

+ 17 - 20
src/trackers/transform.py

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

+ 45 - 25
tests/cairotest.py

@@ -8,54 +8,70 @@ from threading import Thread
 import src as mt
 import src as mt
 
 
 
 
-def quit(*args):
-    gtk.main_quit()
-
-
 class Rectangle(mt.RectangularArea):
 class Rectangle(mt.RectangularArea):
     def __init__(self, x, y, width, height, color=(1, 0, 0)):
     def __init__(self, x, y, width, height, color=(1, 0, 0)):
         super(Rectangle, self).__init__(x, y, width, height)
         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.color = color
         self.t = cairo.Matrix()
         self.t = cairo.Matrix()
-        self.t.translate(*self)
+        self.t.translate(x, y)
 
 
         self.on_drag(self.move)
         self.on_drag(self.move)
         self.on_pinch(self.resize)
         self.on_pinch(self.resize)
-        #self.on_rotate(self.rotate)
+        self.on_rotate(self.rotate)
 
 
     def move(self, g):
     def move(self, g):
+        print 'move:', g
         self.translate(*g.get_translation())
         self.translate(*g.get_translation())
-        print 'drag rectangle', self
+        self.ttrans(*g.get_translation())
         refresh()
         refresh()
 
 
     def resize(self, g):
     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()
         refresh()
 
 
     def rotate(self, g):
     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()
         refresh()
 
 
-    def get_transformation_matrix(self):
+    def ttrans(self, tx, ty):
         t = cairo.Matrix()
         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):
     def draw(self, cr):
-        w, h = self.get_size()
         cr.transform(self.t)
         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.set_source_rgb(*self.color)
         cr.fill()
         cr.fill()
 
 
@@ -134,6 +150,10 @@ def refresh():
     window.queue_draw()
     window.queue_draw()
 
 
 
 
+def quit(*args):
+    gtk.main_quit()
+
+
 # Initialization
 # Initialization
 window = cr = root = None
 window = cr = root = None
 draw_objects = []
 draw_objects = []