Commit c50325c1 authored by Taddeus Kroes's avatar Taddeus Kroes

Fixed rotation- and pinch-detection by keeping their amounts in global variables.

parent 9eceb62b
...@@ -71,6 +71,12 @@ class TouchPoint(object): ...@@ -71,6 +71,12 @@ class TouchPoint(object):
def xy(self): def xy(self):
return self.x, self.y return self.x, self.y
def dx(self):
return self.x - self.px
def dy(self):
return self.y- self.py
def update(self, x, y): def update(self, x, y):
self.update_time = time.time() self.update_time = time.time()
self.px = self.x self.px = self.x
...@@ -78,43 +84,21 @@ class TouchPoint(object): ...@@ -78,43 +84,21 @@ class TouchPoint(object):
self.x = x self.x = x
self.y = y self.y = y
def distance_to(self, other_x, other_y):
return distance((self.x, self.y), (other_x, other_y))
def distance_to_prev(self):
return self.distance_to(self.px, self.py)
def set_centroid(self, cx, cy):
self.pinch = self.distance_to(cx, cy)
self.angle = atan2(cy - self.y, self.x - cx)
if self.pinch != None:
self.old_pinch = self.pinch
self.old_angle = self.angle
self.pinch = pinch
self.angle = angle
else:
self.old_pinch = self.pinch = pinch
self.old_angle = self.angle = angle
def angle_diff(self):
return self.angle - self.old_angle
def pinch_diff(self):
return self.pinch - self.old_pinch
def dx(self):
return self.x - self.px
def dy(self):
return self.y - self.py
def down_time(self): def down_time(self):
return time.time() - self.start_time return time.time() - self.start_time
def angle(self, cx, cy):
return atan2(cy - self.y, self.x - cx)
def distance(self, other_x, other_y):
return distance((self.x, self.y), (other_x, other_y))
def is_tap(self): def is_tap(self):
return self.distance_to_prev() < TAP_TIME \ return time.time() - self.update_time < TAP_TIME \
and self.distance_to(self.start_x, self.start_y) < TAP_DISTANCE and self.distance(self.start_x, self.start_y) < TAP_DISTANCE
def distance_to_prev(self):
return self.distance(self.px, self.py)
def is_stationary(self): def is_stationary(self):
return self.distance_to_prev() < DIST_THRESHOLD return self.distance_to_prev() < DIST_THRESHOLD
...@@ -134,10 +118,12 @@ class MultiTouchListener(Logger): ...@@ -134,10 +118,12 @@ class MultiTouchListener(Logger):
self.points = [] self.points = []
# Put centroid outside screen to prevent misinterpretation # Put centroid outside screen to prevent misinterpretation
self.centroid = (-1., -1.) self.centroid = -1., -1.
self.server = TuioServer2D(self, verbose=tuio_verbose) self.server = TuioServer2D(self, verbose=tuio_verbose)
self.angle = self.pinch = None
def point_down(self, sid, x, y): def point_down(self, sid, x, y):
""" """
Called by TUIO listener when a new touch point is created, triggers a Called by TUIO listener when a new touch point is created, triggers a
...@@ -177,7 +163,7 @@ class MultiTouchListener(Logger): ...@@ -177,7 +163,7 @@ class MultiTouchListener(Logger):
t = time.time() t = time.time()
if t - self.last_tap_time < TAP_TIMEOUT \ if t - self.last_tap_time < TAP_TIMEOUT \
and p.distance_to(*self.last_tap.xy) < DOUBLE_TAP_DISTANCE: and p.distance(*self.last_tap.xy) < DOUBLE_TAP_DISTANCE:
self.trigger(DoubleTap(p.x, p.y)) self.trigger(DoubleTap(p.x, p.y))
self.last_tap = None self.last_tap = None
self.last_tap_time = 0 self.last_tap_time = 0
...@@ -200,7 +186,7 @@ class MultiTouchListener(Logger): ...@@ -200,7 +186,7 @@ class MultiTouchListener(Logger):
""" """
p = self.find_point(sid) p = self.find_point(sid)
if p.distance_to(x, y) > DIST_THRESHOLD: if p.distance(x, y) > DIST_THRESHOLD:
p.update(x, y) p.update(x, y)
self.trigger(MoveEvent(p)) self.trigger(MoveEvent(p))
self.points_changed = True self.points_changed = True
...@@ -215,33 +201,77 @@ class MultiTouchListener(Logger): ...@@ -215,33 +201,77 @@ class MultiTouchListener(Logger):
if l < 2 or ('pinch' not in self.handlers \ if l < 2 or ('pinch' not in self.handlers \
and 'rotate' not in self.handlers): and 'rotate' not in self.handlers):
self.set_state(None, None)
return return
self.calc_state()
rotation, pinch = self.state_diff()
cx, cy = self.centroid cx, cy = self.centroid
#rotation = pinch = 0
#for p in self.points: if rotation:
# da = p.angle_diff() self.trigger(Rotate(cx, cy, rotation, l))
# # Assert that angle is in [-pi, pi] if pinch:
# if da > pi: self.trigger(Pinch(cx, cy, pinch, l))
# da -= 2 * pi
# elif da < pi:
# da += 2 * pi
# rotation += da def calc_state(self):
# pinch += p.pinch_diff() l = len(self.points)
cx, cy = self.centroid
angle = reduce(add, [p.angle(cx, cy) for p in self.points]) / l
distance = reduce(add, [p.distance(cx, cy) for p in self.points]) / l
angles, pinches = zip(*[(p.angle_diff(), p.pinch_diff()) if self.angle == None:
for p in self.points]) self.set_state(angle, distance)
rotation = reduce(add, angles) self.set_prev_state()
pinch = reduce(add, pinches) else:
self.set_prev_state()
self.set_state(angle, distance)
if rotation: def set_state(self, angle, distance):
self.trigger(Rotate(cx, cy, rotation / l, l)) self.angle = angle
self.distance = distance
if pinch: def set_prev_state(self):
self.trigger(Pinch(cx, cy, pinch / l * 2, l)) self.prev_angle = self.angle
self.prev_distance = self.distance
def state_diff(self):
da = self.angle - self.prev_angle
# Assert that angle is in [-pi, pi]
#if da > pi:
# da %= 2 * pi
#elif da < -pi:
# da %= -2 * pi
return da, self.distance / self.prev_distance
def update_centroid(self):
"""
Calculate the centroid of all current touch points.
"""
self.old_centroid = self.centroid
l = len(self.points)
# If there are no touch points, move the centroid to outside the screen
if not l:
self.centroid = -1., -1.
return
# Only use stationary points, if any
use = filter(TouchPoint.is_stationary, self.points)
if not len(use):
use = self.points
cx, cy = zip(*[(p.x, p.y) for p in use])
self.centroid = reduce(add, cx, 0) / l, reduce(add, cy, 0) / l
def centroid_movement(self):
cx, cy = self.centroid
ocx, ocy = self.old_centroid
return cx - ocx, cy - ocy
def detect_pan(self): def detect_pan(self):
""" """
...@@ -254,9 +284,9 @@ class MultiTouchListener(Logger): ...@@ -254,9 +284,9 @@ class MultiTouchListener(Logger):
return False return False
m = MAX_MULTI_DRAG_DISTANCE m = MAX_MULTI_DRAG_DISTANCE
clustered = l == 1 or all([p.distance_to(*self.centroid) <= m \ clustered = l == 1 or all([p.distance(*self.centroid) <= m \
for p in self.points]) for p in self.points])
directions = [(cmp(p.dx(), 0), cmp(p.dy(), 0)) \ directions = [(cmp(p.dx(), 0), cmp(p.dy(), 0))
for p in self.points] for p in self.points]
if not clustered or not any(map(all, zip(*directions))): if not clustered or not any(map(all, zip(*directions))):
...@@ -282,15 +312,6 @@ class MultiTouchListener(Logger): ...@@ -282,15 +312,6 @@ class MultiTouchListener(Logger):
if index: if index:
return -1, None return -1, None
def detect_pinch(self, moved):
cx, cy = self.centroid
dist = moved.distance_to(cx, cy)
old_dist = distance((moved.px, moved.py), self.centroid)
if abs(dist - old_dist) > DIST_THRESHOLD:
self.trigger(Pinch(cx, cy, dist / old_dist,
len(self.points)))
def detect_single_tap(self): def detect_single_tap(self):
""" """
Check if a single tap event should be triggered by checking is the last Check if a single tap event should be triggered by checking is the last
...@@ -301,31 +322,6 @@ class MultiTouchListener(Logger): ...@@ -301,31 +322,6 @@ class MultiTouchListener(Logger):
self.last_tap = None self.last_tap = None
self.last_tap_time = 0 self.last_tap_time = 0
def update_centroid(self):
"""
Calculate the centroid of all current touch points.
"""
self.old_centroid = self.centroid
l = len(self.points)
# If there are no touch points, move the entroid to outside the screen
if not l:
self.centroid = (-1., -1.)
return
cx, cy = zip(*[(p.x, p.y) for p in self.points])
self.centroid = (reduce(add, cx, 0) / l, reduce(add, cy, 0) / l)
# Update angle and pinch of all touch points
for p in self.points:
p.set_centroid(*self.centroid)
def centroid_movement(self):
cx, cy = self.centroid
ocx, ocy = self.old_centroid
return cx - ocx, cy - ocy
def detect_gestures(self): def detect_gestures(self):
""" """
Detect if any gestures have occured in the past gesture frame. This Detect if any gestures have occured in the past gesture frame. This
...@@ -432,6 +428,7 @@ if __name__ == '__main__': ...@@ -432,6 +428,7 @@ if __name__ == '__main__':
listener.bind('single_tap', tap, 1) listener.bind('single_tap', tap, 1)
listener.bind('double_tap', tap, 2) listener.bind('double_tap', tap, 2)
listener.bind('rotate', lambda e: 0) listener.bind('rotate', lambda e: 0)
listener.bind('pinch', lambda e: 0)
try: try:
listener.start() listener.start()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment