Commit 0fc618e5 authored by Taddeus Kroes's avatar Taddeus Kroes

Fixed rotation (finally).

parent 35a46583
...@@ -36,13 +36,19 @@ GESTURE_UPDATE_RATE = 60 ...@@ -36,13 +36,19 @@ GESTURE_UPDATE_RATE = 60
DIST_THRESHOLD = 1. / max(screen_size) DIST_THRESHOLD = 1. / max(screen_size)
def angle_mod(angle): def rotation(p0, p1):
if angle > pi: """
angle -= 2 * pi Calculate the relative rotation from p0 to p1 around (0, 0) in radians.
elif angle < -pi: """
angle += 2 * pi rot = atan2(*p1) - atan2(*p0)
return angle # Assert that the smallest possible rotation value is returned
if rot >= pi:
rot = 2 * pi - rot
elif rot <= -pi:
rot = -2 * pi - rot
return rot
def distance(a, b): def distance(a, b):
...@@ -114,21 +120,11 @@ class TouchPoint(object): ...@@ -114,21 +120,11 @@ class TouchPoint(object):
def is_stationary(self): def is_stationary(self):
return self.distance_to_prev() < DIST_THRESHOLD return self.distance_to_prev() < DIST_THRESHOLD
def angle_diff(self, cx, cy): def rotation_around(self, cx, cy):
angle = atan2(cy - self.y, self.x - cx) prev = self.px - cx, self.py - cy
current = self.x - cx, self.y - cy
if self.prev_angle == None:
delta = 0
elif self.prev_angle > 0 and angle < 0:
delta = -2 * pi - angle + self.prev_angle
elif self.prev_angle < 0 and angle > 0:
delta = 2 * pi - angle + self.prev_angle
else:
delta = angle - self.prev_angle
self.prev_angle = angle
return delta return rotation(prev, current)
class MultiTouchListener(Logger): class MultiTouchListener(Logger):
...@@ -146,11 +142,12 @@ class MultiTouchListener(Logger): ...@@ -146,11 +142,12 @@ class MultiTouchListener(Logger):
# Put centroid outside screen to prevent misinterpretation # Put centroid outside screen to prevent misinterpretation
self.centroid = -1., -1. self.centroid = -1., -1.
self.rot_centroid = -1., -1.
self.server = TuioServer2D(self, verbose=tuio_verbose) self.server = TuioServer2D(self, verbose=tuio_verbose)
self.angle = self.pinch = None self.angle = self.pinch = None
self.prev_pinch = None self.prev_dist = None
def point_down(self, sid, x, y): def point_down(self, sid, x, y):
""" """
...@@ -222,51 +219,43 @@ class MultiTouchListener(Logger): ...@@ -222,51 +219,43 @@ class MultiTouchListener(Logger):
def detect_rotation_and_pinch(self): def detect_rotation_and_pinch(self):
""" """
Rotation is the average angle change between each point and the Rotation is the average angle change between each point and the
centroid. Pinch is the average distance change from the points to the centroid. Pinch is the percentual change in average distance change
centroid. from the points to the centroid.
""" """
l = len(self.points) l = len(self.points)
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.prev_pinch = None self.prev_dist = None
return return
# Get the sum of all angle differences
l = len(self.points) l = len(self.points)
cx, cy = self.centroid cx, cy = self.centroid
#rcx, rcy = self.rot_centroid rotation = sum([p.rotation_around(cx, cy) for p in self.points]) / l
rotation = sum([p.angle_diff(cx, cy) for p in self.points]) / l dist = sum([p.distance(cx, cy) for p in self.points]) / l
pinch = sum([p.distance(cx, cy) for p in self.points]) / l
if rotation: if rotation:
self.trigger(Rotate(cx, cy, rotation, l)) self.trigger(Rotate(cx, cy, rotation, l))
if self.prev_pinch == None: if self.prev_dist != None:
self.prev_pinch = pinch pinch = dist / self.prev_dist
else:
pinch -= self.prev_pinch
if pinch: if pinch:
self.trigger(Pinch(cx, cy, pinch, l)) self.trigger(Pinch(cx, cy, pinch, l))
self.prev_dist = dist
def update_centroid(self): def update_centroid(self):
""" """
Calculate the centroid of all current touch points. Calculate the centroid of all current touch points.
""" """
self.old_centroid = self.centroid 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
if self.points:
self.centroid = average([p.xy for p in self.points]) self.centroid = average([p.xy for p in self.points])
else:
# Only use stationary points for rotational centroid, if any # There are no touch points, move the centroid out of the screen
stat = [p.xy for p in filter(TouchPoint.is_stationary, self.points)] self.centroid = -1., -1.
self.rot_centroid = average(stat) if stat else self.centroid
def centroid_movement(self): def centroid_movement(self):
......
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