q3dviewer 1.1.1__py3-none-any.whl → 1.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- q3dviewer/base_glwidget.py +59 -31
- q3dviewer/custom_items/image_item.py +2 -7
- q3dviewer/tools/film_maker.py +25 -10
- {q3dviewer-1.1.1.dist-info → q3dviewer-1.1.3.dist-info}/METADATA +1 -2
- {q3dviewer-1.1.1.dist-info → q3dviewer-1.1.3.dist-info}/RECORD +9 -9
- {q3dviewer-1.1.1.dist-info → q3dviewer-1.1.3.dist-info}/LICENSE +0 -0
- {q3dviewer-1.1.1.dist-info → q3dviewer-1.1.3.dist-info}/WHEEL +0 -0
- {q3dviewer-1.1.1.dist-info → q3dviewer-1.1.3.dist-info}/entry_points.txt +0 -0
- {q3dviewer-1.1.1.dist-info → q3dviewer-1.1.3.dist-info}/top_level.txt +0 -0
q3dviewer/base_glwidget.py
CHANGED
|
@@ -25,7 +25,7 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
|
|
|
25
25
|
self.active_keys = set()
|
|
26
26
|
self.show_center = False
|
|
27
27
|
self.enable_show_center = True
|
|
28
|
-
self.
|
|
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,7 +98,7 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
|
|
|
98
98
|
|
|
99
99
|
def set_view_matrix(self, view_matrix):
|
|
100
100
|
self.view_matrix = view_matrix
|
|
101
|
-
self.
|
|
101
|
+
self.need_recalc_view = False
|
|
102
102
|
|
|
103
103
|
def mouseReleaseEvent(self, ev):
|
|
104
104
|
if hasattr(self, 'mousePos'):
|
|
@@ -106,13 +106,13 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
|
|
|
106
106
|
|
|
107
107
|
def set_dist(self, dist):
|
|
108
108
|
self.dist = dist
|
|
109
|
-
self.
|
|
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.
|
|
115
|
+
self.need_recalc_view = True
|
|
116
116
|
|
|
117
117
|
def wheelEvent(self, ev):
|
|
118
118
|
delta = ev.angleDelta().x()
|
|
@@ -121,6 +121,24 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
|
|
|
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 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
|
|
|
131
149
|
rot_speed = 0.2
|
|
132
150
|
dyaw = radians(-diff.x() * rot_speed)
|
|
133
151
|
droll = radians(-diff.y() * rot_speed)
|
|
134
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
169
|
+
if self.need_recalc_view:
|
|
150
170
|
self.view_matrix = self.get_view_matrix()
|
|
151
|
-
self.
|
|
171
|
+
self.need_recalc_view = False
|
|
152
172
|
self.update_model_view()
|
|
153
173
|
|
|
154
174
|
# set the background color
|
|
@@ -192,45 +212,48 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
|
|
|
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
|
-
|
|
198
|
-
|
|
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
|
-
|
|
201
|
-
|
|
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
|
-
|
|
204
|
-
|
|
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
|
-
|
|
207
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
|
|
|
259
282
|
|
|
260
283
|
def set_euler(self, euler):
|
|
261
284
|
self.euler = euler
|
|
262
|
-
self.
|
|
285
|
+
self.need_recalc_view = True
|
|
263
286
|
|
|
264
287
|
def set_color(self, color):
|
|
265
288
|
self.color = color
|
|
@@ -303,6 +326,11 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
|
|
|
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
|
|
@@ -7,7 +7,6 @@ from q3dviewer.base_item import BaseItem
|
|
|
7
7
|
from OpenGL.GL import *
|
|
8
8
|
import numpy as np
|
|
9
9
|
from OpenGL.GL import shaders
|
|
10
|
-
from PIL import Image as PIL_Image
|
|
11
10
|
from PySide6.QtWidgets import QLabel, QSpinBox, QCheckBox
|
|
12
11
|
|
|
13
12
|
|
|
@@ -108,12 +107,8 @@ class ImageItem(BaseItem):
|
|
|
108
107
|
glBindVertexArray(0)
|
|
109
108
|
|
|
110
109
|
def set_data(self, data):
|
|
111
|
-
if isinstance(data, np.ndarray):
|
|
112
|
-
|
|
113
|
-
elif isinstance(data, PIL_Image.Image):
|
|
114
|
-
data = np.array(data)
|
|
115
|
-
else:
|
|
116
|
-
print("not support image type")
|
|
110
|
+
if not isinstance(data, np.ndarray):
|
|
111
|
+
print("The image type is not supported.")
|
|
117
112
|
raise NotImplementedError
|
|
118
113
|
|
|
119
114
|
if data.ndim == 2: # Grayscale image
|
q3dviewer/tools/film_maker.py
CHANGED
|
@@ -107,7 +107,7 @@ class CMMViewer(q3d.Viewer):
|
|
|
107
107
|
label_codec = QLabel("Codec:")
|
|
108
108
|
codec_layout.addWidget(label_codec)
|
|
109
109
|
self.codec_combo = QComboBox()
|
|
110
|
-
self.codec_combo.addItems(["
|
|
110
|
+
self.codec_combo.addItems(["libx264", "mjpeg", "mpeg4", "libx265"])
|
|
111
111
|
codec_layout.addWidget(self.codec_combo)
|
|
112
112
|
setting_layout.addLayout(codec_layout)
|
|
113
113
|
|
|
@@ -143,6 +143,8 @@ class CMMViewer(q3d.Viewer):
|
|
|
143
143
|
dock_widget = QDockWidget("Settings", self)
|
|
144
144
|
dock_widget.setWidget(QWidget())
|
|
145
145
|
dock_widget.widget().setLayout(setting_layout)
|
|
146
|
+
# Hide close and undock buttons, I don't want the user to close the dock
|
|
147
|
+
dock_widget.setFeatures(QDockWidget.DockWidgetMovable)
|
|
146
148
|
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock_widget)
|
|
147
149
|
|
|
148
150
|
# Add the dock widget to the main layout
|
|
@@ -308,14 +310,16 @@ class CMMViewer(q3d.Viewer):
|
|
|
308
310
|
|
|
309
311
|
def start_recording(self):
|
|
310
312
|
self.is_recording = True
|
|
311
|
-
self.
|
|
313
|
+
self.prv_frame_shape = None
|
|
312
314
|
video_path = self.video_path_edit.text()
|
|
313
315
|
codec = self.codec_combo.currentText()
|
|
314
316
|
self.play_button.setStyleSheet("background-color: red")
|
|
315
317
|
self.play_button.setText("Recording")
|
|
316
318
|
self.writer = imageio.get_writer(video_path,
|
|
317
319
|
fps=self.update_interval,
|
|
318
|
-
codec=codec
|
|
320
|
+
codec=codec,
|
|
321
|
+
quality=10,
|
|
322
|
+
pixelformat='yuvj420p')
|
|
319
323
|
# disable the all the frame_item while recording
|
|
320
324
|
for frame in self.key_frames:
|
|
321
325
|
frame.item.hide()
|
|
@@ -323,6 +327,7 @@ class CMMViewer(q3d.Viewer):
|
|
|
323
327
|
|
|
324
328
|
def stop_recording(self, save_movie=True):
|
|
325
329
|
self.is_recording = False
|
|
330
|
+
self.prv_frame_shape = None
|
|
326
331
|
self.record_checkbox.setChecked(False)
|
|
327
332
|
# enable the all the frame_item after recording
|
|
328
333
|
for frame in self.key_frames:
|
|
@@ -342,17 +347,27 @@ class CMMViewer(q3d.Viewer):
|
|
|
342
347
|
|
|
343
348
|
def record_frame(self):
|
|
344
349
|
frame = self.glwidget.capture_frame()
|
|
345
|
-
|
|
350
|
+
|
|
351
|
+
# restart recording if the window size changes
|
|
352
|
+
if self.prv_frame_shape is not None and frame.shape != self.prv_frame_shape:
|
|
353
|
+
self.writer.close()
|
|
354
|
+
self.start_recording()
|
|
355
|
+
return
|
|
356
|
+
self.prv_frame_shape = frame.shape
|
|
357
|
+
|
|
346
358
|
height, width, _ = frame.shape
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
359
|
+
# Adjust frame dimensions to be multiples of 16
|
|
360
|
+
new_height = height - (height % 16)
|
|
361
|
+
new_width = width - (width % 16)
|
|
362
|
+
frame = frame[:new_height, :new_width, :]
|
|
363
|
+
frame = np.ascontiguousarray(frame)
|
|
351
364
|
try:
|
|
352
365
|
self.writer.append_data(frame)
|
|
353
366
|
except Exception as e:
|
|
354
|
-
|
|
355
|
-
|
|
367
|
+
# unexpected error, stop recording without saving
|
|
368
|
+
print("Error while recording:")
|
|
369
|
+
print(e)
|
|
370
|
+
self.stop_recording(False)
|
|
356
371
|
self.stop_playback()
|
|
357
372
|
|
|
358
373
|
def eventFilter(self, obj, event):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: q3dviewer
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.3
|
|
4
4
|
Summary: A library designed for quickly deploying a 3D viewer.
|
|
5
5
|
Home-page: https://github.com/scomup/q3dviewer
|
|
6
6
|
Author: Liu Yang
|
|
@@ -16,7 +16,6 @@ Requires-Dist: imageio[ffmpeg]
|
|
|
16
16
|
Requires-Dist: laspy
|
|
17
17
|
Requires-Dist: meshio
|
|
18
18
|
Requires-Dist: numpy
|
|
19
|
-
Requires-Dist: pillow
|
|
20
19
|
Requires-Dist: pye57
|
|
21
20
|
Requires-Dist: pypcd4
|
|
22
21
|
Requires-Dist: pyside6
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
q3dviewer/__init__.py,sha256=rP5XX_x8g7hxIMqNHlU89BN4dt5MSvoYYwip68fCmhc,173
|
|
2
|
-
q3dviewer/base_glwidget.py,sha256=
|
|
2
|
+
q3dviewer/base_glwidget.py,sha256=yQb4ckj4ldmiFoKL_TdZAqZNeBnMeSRDhLbMaruM3nk,12298
|
|
3
3
|
q3dviewer/base_item.py,sha256=lzb04oRaS4rRJrAP6C1Bu4ugK237FgupMTB97zjNVFw,1768
|
|
4
4
|
q3dviewer/basic_window.py,sha256=CFErOPRMysFcCqq3vhDsQ-xZzLArO3m1yABCTIhq5do,7946
|
|
5
5
|
q3dviewer/cloud_viewer.py,sha256=IxxrB6Sl6aPCr9P9QzKHGkMcDP_DjsBWbkmIbsAoIM4,2358
|
|
@@ -15,7 +15,7 @@ q3dviewer/custom_items/cloud_item.py,sha256=s46TxNDw7E6DW3V-ek_PF7egB3kRbnqpOBNU
|
|
|
15
15
|
q3dviewer/custom_items/frame_item.py,sha256=6BOM3MXi-Akv6KUXDC3QYEAXKxwk0Eo1KQn-F7jkqrQ,7559
|
|
16
16
|
q3dviewer/custom_items/gaussian_item.py,sha256=CZoXMmj2JPFfMqu7v4q4dLUI2cg_WfE1DHWGXjEYn6M,9869
|
|
17
17
|
q3dviewer/custom_items/grid_item.py,sha256=20n4TGm5YEaudhnEOCOk-HtsKwxVxaPr8YV36kO04yU,4802
|
|
18
|
-
q3dviewer/custom_items/image_item.py,sha256=
|
|
18
|
+
q3dviewer/custom_items/image_item.py,sha256=3FYAVlNLEILKZplkt2wbL8y16ke124GmwxcSmWmJY8Q,5357
|
|
19
19
|
q3dviewer/custom_items/line_item.py,sha256=u0oFN2iHzsRHtnbvyvC_iglEkCwEU2NnTuE536sKUAE,4348
|
|
20
20
|
q3dviewer/custom_items/text_item.py,sha256=nuHMVMQrwy50lNk9hxB94criFxbJJK-SYiK2fSXWUMQ,2158
|
|
21
21
|
q3dviewer/custom_items/trajectory_item.py,sha256=uoKQSrTs_m_m1M8iNAm3peiXnZ9uVPsYQLYas3Gksjg,2754
|
|
@@ -28,7 +28,7 @@ q3dviewer/shaders/sort_by_key.glsl,sha256=CA2zOcbyDGYAJSJEUvgjUqNshg9NAehf8ipL3J
|
|
|
28
28
|
q3dviewer/tools/__init__.py,sha256=01wG7BGM6VX0QyFBKsqPmyf2e-vrmV_N3-mo-VQ1VBg,20
|
|
29
29
|
q3dviewer/tools/cloud_viewer.py,sha256=10f2LSWpmsXzxrGobXw188doVjJbgBfPoqZPUi35EtI,3867
|
|
30
30
|
q3dviewer/tools/example_viewer.py,sha256=yeVXT0k4-h1vTLKnGzWADZD3our6XUaYUTy0p5daTkE,959
|
|
31
|
-
q3dviewer/tools/film_maker.py,sha256=
|
|
31
|
+
q3dviewer/tools/film_maker.py,sha256=KXl0H03vnS7eAFw7nSRvTG3J0Y7gYt6YFUYaoxJf3xM,16600
|
|
32
32
|
q3dviewer/tools/gaussian_viewer.py,sha256=vIwWmiFhjNmknrEkBLzt2yiegeH7LP3OeNjnGM6GzaI,1633
|
|
33
33
|
q3dviewer/tools/lidar_calib.py,sha256=M01bGg2mT8LwVcYybolr4UW_UUaR-f-BFciEHtjeK-w,10488
|
|
34
34
|
q3dviewer/tools/lidar_cam_calib.py,sha256=SYNLDvi15MX7Q3aGn771fvu1cES9xeXgP0_WmDq33w4,11200
|
|
@@ -39,9 +39,9 @@ q3dviewer/utils/convert_ros_msg.py,sha256=sAoQfy3qLQKsIArBAVm8H--wlQXOcmkKK3-Ox9
|
|
|
39
39
|
q3dviewer/utils/gl_helper.py,sha256=dRY_kUqyPMr7NTcupUr6_VTvgnj53iE2C0Lk0-oFYsI,1435
|
|
40
40
|
q3dviewer/utils/maths.py,sha256=5TmjWUX1K3UjygXxrUsydjbo7tPzu0gD-yy7qtQUGBU,10588
|
|
41
41
|
q3dviewer/utils/range_slider.py,sha256=jZJQL-uQgnpgLvtYSWpKTrJlLkt3aqNpaRQAePEpNd0,3174
|
|
42
|
-
q3dviewer-1.1.
|
|
43
|
-
q3dviewer-1.1.
|
|
44
|
-
q3dviewer-1.1.
|
|
45
|
-
q3dviewer-1.1.
|
|
46
|
-
q3dviewer-1.1.
|
|
47
|
-
q3dviewer-1.1.
|
|
42
|
+
q3dviewer-1.1.3.dist-info/LICENSE,sha256=81cMOyNfw8KLb1JnPYngGHJ5W83gSbZEBU9MEP3tl-E,1124
|
|
43
|
+
q3dviewer-1.1.3.dist-info/METADATA,sha256=AXXroAQRcP2jMPxZCzpiR0tu-Ykj2lHUg28rQQZvM6I,7010
|
|
44
|
+
q3dviewer-1.1.3.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
|
|
45
|
+
q3dviewer-1.1.3.dist-info/entry_points.txt,sha256=EOjker7XYaBk70ffvNB_knPcfA33Bnlg21ZjEeM1EyI,362
|
|
46
|
+
q3dviewer-1.1.3.dist-info/top_level.txt,sha256=HFFDCbGu28txcGe2HPc46A7EPaguBa_b5oH7bufmxHM,10
|
|
47
|
+
q3dviewer-1.1.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|