@@ -25,7 +25,7 @@ def __init__(self, parent=None):
25
25
self .active_keys = set ()
26
26
self .show_center = False
27
27
self .enable_show_center = True
28
- self .view_need_update = True
28
+ self .need_recalc_view = True
29
29
self .view_matrix = self .get_view_matrix ()
30
30
self .projection_matrix = self .get_projection_matrix ()
31
31
@@ -98,21 +98,21 @@ def initializeGL(self):
98
98
99
99
def set_view_matrix (self , view_matrix ):
100
100
self .view_matrix = view_matrix
101
- self .view_need_update = False
101
+ self .need_recalc_view = False
102
102
103
103
def mouseReleaseEvent (self , ev ):
104
104
if hasattr (self , 'mousePos' ):
105
105
delattr (self , 'mousePos' )
106
106
107
107
def set_dist (self , dist ):
108
108
self .dist = dist
109
- self .view_need_update = True
109
+ self .need_recalc_view = True
110
110
111
111
def update_dist (self , delta ):
112
112
self .dist += delta
113
113
if self .dist < 0.1 :
114
114
self .dist = 0.1
115
- self .view_need_update = True
115
+ self .need_recalc_view = True
116
116
117
117
def wheelEvent (self , ev ):
118
118
delta = ev .angleDelta ().x ()
@@ -121,6 +121,24 @@ def wheelEvent(self, ev):
121
121
self .update_dist (- delta * self .dist * 0.001 )
122
122
self .show_center = True
123
123
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
+
124
142
def mouseMoveEvent (self , ev ):
125
143
lpos = ev .localPos ()
126
144
if not hasattr (self , 'mousePos' ):
@@ -131,24 +149,26 @@ def mouseMoveEvent(self, ev):
131
149
rot_speed = 0.2
132
150
dyaw = radians (- diff .x () * rot_speed )
133
151
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 )
135
156
elif ev .buttons () == QtCore .Qt .MouseButton .LeftButton :
136
157
Rwc = euler_to_matrix (self .euler )
137
158
Kinv = np .linalg .inv (self .get_K ())
138
159
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 )
140
161
self .show_center = True
141
- self .view_need_update = True
142
162
143
163
def set_center (self , center ):
144
164
self .center = center
145
- self .view_need_update = True
165
+ self .need_recalc_view = True
146
166
147
167
def paintGL (self ):
148
168
# if the camera is moved, update the model view matrix.
149
- if self .view_need_update :
169
+ if self .need_recalc_view :
150
170
self .view_matrix = self .get_view_matrix ()
151
- self .view_need_update = False
171
+ self .need_recalc_view = False
152
172
self .update_model_view ()
153
173
154
174
# set the background color
@@ -192,45 +212,48 @@ def update_movement(self):
192
212
return
193
213
rot_speed = 0.5
194
214
trans_speed = max (self .dist * 0.005 , 0.1 )
215
+ shift_pressed = QtCore .Qt .Key_Shift in self .active_keys
195
216
# Handle rotation keys
196
217
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 )
199
222
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 )
202
227
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 ))
205
232
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 ))
208
237
# Handle zoom keys
209
238
xz_keys = {QtCore .Qt .Key_Z , QtCore .Qt .Key_X }
210
239
if self .active_keys & xz_keys :
211
240
Rwc = euler_to_matrix (self .euler )
212
241
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 ]))
215
243
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 ]))
218
245
# Handle translation keys on the z plane
219
246
dir_keys = {QtCore .Qt .Key_W , QtCore .Qt .Key_S , QtCore .Qt .Key_A , QtCore .Qt .Key_D }
220
247
if self .active_keys & dir_keys :
221
248
Rz = euler_to_matrix ([0 , 0 , self .euler [2 ]])
222
249
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 ]))
225
251
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 ]))
228
253
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 ]))
231
255
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 ]))
234
257
235
258
def update_model_view (self ):
236
259
glMatrixMode (GL_MODELVIEW )
@@ -259,7 +282,7 @@ def set_cam_position(self, **kwargs):
259
282
260
283
def set_euler (self , euler ):
261
284
self .euler = euler
262
- self .view_need_update = True
285
+ self .need_recalc_view = True
263
286
264
287
def set_color (self , color ):
265
288
self .color = color
@@ -303,6 +326,11 @@ def rotate(self, rx=0, ry=0, rz=0):
303
326
self .euler [2 ] = (self .euler [2 ] + np .pi ) % (2 * np .pi ) - np .pi
304
327
self .euler [1 ] = (self .euler [1 ] + np .pi ) % (2 * np .pi ) - np .pi
305
328
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
306
334
307
335
def change_show_center (self , state ):
308
336
self .enable_show_center = state
0 commit comments