| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- from __future__ import division
- from ..tracker import GestureTracker, Gesture
- from ..geometry import Positionable, MovingPositionable
- class TransformationTracker(GestureTracker):
- """
- Tracker for linear transformations. This implementation detects rotation,
- scaling and translation using the centroid of all touch points.
- """
- __gesture_types__ = ['rotate', 'pinch', 'move']
- def __init__(self, window=None):
- super(TransformationTracker, self).__init__(window)
- # All touch points performing the transformation
- self.points = []
- # Current and previous centroid of all touch points
- self.prev_centroid = self.centroid = None
- def update_centroid(self):
- self.prev_centroid = self.centroid
- if not self.points:
- self.centroid = None
- return
- # Calculate average touch point coordinates
- l = len(self.points)
- coords = [p.get_position() for p in self.points]
- all_x, all_y = zip(*coords)
- x = sum(all_x) / l
- y = sum(all_y) / l
- # Update centroid positionable
- if self.centroid:
- self.centroid.set_position(x, y)
- else:
- self.centroid = MovingPositionable(x, y)
- def on_point_down(self, point):
- self.points.append(point)
- self.update_centroid()
- def on_point_move(self, point):
- l = len(self.points)
- if l > 1:
- # Rotation (around the previous centroid)
- if self.is_type_bound('rotate'):
- rotation = point.rotation_around(self.centroid) / l
- self.trigger(RotationGesture(self.centroid, rotation))
- # Scale
- if self.is_type_bound('pinch'):
- prev = point.get_previous_position().distance_to(self.centroid)
- dist = point.distance_to(self.centroid)
- dist = prev + (dist - prev) / l
- scale = dist / prev
- self.trigger(PinchGesture(self.centroid, scale))
- # Update centroid before movement can be detected
- self.update_centroid()
- # Movement
- self.trigger(MovementGesture(self.centroid,
- self.centroid.translation()))
- def on_point_up(self, point):
- self.points.remove(point)
- self.update_centroid()
- class RotationGesture(Positionable, Gesture):
- """
- A rotation gesture has a angle in radians and a rotational centroid.
- """
- __type__ = 'rotate'
- def __init__(self, centroid, angle):
- Positionable.__init__(self, *centroid.get_position())
- self.angle = angle
- def __str__(self):
- return '<RotationGesture at (%s, %s) angle=%s>' \
- % (self.x, self.y, self.angle)
- def get_angle(self):
- return self.angle
- class PinchGesture(Positionable, Gesture):
- """
- A pinch gesture has a scale (1.0 means no scaling) and a centroid from
- which the scaling originates.
- """
- __type__ = 'pinch'
- def __init__(self, centroid, scale):
- Positionable.__init__(self, *centroid.get_position())
- self.scale = scale
- def __str__(self):
- return '<PinchGesture at (%s, %s) scale=%s>' \
- % (self.x, self.y, self.scale)
- def get_scale(self):
- return self.scale
- class MovementGesture(Positionable, Gesture):
- """
- A momevent gesture has an initial position, and a translation from that
- position.
- """
- __type__ = 'move'
- def __init__(self, initial_position, translation):
- Positionable.__init__(self, *initial_position.get_position())
- self.translation = translation
- def __str__(self):
- return '<MovementGesture at (%s, %s) translation=(%s, %s)>' \
- % (self.get_position() + self.translation.get_position())
|