Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
multitouch
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Taddeüs Kroes
multitouch
Commits
a96fdaa1
Commit
a96fdaa1
authored
May 30, 2012
by
Taddeus Kroes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added tracker for transformations (rotate, pinch, movement).
parent
0032d621
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
190 additions
and
8 deletions
+190
-8
src/geometry.py
src/geometry.py
+26
-8
src/trackers/transform.py
src/trackers/transform.py
+117
-0
tests/transform.py
tests/transform.py
+47
-0
No files found.
src/geometry.py
View file @
a96fdaa1
...
...
@@ -43,8 +43,7 @@ class MovingPositionable(Positionable):
"""
def
__init__
(
self
,
x
=
None
,
y
=
None
):
super
(
MovingPositionable
,
self
).
__init__
(
x
,
y
)
self
.
px
=
x
self
.
py
=
y
self
.
prev
=
Positionable
(
x
,
y
)
def
set_position
(
self
,
x
,
y
):
"""
...
...
@@ -53,16 +52,14 @@ class MovingPositionable(Positionable):
position so that the movement is zero.
"""
if
self
.
x
is
None
or
self
.
y
is
None
:
self
.
px
=
x
self
.
py
=
y
self
.
prev
.
set_position
(
x
,
y
)
else
:
self
.
px
=
self
.
x
self
.
py
=
self
.
y
self
.
prev
.
set_position
(
self
.
x
,
self
.
y
)
Positionable
.
set_position
(
self
,
x
,
y
)
def
get_previous_position
(
self
):
return
self
.
p
x
,
self
.
py
return
self
.
p
rev
def
rotation_around
(
self
,
center
):
"""
...
...
@@ -70,7 +67,8 @@ class MovingPositionable(Positionable):
positionable.
"""
cx
,
cy
=
center
.
get_position
()
prev_angle
=
atan2
(
self
.
px
-
cx
,
self
.
py
-
cy
)
px
,
py
=
self
.
prev
.
get_position
()
prev_angle
=
atan2
(
px
-
cx
,
py
-
cy
)
current_angle
=
atan2
(
self
.
x
-
cx
,
self
.
y
-
cy
)
rotation
=
current_angle
-
prev_angle
...
...
@@ -82,6 +80,17 @@ class MovingPositionable(Positionable):
return
rotation
def
translation
(
self
):
"""
Calculate the movement relative to the last position as a vector
positionable.
"""
px
,
py
=
self
.
prev
.
get_position
()
return
Positionable
(
self
.
x
-
px
,
self
.
y
-
py
)
def
movement_distance
(
self
):
return
self
.
distance_to
(
self
.
prev
)
class
AcceleratedPositionable
(
MovingPositionable
):
"""
...
...
@@ -103,6 +112,15 @@ class AcceleratedPositionable(MovingPositionable):
self
.
prev_timestamp
=
self
.
current_timestamp
self
.
current_timestamp
=
time
.
time
()
def
movement_time
(
self
):
return
self
.
timestamp
-
self
.
prev_timestamp
def
acceleration
(
self
):
"""
Calculate the acceleration in pixels/second.
"""
return
self
.
movement_distance
()
/
self
.
movement_time
()
class
Surface
(
Positionable
):
"""
...
...
src/trackers/transform.py
0 → 100644
View file @
a96fdaa1
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
):
if
len
(
self
.
points
)
>
1
:
# Rotation (around the previous centroid)
if
self
.
is_type_bound
(
'rotate'
):
rotation
=
point
.
rotation_around
(
self
.
centroid
)
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
)
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
)
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
)
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
())
tests/transform.py
0 → 100644
View file @
a96fdaa1
import
argparse
import
logging
from
src.server
import
GestureServer
from
src.window
import
FullscreenWindow
from
src.trackers.transform
import
TransformationTracker
from
src.logger
import
Logger
# Parse arguments
parser
=
argparse
.
ArgumentParser
(
description
=
'Basic test program for usage '
'of multi-touch API.'
)
parser
.
add_argument
(
'--log'
,
metavar
=
'LOG_LEVEL'
,
default
=
'INFO'
,
choices
=
[
'DEBUG'
,
'INFO'
,
'WARNING'
],
help
=
'set log level (defaults to INFO)'
)
parser
.
add_argument
(
'--logfile'
,
metavar
=
'FILENAME'
,
help
=
'filename for the log file (the log is printed to '
'stdout by default)'
)
args
=
parser
.
parse_args
()
# Configure logger
log_config
=
{
'level'
:
getattr
(
logging
,
args
.
log
)}
if
args
.
logfile
:
log_config
[
'filename'
]
=
args
.
logfile
Logger
.
configure
(
**
log_config
)
# Create server
server
=
GestureServer
()
# Create a window to add trackers to
win
=
FullscreenWindow
(
server
=
server
)
# Add tracker and handlers
tracker
=
TransformationTracker
(
win
)
tracker
.
bind
(
'rotate'
,
lambda
g
:
0
)
tracker
.
bind
(
'pinch'
,
lambda
g
:
0
)
tracker
.
bind
(
'move'
,
lambda
g
:
0
)
# Start listening to TUIO events
try
:
server
.
start
()
except
KeyboardInterrupt
:
server
.
stop
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment