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

initial proof of concept for space navigator 3d mouse support #413

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
85 changes: 83 additions & 2 deletions cq_editor/widgets/occt_widget.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from sys import platform

import sys

from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QEvent
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QEvent, QTimer

import OCP

Expand All @@ -12,6 +12,12 @@
from OCP.AIS import AIS_InteractiveContext, AIS_DisplayMode
from OCP.Quantity import Quantity_Color

# pyspacemouse is an optional dependency, so don't fail if it isn't present
try:
import pyspacemouse
except:
pass


ZOOM_STEP = 0.9

Expand Down Expand Up @@ -41,6 +47,33 @@

#Trihedorn, lights, etc
self.prepare_display()

self._spacemouse_connected = False
if 'pyspacemouse' in sys.modules:
# TODO: this currently checks for 3d mouse presence once at
# initialization, which means that if you plug in your mouse after
# starting cq-editor it won't work. We should instead periodically
# check to see if a mouse was newly-connected.

# TODO: the callback-based approach seems better than polling, but
# it didn't work. Probably something threading-related. The
# callback api works for me in a standalone script.
#
# self._spacemouse_connected = pyspacemouse.open(callback=self.spacemouse_callback, dof_callback=self.spacemouse_dof_callback, button_callback=self.spacemouse_button_callback)

self._spacemouse_connected = pyspacemouse.open()

Check warning on line 64 in cq_editor/widgets/occt_widget.py

View check run for this annotation

Codecov / codecov/patch

cq_editor/widgets/occt_widget.py#L64

Added line #L64 was not covered by tests
if self._spacemouse_connected:
print("3DConnexion SpaceNavigator 3d mouse detected")
print(self._spacemouse_connected)

Check warning on line 67 in cq_editor/widgets/occt_widget.py

View check run for this annotation

Codecov / codecov/patch

cq_editor/widgets/occt_widget.py#L66-L67

Added lines #L66 - L67 were not covered by tests

# setup a timer to periodically read the 3d mouse state and
# update the view
self._spacemouse_timer = QTimer(self)
self._spacemouse_timer.setInterval(10) # milliseconds
self._spacemouse_timer.setSingleShot(False)
self._spacemouse_timer.timeout.connect(self._update_from_spacemouse)
self._spacemouse_timer.start()

Check warning on line 75 in cq_editor/widgets/occt_widget.py

View check run for this annotation

Codecov / codecov/patch

cq_editor/widgets/occt_widget.py#L71-L75

Added lines #L71 - L75 were not covered by tests


def prepare_display(self):

Expand Down Expand Up @@ -171,3 +204,51 @@
from OCP.Cocoa import Cocoa_Window

return Cocoa_Window(wid.ascapsule())

# def spacemouse_callback(self, state):
# print("spacemouse_callback: ", state)

# def spacemouse_dof_callback(self, state):
# print("spacemouse_dof_callback: ", state)

# def spacemouse_button_callback(self, state):
# print("spacemouse_button_callback: ", state)

# called periodically to read new values from the 3d mouse and update the
# view
def _update_from_spacemouse(self):
state = pyspacemouse.read()

Check warning on line 220 in cq_editor/widgets/occt_widget.py

View check run for this annotation

Codecov / codecov/patch

cq_editor/widgets/occt_widget.py#L220

Added line #L220 was not covered by tests
# print(state)

# axis values less than this are ignored
threshold = 0.05

Check warning on line 224 in cq_editor/widgets/occt_widget.py

View check run for this annotation

Codecov / codecov/patch

cq_editor/widgets/occt_widget.py#L224

Added line #L224 was not covered by tests

if abs(state.y) > threshold:
# if state.y < 0:
self.view.SetZoom(1-state.y/20)

Check warning on line 228 in cq_editor/widgets/occt_widget.py

View check run for this annotation

Codecov / codecov/patch

cq_editor/widgets/occt_widget.py#L228

Added line #L228 was not covered by tests

# TODO: roll and pitch should also factor into rotation
# if abs(state.yaw) > threshold:
# angle_rad = state.yaw
# # TODO: this rotates about the "current axis". Whatever the current
# # axis is, it doesn't seem to be what we want
# self.view.Rotate(angle_rad,False)

pan_x = 0
pan_y = 0

Check warning on line 238 in cq_editor/widgets/occt_widget.py

View check run for this annotation

Codecov / codecov/patch

cq_editor/widgets/occt_widget.py#L237-L238

Added lines #L237 - L238 were not covered by tests
if abs(state.x) > threshold:
pan_x = int(state.x*100)

Check warning on line 240 in cq_editor/widgets/occt_widget.py

View check run for this annotation

Codecov / codecov/patch

cq_editor/widgets/occt_widget.py#L240

Added line #L240 was not covered by tests
if abs(state.z) > threshold:
pan_y = int(state.z*100)

Check warning on line 242 in cq_editor/widgets/occt_widget.py

View check run for this annotation

Codecov / codecov/patch

cq_editor/widgets/occt_widget.py#L242

Added line #L242 was not covered by tests
if pan_x != 0 or pan_y != 0:
self.view.Pan(pan_x, pan_y, theToStart=True)

Check warning on line 244 in cq_editor/widgets/occt_widget.py

View check run for this annotation

Codecov / codecov/patch

cq_editor/widgets/occt_widget.py#L244

Added line #L244 was not covered by tests


# Override QWidget.destroy to cleanup 3d mouse connection
# TODO: this doesn't seem to get called... use __del__() instead?
def destroy(self, destroyWindow, destroySubWindows):
super().destroy(destroyWindow, destroySubWindows)
print("DEBUG: OcctWidget.destroy() called")

Check warning on line 251 in cq_editor/widgets/occt_widget.py

View check run for this annotation

Codecov / codecov/patch

cq_editor/widgets/occt_widget.py#L250-L251

Added lines #L250 - L251 were not covered by tests
if self._spacemouse_connected:
pyspacemouse.close()
self._spacemouse_timer.stop()

Check warning on line 254 in cq_editor/widgets/occt_widget.py

View check run for this annotation

Codecov / codecov/patch

cq_editor/widgets/occt_widget.py#L253-L254

Added lines #L253 - L254 were not covered by tests