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):
def xy(self):
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):
self.update_time = time.time()
self.px = self.x
......@@ -78,43 +84,21 @@ class TouchPoint(object):
self.x = x
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):
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):
return self.distance_to_prev() < TAP_TIME \
and self.distance_to(self.start_x, self.start_y) < TAP_DISTANCE
return time.time() - self.update_time < TAP_TIME \
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):
return self.distance_to_prev() < DIST_THRESHOLD
......@@ -134,10 +118,12 @@ class MultiTouchListener(Logger):
self.points = []
# Put centroid outside screen to prevent misinterpretation
self.centroid = (-1., -1.)
self.centroid = -1., -1.
self.server = TuioServer2D(self, verbose=tuio_verbose)
self.angle = self.pinch = None
def point_down(self, sid, x, y):
"""
Called by TUIO listener when a new touch point is created, triggers a
......@@ -177,7 +163,7 @@ class MultiTouchListener(Logger):
t = time.time()
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.last_tap = None
self.last_tap_time = 0
......@@ -200,7 +186,7 @@ class MultiTouchListener(Logger):
"""
p = self.find_point(sid)
if p.distance_to(x, y) > DIST_THRESHOLD:
if p.distance(x, y) > DIST_THRESHOLD:
p.update(x, y)
self.trigger(MoveEvent(p))
self.points_changed = True
......@@ -215,33 +201,77 @@ class MultiTouchListener(Logger):
if l < 2 or ('pinch' not in self.handlers \
and 'rotate' not in self.handlers):
self.set_state(None, None)
return
self.calc_state()
rotation, pinch = self.state_diff()
cx, cy = self.centroid
#rotation = pinch = 0
#for p in self.points:
# da = p.angle_diff()
if rotation:
self.trigger(Rotate(cx, cy, rotation, l))
# # Assert that angle is in [-pi, pi]
# if da > pi:
# da -= 2 * pi
# elif da < pi:
# da += 2 * pi
if pinch:
self.trigger(Pinch(cx, cy, pinch, l))
# rotation += da
# pinch += p.pinch_diff()
def calc_state(self):
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())
for p in self.points])
rotation = reduce(add, angles)
pinch = reduce(add, pinches)
if self.angle == None:
self.set_state(angle, distance)
self.set_prev_state()
else:
self.set_prev_state()
self.set_state(angle, distance)
if rotation:
self.trigger(Rotate(cx, cy, rotation / l, l))
def set_state(self, angle, distance):
self.angle = angle
self.distance = distance
if pinch:
self.trigger(Pinch(cx, cy, pinch / l * 2, l))
def set_prev_state(self):
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):
"""
......@@ -254,9 +284,9 @@ class MultiTouchListener(Logger):
return False
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])
directions = [(cmp(p.dx(), 0), cmp(p.dy(), 0)) \
directions = [(cmp(p.dx(), 0), cmp(p.dy(), 0))
for p in self.points]
if not clustered or not any(map(all, zip(*directions))):
......@@ -282,15 +312,6 @@ class MultiTouchListener(Logger):
if index:
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):
"""
Check if a single tap event should be triggered by checking is the last
......@@ -301,31 +322,6 @@ class MultiTouchListener(Logger):
self.last_tap = None
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):
"""
Detect if any gestures have occured in the past gesture frame. This
......@@ -432,6 +428,7 @@ if __name__ == '__main__':
listener.bind('single_tap', tap, 1)
listener.bind('double_tap', tap, 2)
listener.bind('rotate', lambda e: 0)
listener.bind('pinch', lambda e: 0)
try:
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