Skip to content

Commit 5b65f4d

Browse files
committed
added orbital rotation mode and take scroll delta into account when zooming
1 parent 0613140 commit 5b65f4d

File tree

2 files changed

+61
-42
lines changed

2 files changed

+61
-42
lines changed

cq_editor/widgets/occt_widget.py

Lines changed: 57 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,55 @@
1+
import math
12
from sys import platform
23

3-
4-
from PyQt5.QtWidgets import QWidget, QApplication
5-
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QEvent
6-
7-
import OCP
8-
4+
from OCP.AIS import AIS_InteractiveContext, AIS_DisplayMode
95
from OCP.Aspect import Aspect_DisplayConnection, Aspect_TypeOfTriedronPosition
106
from OCP.OpenGl import OpenGl_GraphicDriver
11-
from OCP.V3d import V3d_Viewer
12-
from OCP.AIS import AIS_InteractiveContext, AIS_DisplayMode
137
from OCP.Quantity import Quantity_Color
8+
from OCP.V3d import V3d_Viewer
9+
from OCP.gp import gp_Trsf, gp_Ax1, gp_Dir
10+
from PyQt5.QtCore import pyqtSignal, Qt, QPoint
11+
from PyQt5.QtWidgets import QWidget
1412

1513

16-
ZOOM_STEP = 0.9
17-
18-
1914
class OCCTWidget(QWidget):
2015

2116
sigObjectSelected = pyqtSignal(list)
2217

23-
def __init__(self,parent=None):
18+
def __init__(self, parent=None, *,
19+
orbital_rotation: bool = True,
20+
rotate_step: float = 0.008,
21+
zoom_step: float = 0.1):
2422

25-
super(OCCTWidget,self).__init__(parent)
23+
super(OCCTWidget, self).__init__(parent)
2624

2725
self.setAttribute(Qt.WA_NativeWindow)
2826
self.setAttribute(Qt.WA_PaintOnScreen)
2927
self.setAttribute(Qt.WA_NoSystemBackground)
3028

3129
self._initialized = False
3230
self._needs_update = False
31+
self._old_pos = QPoint(0, 0)
32+
self._rotate_step = rotate_step
33+
self._zoom_step = zoom_step
34+
self._orbital_rotation = orbital_rotation
3335

34-
#OCCT secific things
36+
# OCCT secific things
3537
self.display_connection = Aspect_DisplayConnection()
3638
self.graphics_driver = OpenGl_GraphicDriver(self.display_connection)
3739

3840
self.viewer = V3d_Viewer(self.graphics_driver)
3941
self.view = self.viewer.CreateView()
4042
self.context = AIS_InteractiveContext(self.viewer)
4143

42-
#Trihedorn, lights, etc
44+
# Trihedorn, lights, etc
4345
self.prepare_display()
44-
46+
47+
def set_orbital_rotation(self, new_value: bool):
48+
if self._orbital_rotation != new_value:
49+
self._orbital_rotation = new_value
50+
if self._orbital_rotation:
51+
self.view.SetUp(0, 0, 1)
52+
4553
def prepare_display(self):
4654

4755
view = self.view
@@ -65,49 +73,58 @@ def prepare_display(self):
6573
ctx.DefaultDrawer().SetFaceBoundaryDraw(True)
6674

6775
def wheelEvent(self, event):
68-
69-
delta = event.angleDelta().y()
70-
factor = ZOOM_STEP if delta<0 else 1/ZOOM_STEP
71-
76+
77+
# dividing by 120 gets number of notches on a typical scroll wheel.
78+
# See QWheelEvent documentation
79+
delta_notches = event.angleDelta().y() / 120
80+
direction = math.copysign(1, delta_notches)
81+
factor = (1 + self._zoom_step * direction) ** abs(delta_notches)
82+
7283
self.view.SetZoom(factor)
7384

74-
def mousePressEvent(self,event):
85+
def mousePressEvent(self, event):
7586

7687
pos = event.pos()
77-
88+
7889
if event.button() == Qt.LeftButton:
79-
self.view.StartRotation(pos.x(), pos.y())
90+
if not self._orbital_rotation:
91+
self.view.StartRotation(pos.x(), pos.y())
8092
elif event.button() == Qt.RightButton:
8193
self.view.StartZoomAtPoint(pos.x(), pos.y())
8294

83-
self.old_pos = pos
84-
85-
def mouseMoveEvent(self,event):
95+
self._old_pos = pos
96+
97+
def mouseMoveEvent(self, event):
8698

8799
pos = event.pos()
88-
x,y = pos.x(),pos.y()
89-
100+
x, y = pos.x(), pos.y()
101+
90102
if event.buttons() == Qt.LeftButton:
91-
self.view.Rotation(x,y)
92-
103+
if self._orbital_rotation:
104+
delta_x, delta_y = x - self._old_pos.x(), y - self._old_pos.y()
105+
cam = self.view.Camera()
106+
z_rotation = gp_Trsf()
107+
z_rotation.SetRotation(gp_Ax1(cam.Center(), gp_Dir(0, 0, 1)), -delta_x * self._rotate_step)
108+
cam.Transform(z_rotation)
109+
self.view.Rotate(0, -delta_y * self._rotate_step, 0)
110+
else:
111+
self.view.Rotation(x, y)
112+
93113
elif event.buttons() == Qt.MiddleButton:
94-
self.view.Pan(x - self.old_pos.x(),
95-
self.old_pos.y() - y, theToStart=True)
114+
delta_x, delta_y = x - self._old_pos.x(), y - self._old_pos.y()
115+
self.view.Pan(delta_x, -delta_y, theToStart=True)
96116

97117
elif event.buttons() == Qt.RightButton:
98-
self.view.ZoomAtPoint(self.old_pos.x(), y,
99-
x, self.old_pos.y())
118+
self.view.ZoomAtPoint(self._old_pos.x(), y,
119+
x, self._old_pos.y())
100120

101-
self.old_pos = pos
121+
self._old_pos = pos
102122

103-
def mouseReleaseEvent(self,event):
123+
def mouseReleaseEvent(self, event):
104124

105125
if event.button() == Qt.LeftButton:
106126
pos = event.pos()
107-
x,y = pos.x(),pos.y()
108-
109-
self.context.MoveTo(x,y,self.view,True)
110-
127+
self.context.MoveTo(pos.x(), pos.y(), self.view, True)
111128
self._handle_selection()
112129

113130
def _handle_selection(self):

cq_editor/widgets/viewer.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ class OCCViewer(QWidget,ComponentMixin):
3939
{'name': 'Background color (aux)', 'type': 'color', 'value': (30,30,30)},
4040
{'name': 'Default object color', 'type': 'color', 'value': "FF0"},
4141
{'name': 'Deviation', 'type': 'float', 'value': 1e-5, 'dec': True, 'step': 1},
42-
{'name': 'Angular deviation', 'type': 'float', 'value': 0.1, 'dec': True, 'step': 1}])
43-
42+
{'name': 'Angular deviation', 'type': 'float', 'value': 0.1, 'dec': True, 'step': 1},
43+
{'name': 'Orbital rotation', 'type': 'bool', 'value': True}])
44+
4445

4546
IMAGE_EXTENSIONS = 'png'
4647

@@ -71,6 +72,7 @@ def updatePreferences(self,*args):
7172
if not self.preferences['Use gradient']:
7273
color2 = color1
7374
self.canvas.view.SetBgGradientColors(color1,color2,theToUpdate=True)
75+
self.canvas.set_orbital_rotation(self.preferences['Orbital rotation'])
7476

7577
self.canvas.update()
7678

0 commit comments

Comments
 (0)