Leap Motion

From PyMOLWiki
Jump to: navigation, search

This page describes how to get the Leap Motion Controller working in PyMOL, using the Leap Python API. The script was tested with PyMOL 2.0 on all platforms, with MacPyMOL "syspython", and with Open-Source PyMOL on Gentoo Linux and MacOS.

Using PyMOL 2.0 (Anaconda Python)

Install the driver from https://www.leapmotion.com/setup/desktop/

Install PyMOL and the Leap Python module from Anaconda Cloud:

conda install -c schrodinger pymol
conda install -c speleo3 leap-motion-python

Using Open-Source PyMOL on MacOS

Experienced Issues

  • 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