Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update README.md #36

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 54 additions & 55 deletions FingerControl.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
#William Yager
#Leap Python mouse controller POC
#This file is for pointer-finger-based control (--finger and default)

# William Yager
# Leap Python mouse controller POC
# This file is for pointer-finger-based control (--finger and default)

import math
import sys
from leap import Leap, Mouse
from MiscFunctions import *


class Finger_Control_Listener(Leap.Listener): #The Listener that we attach to the controller. This listener is for pointer finger movement
class Finger_Control_Listener(Leap.Listener): # The Listener that we attach to the controller. This listener is for pointer finger movement
def __init__(self, mouse, smooth_aggressiveness=8, smooth_falloff=1.3):
super(Finger_Control_Listener, self).__init__() #Initialize like a normal listener
#Initialize a bunch of stuff specific to this implementation
super(Finger_Control_Listener, self).__init__() # Initialize like a normal listener
# Initialize a bunch of stuff specific to this implementation
self.screen = None
self.screen_resolution = (1920,1080)
self.cursor = mouse.absolute_cursor() #The cursor object that lets us control mice cross-platform
self.mouse_position_smoother = mouse_position_smoother(smooth_aggressiveness, smooth_falloff) #Keeps the cursor from fidgeting
self.mouse_button_debouncer = debouncer(5) #A signal debouncer that ensures a reliable, non-jumpy click
self.most_recent_pointer_finger_id = None #This holds the ID of the most recently used pointing finger, to prevent annoying switching
self.screen_resolution = (1920, 1080)
self.cursor = mouse.absolute_cursor() # The cursor object that lets us control mice cross-platform
self.mouse_position_smoother = mouse_position_smoother(smooth_aggressiveness, smooth_falloff) # Keeps the cursor from fidgeting
self.mouse_button_debouncer = debouncer(5) # A signal debouncer that ensures a reliable, non-jumpy click
self.most_recent_pointer_finger_id = None # This holds the ID of the most recently used pointing finger, to prevent annoying switching

def on_init(self, controller):
print "Initialized"
Expand All @@ -33,7 +32,7 @@ def on_exit(self, controller):
print "Exited"

def on_frame(self, controller):
frame = controller.frame() #Grab the latest 3D data
frame = controller.frame() # Grab the latest 3D data
finger = frame.fingers.frontmost
stabilizedPosition = finger.stabilized_tip_position
interactionBox = frame.interaction_box
Expand All @@ -57,61 +56,61 @@ def on_frame(self, controller):
elif finger_count == 2:
self.cursor.set_left_button_pressed(True)
self.cursor.move(normalizedPosition.x * self.screen_resolution[0], self.screen_resolution[1] - normalizedPosition.y * self.screen_resolution[1])
#if(finger.touch_distance > -0.3 and finger.touch_zone != Leap.Pointable.ZONE_NONE):
#self.cursor.set_left_button_pressed(False)
#self.cursor.move(normalizedPosition.x * self.screen_resolution[0], self.screen_resolution[1] - normalizedPosition.y * self.screen_resolution[1])
#elif(finger.touch_distance <= -0.4):
#self.cursor.set_left_button_pressed(True)
# print finger.touch_distance
# if(finger.touch_distance > -0.3 and finger.touch_zone != Leap.Pointable.ZONE_NONE):
# self.cursor.set_left_button_pressed(False)
# self.cursor.move(normalizedPosition.x * self.screen_resolution[0], self.screen_resolution[1] - normalizedPosition.y * self.screen_resolution[1])
# elif(finger.touch_distance <= -0.4):
# self.cursor.set_left_button_pressed(True)
# print finger.touch_distance

def do_scroll_stuff(self, hand): #Take a hand and use it as a scroller
fingers = hand.fingers #The list of fingers on said hand
if not fingers.is_empty: #Make sure we have some fingers to work with
sorted_fingers = sort_fingers_by_distance_from_screen(fingers) #Prioritize fingers by distance from screen
finger_velocity = sorted_fingers[0].tip_velocity #Get the velocity of the forwardmost finger
def do_scroll_stuff(self, hand): # Take a hand and use it as a scroller
fingers = hand.fingers # The list of fingers on said hand
if not fingers.is_empty: # Make sure we have some fingers to work with
sorted_fingers = sort_fingers_by_distance_from_screen(fingers) # Prioritize fingers by distance from screen
finger_velocity = sorted_fingers[0].tip_velocity # Get the velocity of the forwardmost finger
x_scroll = self.velocity_to_scroll_amount(finger_velocity.x)
y_scroll = self.velocity_to_scroll_amount(finger_velocity.y)
self.cursor.scroll(x_scroll, y_scroll)

def velocity_to_scroll_amount(self, velocity): #Converts a finger velocity to a scroll velocity
#The following algorithm was designed to reflect what I think is a comfortable
#Scrolling behavior.
vel = velocity #Save to a shorter variable
vel = vel + math.copysign(300, vel) #Add/subtract 300 to velocity
def velocity_to_scroll_amount(self, velocity): # Converts a finger velocity to a scroll velocity
# The following algorithm was designed to reflect what I think is a comfortable
# Scrolling behavior.
vel = velocity # Save to a shorter variable
vel = vel + math.copysign(300, vel) # Add/subtract 300 to velocity
vel = vel / 150
vel = vel ** 3 #Cube vel
vel = vel ** 3 # Cube vel
vel = vel / 8
vel = vel * -1 #Negate direction, depending on how you like to scroll
vel = vel * -1 # Negate direction, depending on how you like to scroll
return vel

def do_mouse_stuff(self, hand): #Take a hand and use it as a mouse
fingers = hand.fingers #The list of fingers on said hand
if not fingers.is_empty: #Make sure we have some fingers to work with
pointer_finger = self.select_pointer_finger(fingers) #Determine which finger to use
def do_mouse_stuff(self, hand): # Take a hand and use it as a mouse
fingers = hand.fingers # The list of fingers on said hand
if not fingers.is_empty: # Make sure we have some fingers to work with
pointer_finger = self.select_pointer_finger(fingers) # Determine which finger to use

try:
intersection = self.screen.intersect(pointer_finger, True) #Where the finger projection intersects with the screen
if not math.isnan(intersection.x) and not math.isnan(intersection.y): #If the finger intersects with the screen
x_coord = intersection.x * self.screen_resolution[0] #x pixel of intersection
y_coord = (1.0 - intersection.y) * self.screen_resolution[1] #y pixel of intersection
x_coord,y_coord = self.mouse_position_smoother.update((x_coord,y_coord)) #Smooth movement
self.cursor.move(x_coord,y_coord) #Move the cursor
if has_thumb(hand): #We've found a thumb!
self.mouse_button_debouncer.signal(True) #We have detected a possible click. The debouncer ensures that we don't have click jitter
intersection = self.screen.intersect(pointer_finger, True) # Where the finger projection intersects with the screen
if not math.isnan(intersection.x) and not math.isnan(intersection.y): # If the finger intersects with the screen
x_coord = intersection.x * self.screen_resolution[0] # x pixel of intersection
y_coord = (1.0 - intersection.y) * self.screen_resolution[1] # y pixel of intersection
x_coord, y_coord = self.mouse_position_smoother.update((x_coord, y_coord)) # Smooth movement
self.cursor.move(x_coord, y_coord) # Move the cursor
if has_thumb(hand): # We've found a thumb!
self.mouse_button_debouncer.signal(True) # We have detected a possible click. The debouncer ensures that we don't have click jitter
else:
self.mouse_button_debouncer.signal(False) #Same idea as above (but opposite)
self.mouse_button_debouncer.signal(False) # Same idea as above (but opposite)

if self.cursor.left_button_pressed != self.mouse_button_debouncer.state: #We need to push/unpush the cursor's button
self.cursor.set_left_button_pressed(self.mouse_button_debouncer.state) #Set the cursor to click/not click
if self.cursor.left_button_pressed != self.mouse_button_debouncer.state: # We need to push/unpush the cursor's button
self.cursor.set_left_button_pressed(self.mouse_button_debouncer.state) # Set the cursor to click/not click
except Exception as e:
print e

def select_pointer_finger(self, possible_fingers): #Choose the best pointer finger
sorted_fingers = sort_fingers_by_distance_from_screen(possible_fingers) #Prioritize fingers by distance from screen
if self.most_recent_pointer_finger_id != None: #If we have a previous pointer finger in memory
for finger in sorted_fingers: #Look at all the fingers
if finger.id == self.most_recent_pointer_finger_id: #The previously used pointer finger is still in frame
return finger #Keep using it
#If we got this far, it means we don't have any previous pointer fingers OR we didn't find the most recently used pointer finger in the frame
self.most_recent_pointer_finger_id = sorted_fingers[0].id #This is the new pointer finger
def select_pointer_finger(self, possible_fingers): # Choose the best pointer finger
sorted_fingers = sort_fingers_by_distance_from_screen(possible_fingers) # Prioritize fingers by distance from screen
if self.most_recent_pointer_finger_id: # If we have a previous pointer finger in memory
for finger in sorted_fingers: # Look at all the fingers
if finger.id == self.most_recent_pointer_finger_id: # The previously used pointer finger is still in frame
return finger # Keep using it
# If we got this far, it means we don't have any previous pointer fingers OR we didn't find the most recently used pointer finger in the frame
self.most_recent_pointer_finger_id = sorted_fingers[0].id # This is the new pointer finger
return sorted_fingers[0]
18 changes: 10 additions & 8 deletions Geometry.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#William Yager
#Leap Python mouse controller POC
# William Yager
# Leap Python mouse controller POC


import math
Expand Down Expand Up @@ -56,6 +56,7 @@ def __init__(self, point1, point2):
self.point1 = point1
self.point2 = point2
#Shortest distance code based off of http://geomalgorithms.com/a07-_distance.html

def min_distance_infinite(self, other): #Return shortest distance between two lines
u = self.point2 - self.point1
v = other.point2 - other.point1
Expand All @@ -80,11 +81,12 @@ def min_distance_infinite(self, other): #Return shortest distance between two l
tc = (a * e - b * d) / D
dP = w + u**sc - v**tc
return dP.norm()
def min_distance_finite(self, other): #Return shortest distance between two segments

def min_distance_finite(self, other): # Return shortest distance between two segments
u = self.point2 - self.point1
v = other.point2 - other.point1
w = self.point1 - other.point1
a = u * u #* here is cross product
a = u * u # * here is cross product
b = u * v
c = v * v
d = u * w
Expand Down Expand Up @@ -139,7 +141,7 @@ def min_distance_finite(self, other): #Return shortest distance between two seg
tc = 0.0
else:
tc = tN / tD
dP = w + u**sc - v**tc #I'm pretty sure dP is the actual vector linking the lines
dP = w + u**sc - v**tc # I'm pretty sure dP is the actual vector linking the lines
return dP.norm()


Expand All @@ -151,8 +153,8 @@ def __init__(self, point1, direction_vector):


def angle_between_vectors(vector1, vector2):
#cos(theta)=dot product / (|a|*|b|)
top = vector1 * vector2 #* is dot product
# cos(theta)=dot product / (|a|*|b|)
top = vector1 * vector2 # * is dot product
bottom = vector1.norm() * vector2.norm()
angle = math.acos(top/bottom)
return angle #In radians
return angle # In radians
Loading