Skip to content

Commit a4f802e

Browse files
committed
push shift to rotate but keep cam pos
1 parent eac74ac commit a4f802e

File tree

1 file changed

+59
-31
lines changed

1 file changed

+59
-31
lines changed

q3dviewer/base_glwidget.py

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def __init__(self, parent=None):
2525
self.active_keys = set()
2626
self.show_center = False
2727
self.enable_show_center = True
28-
self.view_need_update = True
28+
self.need_recalc_view = True
2929
self.view_matrix = self.get_view_matrix()
3030
self.projection_matrix = self.get_projection_matrix()
3131

@@ -98,21 +98,21 @@ def initializeGL(self):
9898

9999
def set_view_matrix(self, view_matrix):
100100
self.view_matrix = view_matrix
101-
self.view_need_update = False
101+
self.need_recalc_view = False
102102

103103
def mouseReleaseEvent(self, ev):
104104
if hasattr(self, 'mousePos'):
105105
delattr(self, 'mousePos')
106106

107107
def set_dist(self, dist):
108108
self.dist = dist
109-
self.view_need_update = True
109+
self.need_recalc_view = True
110110

111111
def update_dist(self, delta):
112112
self.dist += delta
113113
if self.dist < 0.1:
114114
self.dist = 0.1
115-
self.view_need_update = True
115+
self.need_recalc_view = True
116116

117117
def wheelEvent(self, ev):
118118
delta = ev.angleDelta().x()
@@ -121,6 +121,24 @@ def wheelEvent(self, ev):
121121
self.update_dist(-delta * self.dist * 0.001)
122122
self.show_center = True
123123

124+
125+
def rotate_keep_cam_pos(self, rx=0, ry=0, rz=0):
126+
"""
127+
Rotate the camera while keeping the current camera position.
128+
This updates both the Euler angles and the center point.
129+
"""
130+
new_euler = self.euler + np.array([rx, ry, rz])
131+
new_euler = (new_euler + np.pi) % (2 * np.pi) - np.pi
132+
133+
Rwc_old = euler_to_matrix(self.euler)
134+
tco = np.array([0, 0, self.dist])
135+
twc = self.center + Rwc_old @ tco
136+
137+
Rwc_new = euler_to_matrix(new_euler)
138+
self.center = twc - Rwc_new @ tco
139+
self.euler = new_euler
140+
self.need_recalc_view = True
141+
124142
def mouseMoveEvent(self, ev):
125143
lpos = ev.localPos()
126144
if not hasattr(self, 'mousePos'):
@@ -131,24 +149,26 @@ def mouseMoveEvent(self, ev):
131149
rot_speed = 0.2
132150
dyaw = radians(-diff.x() * rot_speed)
133151
droll = radians(-diff.y() * rot_speed)
134-
self.rotate(droll, 0, dyaw)
152+
if ev.modifiers() & QtCore.Qt.ShiftModifier:
153+
self.rotate_keep_cam_pos(droll, 0, dyaw)
154+
else:
155+
self.rotate(droll, 0, dyaw)
135156
elif ev.buttons() == QtCore.Qt.MouseButton.LeftButton:
136157
Rwc = euler_to_matrix(self.euler)
137158
Kinv = np.linalg.inv(self.get_K())
138159
dist = max(self.dist, 0.5)
139-
self.center += Rwc @ Kinv @ np.array([-diff.x(), diff.y(), 0]) * dist
160+
self.translate(Rwc @ Kinv @ np.array([-diff.x(), diff.y(), 0]) * dist)
140161
self.show_center = True
141-
self.view_need_update = True
142162

143163
def set_center(self, center):
144164
self.center = center
145-
self.view_need_update = True
165+
self.need_recalc_view = True
146166

147167
def paintGL(self):
148168
# if the camera is moved, update the model view matrix.
149-
if self.view_need_update:
169+
if self.need_recalc_view:
150170
self.view_matrix = self.get_view_matrix()
151-
self.view_need_update = False
171+
self.need_recalc_view = False
152172
self.update_model_view()
153173

154174
# set the background color
@@ -192,45 +212,48 @@ def update_movement(self):
192212
return
193213
rot_speed = 0.5
194214
trans_speed = max(self.dist * 0.005, 0.1)
215+
shift_pressed = QtCore.Qt.Key_Shift in self.active_keys
195216
# Handle rotation keys
196217
if QtCore.Qt.Key_Up in self.active_keys:
197-
self.rotate(radians(rot_speed), 0, 0)
198-
self.view_need_update = True
218+
if shift_pressed:
219+
self.rotate_keep_cam_pos(radians(rot_speed), 0, 0)
220+
else:
221+
self.rotate(radians(rot_speed), 0, 0)
199222
if QtCore.Qt.Key_Down in self.active_keys:
200-
self.rotate(radians(-rot_speed), 0, 0)
201-
self.view_need_update = True
223+
if shift_pressed:
224+
self.rotate_keep_cam_pos(radians(-rot_speed), 0, 0)
225+
else:
226+
self.rotate(radians(-rot_speed), 0, 0)
202227
if QtCore.Qt.Key_Left in self.active_keys:
203-
self.rotate(0, 0, radians(rot_speed))
204-
self.view_need_update = True
228+
if shift_pressed:
229+
self.rotate_keep_cam_pos(0, 0, radians(rot_speed))
230+
else:
231+
self.rotate(0, 0, radians(rot_speed))
205232
if QtCore.Qt.Key_Right in self.active_keys:
206-
self.rotate(0, 0, radians(-rot_speed))
207-
self.view_need_update = True
233+
if shift_pressed:
234+
self.rotate_keep_cam_pos(0, 0, radians(-rot_speed))
235+
else:
236+
self.rotate(0, 0, radians(-rot_speed))
208237
# Handle zoom keys
209238
xz_keys = {QtCore.Qt.Key_Z, QtCore.Qt.Key_X}
210239
if self.active_keys & xz_keys:
211240
Rwc = euler_to_matrix(self.euler)
212241
if QtCore.Qt.Key_Z in self.active_keys:
213-
self.center += Rwc @ np.array([0, 0, -trans_speed])
214-
self.view_need_update = True
242+
self.translate(Rwc @ np.array([0, 0, -trans_speed]))
215243
if QtCore.Qt.Key_X in self.active_keys:
216-
self.center += Rwc @ np.array([0, 0, trans_speed])
217-
self.view_need_update = True
244+
self.translate(Rwc @ np.array([0, 0, trans_speed]))
218245
# Handle translation keys on the z plane
219246
dir_keys = {QtCore.Qt.Key_W, QtCore.Qt.Key_S, QtCore.Qt.Key_A, QtCore.Qt.Key_D}
220247
if self.active_keys & dir_keys:
221248
Rz = euler_to_matrix([0, 0, self.euler[2]])
222249
if QtCore.Qt.Key_W in self.active_keys:
223-
self.center += Rz @ np.array([0, trans_speed, 0])
224-
self.view_need_update = True
250+
self.translate(Rz @ np.array([0, trans_speed, 0]))
225251
if QtCore.Qt.Key_S in self.active_keys:
226-
self.center += Rz @ np.array([0, -trans_speed, 0])
227-
self.view_need_update = True
252+
self.translate(Rz @ np.array([0, -trans_speed, 0]))
228253
if QtCore.Qt.Key_A in self.active_keys:
229-
self.center += Rz @ np.array([-trans_speed, 0, 0])
230-
self.view_need_update = True
254+
self.translate(Rz @ np.array([-trans_speed, 0, 0]))
231255
if QtCore.Qt.Key_D in self.active_keys:
232-
self.center += Rz @ np.array([trans_speed, 0, 0])
233-
self.view_need_update = True
256+
self.translate(Rz @ np.array([trans_speed, 0, 0]))
234257

235258
def update_model_view(self):
236259
glMatrixMode(GL_MODELVIEW)
@@ -259,7 +282,7 @@ def set_cam_position(self, **kwargs):
259282

260283
def set_euler(self, euler):
261284
self.euler = euler
262-
self.view_need_update = True
285+
self.need_recalc_view = True
263286

264287
def set_color(self, color):
265288
self.color = color
@@ -303,6 +326,11 @@ def rotate(self, rx=0, ry=0, rz=0):
303326
self.euler[2] = (self.euler[2] + np.pi) % (2 * np.pi) - np.pi
304327
self.euler[1] = (self.euler[1] + np.pi) % (2 * np.pi) - np.pi
305328
self.euler[0] = np.clip(self.euler[0], 0, np.pi)
329+
self.need_recalc_view = True
330+
331+
def translate(self, trans):
332+
self.center += trans
333+
self.need_recalc_view = True
306334

307335
def change_show_center(self, state):
308336
self.enable_show_center = state

0 commit comments

Comments
 (0)