Leap Motion

From PyMOLWiki
Revision as of 12:04, 30 July 2013 by Speleo3 (talk | contribs) (created)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

This page describes how to get the Leap Motion Controller working in PyMOL, using the Leap Python API. The script was tested on Gentoo Linux and OSX.

Experienced Issues on OSX

  • must use /usr/bin/python2.7, the macports or fink python does not work
  • must use GLUT framework, macports or fink X11 glut will not work
  • the GLUT framework will change the current directory on startup
  • no Tk (external window)

Compiling and Running PyMOL on OSX

In SVN rev 4037 there was a --osx-frameworks argument added to use OpenGL and GLUT frameworks. See also Linux Install.

/usr/bin/python2.7 setup.py build install \
    --prefix=/tmp/pymol-for-leapmotion \
    --osx-frameworks

Run PyMOL without the external GUI and provide absolute paths for arguments:

/tmp/pymol-for-leapmotion/bin/pymol -xqr $PWD/LeapExampleScript.py

Example Script

The script below demostrates proof-of-concept by implementing camera rotation and zooming with multiple fingers. It's not supposed to provide real production functionality.

'''
Minimal example for PyMOL + LEAP Motion

(c) 2013 Schrödinger, Inc.

License: BSD-2-Clause
'''

import sys
import math
from pymol import cmd

if sys.platform.startswith('linux'):
    sys.path.append('/usr/share/Leap/LeapSDK/lib')
    sys.path.append('/usr/share/Leap/LeapSDK/lib/x64')
else:
    # TODO: ADJUST THIS
    sys.path.append('/path/to/LeapSDK/lib')

import Leap
from Leap import Matrix, Vector

class PymolListener(Leap.Listener):
    def __init__(self, *args, **kwargs):
        super(PymolListener, self).__init__(*args, **kwargs)

        self.prev_frame = None

        self.controller = Leap.Controller()
        self.controller.add_listener(self)

    def __del__(self):
        self.controller.remove_listener(self)

        super(PymolListener, self).__del__()

    def update_view(self, frame):
        if not self.prev_frame:
            return

        view = list(cmd.get_view())

        if frame.rotation_probability(self.prev_frame) > 0.1:
            m = frame.rotation_matrix(self.prev_frame)
            m *= Matrix(Vector(*view[0:3]),
                        Vector(*view[3:6]),
                        Vector(*view[6:9]))
            view[:9] = m.to_array_3x3()

        if frame.scale_probability(self.prev_frame) > 0.1:
            s = frame.scale_factor(self.prev_frame)
            delta_z = math.log(s) * 100.0
            view[11] += delta_z
            view[15] -= delta_z
            view[16] -= delta_z

        cmd.set_view(view)

    def on_frame(self, controller):
        frame = controller.frame()

        self.update_view(frame)

        self.prev_frame = frame

listener = PymolListener()

See Also