q3dviewer 1.1.5__py3-none-any.whl → 1.1.7__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/Qt/__init__.py +68 -0
- q3dviewer/__init__.py +9 -0
- q3dviewer/base_glwidget.py +4 -3
- q3dviewer/base_item.py +2 -3
- q3dviewer/custom_items/__init__.py +9 -9
- q3dviewer/custom_items/axis_item.py +1 -2
- q3dviewer/custom_items/cloud_io_item.py +9 -1
- q3dviewer/custom_items/cloud_item.py +19 -11
- q3dviewer/custom_items/frame_item.py +3 -3
- q3dviewer/custom_items/gaussian_item.py +2 -2
- q3dviewer/custom_items/grid_item.py +2 -2
- q3dviewer/custom_items/image_item.py +2 -1
- q3dviewer/custom_items/line_item.py +2 -2
- q3dviewer/custom_items/text_item.py +6 -8
- q3dviewer/glwidget.py +4 -6
- q3dviewer/shaders/cloud_vert.glsl +9 -0
- q3dviewer/tools/cloud_viewer.py +2 -2
- q3dviewer/tools/example_viewer.py +1 -1
- q3dviewer/tools/film_maker.py +9 -8
- q3dviewer/tools/lidar_calib.py +9 -8
- q3dviewer/tools/lidar_cam_calib.py +10 -9
- q3dviewer/utils/__init__.py +2 -4
- q3dviewer/utils/cloud_io.py +21 -10
- q3dviewer/utils/helpers.py +97 -0
- q3dviewer/utils/maths.py +0 -58
- q3dviewer/utils/range_slider.py +28 -9
- q3dviewer/viewer.py +5 -2
- {q3dviewer-1.1.5.dist-info → q3dviewer-1.1.7.dist-info}/METADATA +11 -13
- q3dviewer-1.1.7.dist-info/RECORD +49 -0
- {q3dviewer-1.1.5.dist-info → q3dviewer-1.1.7.dist-info}/WHEEL +1 -1
- {q3dviewer-1.1.5.dist-info → q3dviewer-1.1.7.dist-info}/entry_points.txt +0 -1
- q3dviewer-1.1.5.dist-info/RECORD +0 -47
- {q3dviewer-1.1.5.dist-info → q3dviewer-1.1.7.dist-info}/LICENSE +0 -0
- {q3dviewer-1.1.5.dist-info → q3dviewer-1.1.7.dist-info}/top_level.txt +0 -0
q3dviewer/Qt/__init__.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Copyright 2024 Panasonic Advanced Technology Development Co.,Ltd. (Liu Yang)
|
|
5
|
+
Distributed under MIT license. See LICENSE for more information.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
You can use the following code to set the Q3D_QT_IMPL environment variable
|
|
10
|
+
# tested for PyQt5, PySide2 and PySide6
|
|
11
|
+
# -------------------------------
|
|
12
|
+
in your python script before importing QT:
|
|
13
|
+
import os
|
|
14
|
+
os.environ['Q3D_QT_IMPL'] = 'PySide6'
|
|
15
|
+
or in your bash:
|
|
16
|
+
export Q3D_QT_IMPL=PyQt5
|
|
17
|
+
# -------------------------------
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import importlib.util
|
|
21
|
+
import builtins
|
|
22
|
+
import sys
|
|
23
|
+
import os
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
Q3D_QT_IMPL = os.environ.get('Q3D_QT_IMPL')
|
|
27
|
+
Q3D_DEBUG = os.environ.get('Q3D_DEBUG')
|
|
28
|
+
|
|
29
|
+
if Q3D_QT_IMPL not in ['PyQt5', 'PySide2', 'PySide6']:
|
|
30
|
+
Q3D_QT_IMPL = None
|
|
31
|
+
|
|
32
|
+
if Q3D_QT_IMPL is None:
|
|
33
|
+
if importlib.util.find_spec('PyQt5') is not None:
|
|
34
|
+
Q3D_QT_IMPL = 'PyQt5'
|
|
35
|
+
elif importlib.util.find_spec('PySide6') is not None:
|
|
36
|
+
Q3D_QT_IMPL = 'PySide6'
|
|
37
|
+
else:
|
|
38
|
+
raise ImportError('No Qt binding found. Please install PySide6.')
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def import_module(name):
|
|
42
|
+
module = builtins.__import__(f'{Q3D_QT_IMPL}.{name}').__dict__[name]
|
|
43
|
+
sys.modules[f'{__name__}.{name}'] = module
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def load_qt():
|
|
47
|
+
if Q3D_DEBUG is not None:
|
|
48
|
+
print(f'Using {Q3D_QT_IMPL} as Qt binding.')
|
|
49
|
+
|
|
50
|
+
# register common Qt modules
|
|
51
|
+
modules = ['QtCore', 'QtGui', 'QtWidgets']
|
|
52
|
+
for name in modules:
|
|
53
|
+
import_module(name)
|
|
54
|
+
# register OpenGL modules for PySide6
|
|
55
|
+
if Q3D_QT_IMPL == 'PySide6':
|
|
56
|
+
import_module('QtOpenGLWidgets')
|
|
57
|
+
sys.modules[f'{__name__}.QtWidgets'].QOpenGLWidget = sys.modules[f'{__name__}.QtOpenGLWidgets'].QOpenGLWidget
|
|
58
|
+
# make PyQt5 and PySide6 modules compatible
|
|
59
|
+
if Q3D_QT_IMPL == 'PyQt5':
|
|
60
|
+
sys.modules[f'{__name__}.QtCore'].Signal = sys.modules[f'{__name__}.QtCore'].pyqtSignal
|
|
61
|
+
sys.modules[f'{__name__}.QtCore'].Slot = sys.modules[f'{__name__}.QtCore'].pyqtSlot
|
|
62
|
+
sys.modules[f'{__name__}.QtCore'].Property = sys.modules[f'{__name__}.QtCore'].pyqtProperty
|
|
63
|
+
# Handle exec() for PySide2
|
|
64
|
+
if Q3D_QT_IMPL == 'PySide2':
|
|
65
|
+
sys.modules[f'{__name__}.QtWidgets'].QApplication.exec = sys.modules[f'{__name__}.QtWidgets'].QApplication.exec_
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
load_qt()
|
q3dviewer/__init__.py
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
+
import time
|
|
2
|
+
t1 = time.time()
|
|
1
3
|
from q3dviewer.custom_items import *
|
|
4
|
+
t2 = time.time()
|
|
2
5
|
from q3dviewer.glwidget import *
|
|
3
6
|
from q3dviewer.viewer import *
|
|
4
7
|
from q3dviewer.base_item import *
|
|
5
8
|
from q3dviewer.base_glwidget import *
|
|
9
|
+
t3 = time.time()
|
|
10
|
+
|
|
11
|
+
from q3dviewer.Qt import Q3D_DEBUG
|
|
12
|
+
if Q3D_DEBUG:
|
|
13
|
+
print("Import custom items: ", t2 - t1)
|
|
14
|
+
print("Import base q3dviewer: ", t3 - t2)
|
q3dviewer/base_glwidget.py
CHANGED
|
@@ -6,13 +6,14 @@ Distributed under MIT license. See LICENSE for more information.
|
|
|
6
6
|
from OpenGL.GL import *
|
|
7
7
|
from math import radians, tan
|
|
8
8
|
import numpy as np
|
|
9
|
-
from
|
|
9
|
+
from q3dviewer.Qt import QtCore, QtGui
|
|
10
10
|
from q3dviewer.utils.maths import frustum, euler_to_matrix, makeT
|
|
11
|
+
from q3dviewer.Qt.QtWidgets import QOpenGLWidget
|
|
11
12
|
|
|
12
13
|
|
|
13
|
-
class BaseGLWidget(
|
|
14
|
+
class BaseGLWidget(QOpenGLWidget):
|
|
14
15
|
def __init__(self, parent=None):
|
|
15
|
-
|
|
16
|
+
QOpenGLWidget.__init__(self, parent)
|
|
16
17
|
self.setFocusPolicy(QtCore.Qt.FocusPolicy.ClickFocus)
|
|
17
18
|
self.reset()
|
|
18
19
|
self._fov = 60
|
q3dviewer/base_item.py
CHANGED
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
Copyright 2024 Panasonic Advanced Technology Development Co.,Ltd. (Liu Yang)
|
|
3
3
|
Distributed under MIT license. See LICENSE for more information.
|
|
4
4
|
"""
|
|
5
|
+
from q3dviewer.Qt.QtCore import QObject
|
|
5
6
|
|
|
6
|
-
from PySide6 import QtCore
|
|
7
|
-
import numpy as np
|
|
8
7
|
|
|
9
|
-
class BaseItem(
|
|
8
|
+
class BaseItem(QObject):
|
|
10
9
|
_next_id = 0
|
|
11
10
|
|
|
12
11
|
def __init__(self):
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
from q3dviewer.custom_items.axis_item import
|
|
2
|
-
from q3dviewer.custom_items.cloud_item import
|
|
3
|
-
from q3dviewer.custom_items.cloud_io_item import
|
|
4
|
-
from q3dviewer.custom_items.gaussian_item import
|
|
5
|
-
from q3dviewer.custom_items.frame_item import
|
|
6
|
-
from q3dviewer.custom_items.grid_item import
|
|
7
|
-
from q3dviewer.custom_items.text_item import
|
|
8
|
-
from q3dviewer.custom_items.image_item import
|
|
9
|
-
from q3dviewer.custom_items.line_item import
|
|
1
|
+
from q3dviewer.custom_items.axis_item import AxisItem
|
|
2
|
+
from q3dviewer.custom_items.cloud_item import CloudItem
|
|
3
|
+
from q3dviewer.custom_items.cloud_io_item import CloudIOItem
|
|
4
|
+
from q3dviewer.custom_items.gaussian_item import GaussianItem
|
|
5
|
+
from q3dviewer.custom_items.frame_item import FrameItem
|
|
6
|
+
from q3dviewer.custom_items.grid_item import GridItem
|
|
7
|
+
from q3dviewer.custom_items.text_item import Text2DItem
|
|
8
|
+
from q3dviewer.custom_items.image_item import ImageItem
|
|
9
|
+
from q3dviewer.custom_items.line_item import LineItem
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
Copyright 2024 Panasonic Advanced Technology Development Co.,Ltd. (Liu Yang)
|
|
3
3
|
Distributed under MIT license. See LICENSE for more information.
|
|
4
4
|
"""
|
|
5
|
-
|
|
6
5
|
from q3dviewer.base_item import BaseItem
|
|
7
6
|
from OpenGL.GL import *
|
|
8
7
|
import numpy as np
|
|
9
|
-
from
|
|
8
|
+
from q3dviewer.Qt.QtWidgets import QDoubleSpinBox
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class AxisItem(BaseItem):
|
|
@@ -6,7 +6,7 @@ Distributed under MIT license. See LICENSE for more information.
|
|
|
6
6
|
from q3dviewer.custom_items.cloud_item import CloudItem
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
import os
|
|
9
|
-
from
|
|
9
|
+
from q3dviewer.Qt.QtWidgets import QPushButton, QLabel, QLineEdit, QMessageBox
|
|
10
10
|
from q3dviewer.utils.cloud_io import save_pcd, save_ply, save_e57, save_las, load_pcd, load_ply, load_e57, load_las
|
|
11
11
|
|
|
12
12
|
class CloudIOItem(CloudItem):
|
|
@@ -38,12 +38,16 @@ class CloudIOItem(CloudItem):
|
|
|
38
38
|
cloud = self.buff[:self.valid_buff_top]
|
|
39
39
|
func = None
|
|
40
40
|
if self.save_path.endswith(".pcd"):
|
|
41
|
+
from q3dviewer.utils.cloud_io import save_pcd
|
|
41
42
|
func = save_pcd
|
|
42
43
|
elif self.save_path.endswith(".ply"):
|
|
44
|
+
from q3dviewer.utils.cloud_io import save_ply
|
|
43
45
|
func = save_ply
|
|
44
46
|
elif self.save_path.endswith(".e57"):
|
|
47
|
+
from q3dviewer.utils.cloud_io import save_e57
|
|
45
48
|
func = save_e57
|
|
46
49
|
elif self.save_path.endswith(".las"):
|
|
50
|
+
from q3dviewer.utils.cloud_io import save_las
|
|
47
51
|
func = save_las
|
|
48
52
|
elif self.save_path.endswith(".tif") or self.save_path.endswith(".tiff"):
|
|
49
53
|
print("Do not support save as tif type!")
|
|
@@ -61,12 +65,16 @@ class CloudIOItem(CloudItem):
|
|
|
61
65
|
def load(self, file, append=False):
|
|
62
66
|
# print("Try to load %s ..." % file)
|
|
63
67
|
if file.endswith(".pcd"):
|
|
68
|
+
from q3dviewer.utils.cloud_io import load_pcd
|
|
64
69
|
cloud = load_pcd(file)
|
|
65
70
|
elif file.endswith(".ply"):
|
|
71
|
+
from q3dviewer.utils.cloud_io import load_ply
|
|
66
72
|
cloud = load_ply(file)
|
|
67
73
|
elif file.endswith(".e57"):
|
|
74
|
+
from q3dviewer.utils.cloud_io import load_e57
|
|
68
75
|
cloud = load_e57(file)
|
|
69
76
|
elif file.endswith(".las"):
|
|
77
|
+
from q3dviewer.utils.cloud_io import load_las
|
|
70
78
|
cloud = load_las(file)
|
|
71
79
|
else:
|
|
72
80
|
print("Not supported file type.")
|
|
@@ -7,13 +7,15 @@ Distributed under MIT license. See LICENSE for more information.
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
from q3dviewer.base_item import BaseItem
|
|
9
9
|
from OpenGL.GL import *
|
|
10
|
+
from OpenGL.GL import shaders
|
|
11
|
+
|
|
10
12
|
import threading
|
|
11
13
|
import os
|
|
12
|
-
from
|
|
13
|
-
QComboBox, QCheckBox
|
|
14
|
-
from OpenGL.GL import shaders
|
|
15
|
-
from q3dviewer.utils import *
|
|
14
|
+
from q3dviewer.Qt.QtWidgets import QLabel, QLineEdit, QDoubleSpinBox, QComboBox, QCheckBox
|
|
16
15
|
from q3dviewer.utils.range_slider import RangeSlider
|
|
16
|
+
from q3dviewer.utils import set_uniform
|
|
17
|
+
from q3dviewer.utils import text_to_rgba
|
|
18
|
+
from q3dviewer.Qt import Q3D_DEBUG
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
# draw points with color (x, y, z, color)
|
|
@@ -38,7 +40,7 @@ class CloudItem(BaseItem):
|
|
|
38
40
|
except ValueError:
|
|
39
41
|
print(f"Invalid color: {color}, please use matplotlib color format")
|
|
40
42
|
exit(1)
|
|
41
|
-
self.mode_table = {'FLAT': 0, 'I': 1, 'RGB': 2}
|
|
43
|
+
self.mode_table = {'FLAT': 0, 'I': 1, 'RGB': 2, 'GRAY': 3}
|
|
42
44
|
self.point_type_table = {'PIXEL': 0, 'SQUARE': 1, 'SPHERE': 2}
|
|
43
45
|
self.color_mode = self.mode_table[color_mode]
|
|
44
46
|
self.CAPACITY = 10000000 # 10MB * 3 (x,y,z, color) * 4
|
|
@@ -87,6 +89,7 @@ class CloudItem(BaseItem):
|
|
|
87
89
|
self.combo_color.addItem("flat color")
|
|
88
90
|
self.combo_color.addItem("intensity")
|
|
89
91
|
self.combo_color.addItem("RGB")
|
|
92
|
+
self.combo_color.addItem("gray")
|
|
90
93
|
self.combo_color.setCurrentIndex(self.color_mode)
|
|
91
94
|
self.combo_color.currentIndexChanged.connect(self._on_color_mode)
|
|
92
95
|
layout.addWidget(self.combo_color)
|
|
@@ -125,10 +128,13 @@ class CloudItem(BaseItem):
|
|
|
125
128
|
self.edit_rgb.show()
|
|
126
129
|
elif (index == self.mode_table['I']): # flat color
|
|
127
130
|
self.slider_v.show()
|
|
131
|
+
elif (index == self.mode_table['GRAY']): # flat color
|
|
132
|
+
self.slider_v.show()
|
|
133
|
+
|
|
128
134
|
self.need_update_setting = True
|
|
129
135
|
|
|
130
136
|
def set_color_mode(self, color_mode):
|
|
131
|
-
if color_mode in {'FLAT', 'RGB', 'I'}:
|
|
137
|
+
if color_mode in {'FLAT', 'RGB', 'I', 'GRAY'}:
|
|
132
138
|
try:
|
|
133
139
|
self.combo_color.setCurrentIndex(self.mode_table[color_mode])
|
|
134
140
|
except:
|
|
@@ -143,14 +149,15 @@ class CloudItem(BaseItem):
|
|
|
143
149
|
self.box_size.setPrefix("Set size (pixel): ")
|
|
144
150
|
self.box_size.setDecimals(0)
|
|
145
151
|
self.box_size.setSingleStep(1)
|
|
146
|
-
self.
|
|
147
|
-
self.size
|
|
152
|
+
self.size = np.ceil(self.size)
|
|
153
|
+
self.box_size.setValue(self.size)
|
|
148
154
|
else:
|
|
149
155
|
self.box_size.setPrefix("Set size (meter): ")
|
|
150
156
|
self.box_size.setDecimals(2)
|
|
151
157
|
self.box_size.setSingleStep(0.01)
|
|
152
|
-
self.
|
|
153
|
-
|
|
158
|
+
if self.size >= 1:
|
|
159
|
+
self.size = self.size * 0.01
|
|
160
|
+
self.box_size.setValue(self.size)
|
|
154
161
|
self.need_update_setting = True
|
|
155
162
|
|
|
156
163
|
def set_alpha(self, alpha):
|
|
@@ -237,7 +244,8 @@ class CloudItem(BaseItem):
|
|
|
237
244
|
buff_capacity = self.buff.shape[0]
|
|
238
245
|
while (new_buff_top > buff_capacity):
|
|
239
246
|
buff_capacity += self.CAPACITY
|
|
240
|
-
|
|
247
|
+
if Q3D_DEBUG is not None:
|
|
248
|
+
print("[Cloud Item] Update capacity to %d" % buff_capacity)
|
|
241
249
|
new_buff = np.empty((buff_capacity), self.data_type)
|
|
242
250
|
new_buff[:self.add_buff_loc] = self.buff[:self.add_buff_loc]
|
|
243
251
|
new_buff[self.add_buff_loc:new_buff_top] = self.wait_add_data
|
|
@@ -4,11 +4,11 @@ Distributed under MIT license. See LICENSE for more information.
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
from q3dviewer.base_item import BaseItem
|
|
7
|
-
from OpenGL.GL import *
|
|
8
7
|
import numpy as np
|
|
8
|
+
from OpenGL.GL import *
|
|
9
9
|
from OpenGL.GL import shaders
|
|
10
|
-
from q3dviewer.utils import
|
|
11
|
-
|
|
10
|
+
from q3dviewer.utils import set_uniform
|
|
11
|
+
from q3dviewer.utils import text_to_rgba
|
|
12
12
|
|
|
13
13
|
# Vertex and Fragment shader source code
|
|
14
14
|
vertex_shader_source = """
|
|
@@ -8,9 +8,9 @@ from q3dviewer.base_item import BaseItem
|
|
|
8
8
|
from OpenGL.GL import *
|
|
9
9
|
import numpy as np
|
|
10
10
|
import os
|
|
11
|
-
from
|
|
11
|
+
from q3dviewer.Qt.QtWidgets import QComboBox, QLabel
|
|
12
12
|
from OpenGL.GL import shaders
|
|
13
|
-
from q3dviewer.utils import
|
|
13
|
+
from q3dviewer.utils import set_uniform
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def div_round_up(x, y):
|
|
@@ -5,9 +5,9 @@ Distributed under MIT license. See LICENSE for more information.
|
|
|
5
5
|
|
|
6
6
|
from q3dviewer.base_item import BaseItem
|
|
7
7
|
from OpenGL.GL import *
|
|
8
|
-
from
|
|
8
|
+
from q3dviewer.Qt.QtWidgets import QDoubleSpinBox
|
|
9
9
|
import numpy as np
|
|
10
|
-
from q3dviewer.utils
|
|
10
|
+
from q3dviewer.utils import text_to_rgba
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class GridItem(BaseItem):
|
|
@@ -5,9 +5,10 @@ Distributed under MIT license. See LICENSE for more information.
|
|
|
5
5
|
|
|
6
6
|
from q3dviewer.base_item import BaseItem
|
|
7
7
|
from OpenGL.GL import *
|
|
8
|
+
|
|
8
9
|
import numpy as np
|
|
9
10
|
from OpenGL.GL import shaders
|
|
10
|
-
from
|
|
11
|
+
from q3dviewer.Qt.QtWidgets import QSpinBox, QCheckBox
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
# Vertex and Fragment shader source code
|
|
@@ -7,8 +7,8 @@ from q3dviewer.base_item import BaseItem
|
|
|
7
7
|
from OpenGL.GL import *
|
|
8
8
|
import numpy as np
|
|
9
9
|
import threading
|
|
10
|
-
from
|
|
11
|
-
from q3dviewer.utils
|
|
10
|
+
from q3dviewer.Qt.QtWidgets import QLabel, QLineEdit, QDoubleSpinBox
|
|
11
|
+
from q3dviewer.utils import text_to_rgba
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class LineItem(BaseItem):
|
|
@@ -3,10 +3,9 @@ Copyright 2024 Panasonic Advanced Technology Development Co.,Ltd. (Liu Yang)
|
|
|
3
3
|
Distributed under MIT license. See LICENSE for more information.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from q3dviewer.Qt import QtCore, QtGui
|
|
7
7
|
from q3dviewer.base_item import BaseItem
|
|
8
|
-
from
|
|
9
|
-
from q3dviewer.utils.maths import text_to_rgba
|
|
8
|
+
from q3dviewer.utils import text_to_rgba
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class Text2DItem(BaseItem):
|
|
@@ -16,12 +15,12 @@ class Text2DItem(BaseItem):
|
|
|
16
15
|
"""All keyword arguments are passed to set_data()"""
|
|
17
16
|
BaseItem.__init__(self)
|
|
18
17
|
self.pos = (20, 50)
|
|
19
|
-
try:
|
|
20
|
-
self.rgb = text_to_rgba(self.color)
|
|
21
|
-
except ValueError:
|
|
22
|
-
raise ValueError("Invalid color format. Use mathplotlib color format.")
|
|
23
18
|
self.text = ''
|
|
24
19
|
self.font = QtGui.QFont('Helvetica', 16)
|
|
20
|
+
|
|
21
|
+
self.rgb = text_to_rgba('w')
|
|
22
|
+
if 'pos' in kwds:
|
|
23
|
+
self.pos = kwds['pos']
|
|
25
24
|
self.set_data(**kwds)
|
|
26
25
|
|
|
27
26
|
def set_data(self, **kwds):
|
|
@@ -47,7 +46,6 @@ class Text2DItem(BaseItem):
|
|
|
47
46
|
def set_color(self, color):
|
|
48
47
|
try:
|
|
49
48
|
self.rgb = text_to_rgba(color)
|
|
50
|
-
self.color = color
|
|
51
49
|
except ValueError:
|
|
52
50
|
print("Invalid color format. Use mathplotlib color format.")
|
|
53
51
|
|
q3dviewer/glwidget.py
CHANGED
|
@@ -3,13 +3,11 @@ Copyright 2024 Panasonic Advanced Technology Development Co.,Ltd. (Liu Yang)
|
|
|
3
3
|
Distributed under MIT license. See LICENSE for more information.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from
|
|
7
|
-
from
|
|
8
|
-
from
|
|
9
|
-
from OpenGL.GL import *
|
|
10
|
-
import numpy as np
|
|
6
|
+
from q3dviewer.Qt import QtCore
|
|
7
|
+
from q3dviewer.Qt.QtWidgets import QWidget, QComboBox, QVBoxLayout, QLabel, QLineEdit, QCheckBox, QGroupBox
|
|
8
|
+
from q3dviewer.Qt.QtGui import QKeyEvent
|
|
11
9
|
from q3dviewer.base_glwidget import BaseGLWidget
|
|
12
|
-
from q3dviewer.utils
|
|
10
|
+
from q3dviewer.utils import text_to_rgba
|
|
13
11
|
|
|
14
12
|
class SettingWindow(QWidget):
|
|
15
13
|
def __init__(self):
|
|
@@ -62,6 +62,15 @@ void main()
|
|
|
62
62
|
c.y = float((value & uint(0x0000FF00)) >> 8)/255.;
|
|
63
63
|
c.x = float((value & uint(0x00FF0000)) >> 16)/255.;
|
|
64
64
|
}
|
|
65
|
+
else if(color_mode == 3)
|
|
66
|
+
{
|
|
67
|
+
uint intensity = value >> 24;
|
|
68
|
+
float range = vmax - vmin;
|
|
69
|
+
float value = 1.0 - (float(intensity) - vmin) / range;
|
|
70
|
+
c.z = value;
|
|
71
|
+
c.y = value;
|
|
72
|
+
c.x = value;
|
|
73
|
+
}
|
|
65
74
|
else
|
|
66
75
|
{
|
|
67
76
|
c.z = float( uint(flat_rgb) & uint(0x000000FF))/255.;
|
q3dviewer/tools/cloud_viewer.py
CHANGED
|
@@ -7,8 +7,8 @@ Distributed under MIT license. See LICENSE for more information.
|
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
9
9
|
import q3dviewer as q3d
|
|
10
|
-
from
|
|
11
|
-
from
|
|
10
|
+
from q3dviewer.Qt.QtWidgets import QVBoxLayout, QProgressBar, QDialog, QLabel
|
|
11
|
+
from q3dviewer.Qt.QtCore import QThread, Signal
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class ProgressDialog(QDialog):
|
q3dviewer/tools/film_maker.py
CHANGED
|
@@ -7,22 +7,23 @@ Distributed under MIT license. See LICENSE for more information.
|
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
9
9
|
import q3dviewer as q3d
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
from q3dviewer.
|
|
13
|
-
from
|
|
14
|
-
from PySide6.QtGui import QKeyEvent
|
|
10
|
+
from q3dviewer.Qt.QtWidgets import QVBoxLayout, QListWidget, QListWidgetItem, QPushButton, QDoubleSpinBox, QCheckBox, QLineEdit, QMessageBox, QLabel, QHBoxLayout, QDockWidget, QWidget, QComboBox
|
|
11
|
+
from q3dviewer.Qt.QtCore import QTimer
|
|
12
|
+
from q3dviewer.Qt.QtGui import QKeyEvent
|
|
13
|
+
from q3dviewer.Qt import QtCore
|
|
15
14
|
from q3dviewer import GLWidget
|
|
15
|
+
from q3dviewer.tools.cloud_viewer import ProgressDialog, FileLoaderThread
|
|
16
|
+
|
|
16
17
|
import imageio.v2 as imageio
|
|
17
18
|
import os
|
|
18
|
-
|
|
19
|
+
from q3dviewer.utils.maths import matrix_to_euler, interpolate_pose
|
|
19
20
|
|
|
20
21
|
def recover_center_euler(Twc, dist):
|
|
21
22
|
Rwc = Twc[:3, :3] # Extract rotation
|
|
22
23
|
twc = Twc[:3, 3] # Extract translation
|
|
23
24
|
tco = np.array([0, 0, dist]) # Camera frame origin
|
|
24
25
|
two = twc - Rwc @ tco # Compute center
|
|
25
|
-
euler =
|
|
26
|
+
euler = matrix_to_euler(Rwc)
|
|
26
27
|
return two, euler
|
|
27
28
|
|
|
28
29
|
|
|
@@ -247,7 +248,7 @@ class CMMViewer(q3d.Viewer):
|
|
|
247
248
|
for j in range(num_steps):
|
|
248
249
|
self.frames.append([i, current_frame.Twc])
|
|
249
250
|
next_frame = self.key_frames[i + 1]
|
|
250
|
-
Ts =
|
|
251
|
+
Ts = interpolate_pose(current_frame.Twc, next_frame.Twc,
|
|
251
252
|
current_frame.lin_vel,
|
|
252
253
|
current_frame.ang_vel,
|
|
253
254
|
dt)
|
q3dviewer/tools/lidar_calib.py
CHANGED
|
@@ -10,10 +10,11 @@ import rospy
|
|
|
10
10
|
import numpy as np
|
|
11
11
|
import argparse
|
|
12
12
|
import q3dviewer as q3d
|
|
13
|
-
from
|
|
14
|
-
|
|
15
|
-
from PySide6 import QtCore
|
|
13
|
+
from q3dviewer.Qt.QtWidgets import QLabel, QLineEdit, QDoubleSpinBox, QSpinBox, QWidget, QVBoxLayout, QHBoxLayout, QPushButton
|
|
14
|
+
from q3dviewer.Qt import QtCore
|
|
16
15
|
from q3dviewer.utils.convert_ros_msg import convert_pointcloud2_msg
|
|
16
|
+
from q3dviewer.utils.maths import matrix_to_quaternion, euler_to_matrix, matrix_to_euler
|
|
17
|
+
|
|
17
18
|
|
|
18
19
|
try:
|
|
19
20
|
import open3d as o3d
|
|
@@ -123,7 +124,7 @@ class LiDARCalibViewer(q3d.Viewer):
|
|
|
123
124
|
|
|
124
125
|
self.line_trans.setText(
|
|
125
126
|
f"[{self.t01[0]:.6f}, {self.t01[1]:.6f}, {self.t01[2]:.6f}]")
|
|
126
|
-
quat =
|
|
127
|
+
quat = matrix_to_quaternion(self.R01)
|
|
127
128
|
self.line_quat.setText(
|
|
128
129
|
f"[{quat[0]:.6f}, {quat[1]:.6f}, {quat[2]:.6f}, {quat[3]:.6f}]")
|
|
129
130
|
|
|
@@ -155,8 +156,8 @@ class LiDARCalibViewer(q3d.Viewer):
|
|
|
155
156
|
roll = self.box_roll.value()
|
|
156
157
|
pitch = self.box_pitch.value()
|
|
157
158
|
yaw = self.box_yaw.value()
|
|
158
|
-
self.R01 =
|
|
159
|
-
quat =
|
|
159
|
+
self.R01 = euler_to_matrix(np.array([roll, pitch, yaw]))
|
|
160
|
+
quat = matrix_to_quaternion(self.R01)
|
|
160
161
|
self.line_quat.setText(
|
|
161
162
|
f"[{quat[0]:.6f}, {quat[1]:.6f}, {quat[2]:.6f}, {quat[3]:.6f}]")
|
|
162
163
|
|
|
@@ -202,8 +203,8 @@ class LiDARCalibViewer(q3d.Viewer):
|
|
|
202
203
|
t01 = transformation_icp[:3, 3]
|
|
203
204
|
|
|
204
205
|
# Update the UI with new values
|
|
205
|
-
quat =
|
|
206
|
-
rpy =
|
|
206
|
+
quat = matrix_to_quaternion(R01)
|
|
207
|
+
rpy = matrix_to_euler(R01)
|
|
207
208
|
self.box_roll.setValue(rpy[0])
|
|
208
209
|
self.box_pitch.setValue(rpy[1])
|
|
209
210
|
self.box_yaw.setValue(rpy[2])
|
|
@@ -9,14 +9,15 @@ from sensor_msgs.msg import PointCloud2, Image, CameraInfo
|
|
|
9
9
|
import rospy
|
|
10
10
|
import numpy as np
|
|
11
11
|
import q3dviewer as q3d
|
|
12
|
-
from
|
|
12
|
+
from q3dviewer.Qt.QtWidgets import QLabel, QLineEdit, QDoubleSpinBox, \
|
|
13
13
|
QSpinBox, QWidget, QVBoxLayout, QHBoxLayout, QCheckBox
|
|
14
|
-
from
|
|
14
|
+
from q3dviewer.Qt import QtCore
|
|
15
15
|
import rospy
|
|
16
16
|
import cv2
|
|
17
17
|
import argparse
|
|
18
18
|
from q3dviewer.utils.convert_ros_msg import convert_pointcloud2_msg, convert_image_msg
|
|
19
|
-
|
|
19
|
+
from q3dviewer.utils.maths import euler_to_matrix, matrix_to_quaternion, matrix_to_euler
|
|
20
|
+
from q3dviewer.utils.helpers import rainbow
|
|
20
21
|
clouds = []
|
|
21
22
|
remap_info = None
|
|
22
23
|
K = None
|
|
@@ -42,7 +43,7 @@ class LidarCamViewer(q3d.Viewer):
|
|
|
42
43
|
# c: camera image frame
|
|
43
44
|
# l: lidar frame
|
|
44
45
|
self.Rbl = np.eye(3)
|
|
45
|
-
self.Rbl =
|
|
46
|
+
self.Rbl = euler_to_matrix(np.array([0.0, 0.0, 0.0]))
|
|
46
47
|
self.Rcb = np.array([[0, -1, 0],
|
|
47
48
|
[0, 0, -1],
|
|
48
49
|
[1, 0, 0]])
|
|
@@ -104,7 +105,7 @@ class LidarCamViewer(q3d.Viewer):
|
|
|
104
105
|
self.box_roll.setRange(-np.pi, np.pi)
|
|
105
106
|
self.box_pitch.setRange(-np.pi, np.pi)
|
|
106
107
|
self.box_yaw.setRange(-np.pi, np.pi)
|
|
107
|
-
rpy =
|
|
108
|
+
rpy = matrix_to_euler(self.Rbl)
|
|
108
109
|
self.box_roll.setValue(rpy[0])
|
|
109
110
|
self.box_pitch.setValue(rpy[1])
|
|
110
111
|
self.box_yaw.setValue(rpy[2])
|
|
@@ -136,7 +137,7 @@ class LidarCamViewer(q3d.Viewer):
|
|
|
136
137
|
|
|
137
138
|
self.line_trans.setText(
|
|
138
139
|
f"[{self.tcl[0]:.6f}, {self.tcl[1]:.6f}, {self.tcl[2]:.6f}]")
|
|
139
|
-
quat =
|
|
140
|
+
quat = matrix_to_quaternion(self.Rcl)
|
|
140
141
|
self.line_quat.setText(
|
|
141
142
|
f"[{quat[0]:.6f}, {quat[1]:.6f}, {quat[2]:.6f}, {quat[3]:.6f}]")
|
|
142
143
|
|
|
@@ -170,9 +171,9 @@ class LidarCamViewer(q3d.Viewer):
|
|
|
170
171
|
roll = self.box_roll.value()
|
|
171
172
|
pitch = self.box_pitch.value()
|
|
172
173
|
yaw = self.box_yaw.value()
|
|
173
|
-
self.Rbl =
|
|
174
|
+
self.Rbl = euler_to_matrix(np.array([roll, pitch, yaw]))
|
|
174
175
|
self.Rcl = self.Rcb @ self.Rbl
|
|
175
|
-
quat =
|
|
176
|
+
quat = matrix_to_quaternion(self.Rcl)
|
|
176
177
|
self.line_quat.setText(
|
|
177
178
|
f"[{quat[0]:.6f}, {quat[1]:.6f}, {quat[2]:.6f}, {quat[3]:.6f}]")
|
|
178
179
|
|
|
@@ -252,7 +253,7 @@ def image_cb(data):
|
|
|
252
253
|
intensity = cloud_local['irgb'][u_mask][valid_points] >> 24
|
|
253
254
|
vmin = viewer['scan'].vmin
|
|
254
255
|
vmax = viewer['scan'].vmax
|
|
255
|
-
intensity_color =
|
|
256
|
+
intensity_color = rainbow(intensity, scalar_min=vmin, scalar_max=vmax).astype(np.uint8)
|
|
256
257
|
draw_image = image_un.copy()
|
|
257
258
|
draw_image = draw_larger_points(draw_image, u, intensity_color, radius)
|
|
258
259
|
rgb = image_un[u[:, 1], u[:, 0]]
|
q3dviewer/utils/__init__.py
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
from q3dviewer.utils.
|
|
2
|
-
from q3dviewer.utils.gl_helper import
|
|
3
|
-
from q3dviewer.utils.range_slider import *
|
|
4
|
-
from q3dviewer.utils.cloud_io import *
|
|
1
|
+
from q3dviewer.utils.helpers import rainbow, text_to_rgba
|
|
2
|
+
from q3dviewer.utils.gl_helper import set_uniform
|
q3dviewer/utils/cloud_io.py
CHANGED
|
@@ -4,13 +4,10 @@ Distributed under MIT license. See LICENSE for more information.
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
|
-
import meshio
|
|
8
|
-
from pypcd4 import PointCloud, MetaData
|
|
9
|
-
from pye57 import E57
|
|
10
|
-
import laspy
|
|
11
7
|
|
|
12
8
|
|
|
13
9
|
def save_ply(cloud, save_path):
|
|
10
|
+
import meshio
|
|
14
11
|
xyz = cloud['xyz']
|
|
15
12
|
i = (cloud['irgb'] & 0xFF000000) >> 24
|
|
16
13
|
rgb = cloud['irgb'] & 0x00FFFFFF
|
|
@@ -20,6 +17,7 @@ def save_ply(cloud, save_path):
|
|
|
20
17
|
|
|
21
18
|
|
|
22
19
|
def load_ply(file):
|
|
20
|
+
import meshio
|
|
23
21
|
mesh = meshio.read(file)
|
|
24
22
|
xyz = mesh.points
|
|
25
23
|
rgb = np.zeros([xyz.shape[0]], dtype=np.uint32)
|
|
@@ -35,6 +33,7 @@ def load_ply(file):
|
|
|
35
33
|
|
|
36
34
|
|
|
37
35
|
def save_pcd(cloud, save_path):
|
|
36
|
+
from pypcd4 import PointCloud, MetaData
|
|
38
37
|
fields = ('x', 'y', 'z', 'intensity', 'rgb')
|
|
39
38
|
metadata = MetaData.model_validate(
|
|
40
39
|
{
|
|
@@ -82,12 +81,17 @@ def save_pcd(cloud, save_path):
|
|
|
82
81
|
|
|
83
82
|
|
|
84
83
|
def load_pcd(file):
|
|
84
|
+
from pypcd4 import PointCloud
|
|
85
85
|
dtype = [('xyz', '<f4', (3,)), ('irgb', '<u4')]
|
|
86
86
|
pc = PointCloud.from_path(file).pc_data
|
|
87
87
|
rgb = np.zeros([pc.shape[0]], dtype=np.uint32)
|
|
88
88
|
intensity = np.zeros([pc.shape[0]], dtype=np.uint32)
|
|
89
89
|
if 'intensity' in pc.dtype.names:
|
|
90
90
|
intensity = pc['intensity'].astype(np.uint32)
|
|
91
|
+
max_initensity = np.max(intensity)
|
|
92
|
+
# normalize the intensity to 0-255
|
|
93
|
+
if max_initensity > 255:
|
|
94
|
+
intensity = (intensity / max_initensity * 255).astype(np.uint32)
|
|
91
95
|
if 'rgb' in pc.dtype.names:
|
|
92
96
|
rgb = pc['rgb'].astype(np.uint32)
|
|
93
97
|
irgb = (intensity << 24) | rgb
|
|
@@ -97,6 +101,7 @@ def load_pcd(file):
|
|
|
97
101
|
|
|
98
102
|
|
|
99
103
|
def save_e57(cloud, save_path):
|
|
104
|
+
from pye57 import E57
|
|
100
105
|
e57 = E57(save_path, mode='w')
|
|
101
106
|
x = cloud['xyz'][:, 0]
|
|
102
107
|
y = cloud['xyz'][:, 1]
|
|
@@ -113,6 +118,7 @@ def save_e57(cloud, save_path):
|
|
|
113
118
|
|
|
114
119
|
|
|
115
120
|
def load_e57(file_path):
|
|
121
|
+
from pye57 import E57
|
|
116
122
|
e57 = E57(file_path, mode="r")
|
|
117
123
|
scans = e57.read_scan(0, ignore_missing_fields=True,
|
|
118
124
|
intensity=True, colors=True)
|
|
@@ -138,6 +144,7 @@ def load_e57(file_path):
|
|
|
138
144
|
|
|
139
145
|
|
|
140
146
|
def load_las(file):
|
|
147
|
+
import laspy
|
|
141
148
|
with laspy.open(file) as f:
|
|
142
149
|
las = f.read()
|
|
143
150
|
xyz = np.vstack((las.x, las.y, las.z)).transpose()
|
|
@@ -147,21 +154,24 @@ def load_las(file):
|
|
|
147
154
|
if 'intensity' in dimensions:
|
|
148
155
|
intensity = las.intensity.astype(np.uint32)
|
|
149
156
|
if 'red' in dimensions and 'green' in dimensions and 'blue' in dimensions:
|
|
150
|
-
red = las.red
|
|
151
|
-
green = las.green
|
|
152
|
-
blue = las.blue
|
|
153
|
-
|
|
154
|
-
if red.dtype == np.dtype('uint16') and max_val > 255:
|
|
157
|
+
red = las.red.astype(np.uint32)
|
|
158
|
+
green = las.green.astype(np.uint32)
|
|
159
|
+
blue = las.blue.astype(np.uint32)
|
|
160
|
+
if np.max([red, green, blue]) > 255:
|
|
155
161
|
red = (red / 255).astype(np.uint32)
|
|
156
162
|
green = (green / 255).astype(np.uint32)
|
|
157
163
|
blue = (blue / 255).astype(np.uint32)
|
|
158
164
|
rgb = (red << 16) | (green << 8) | blue
|
|
159
|
-
|
|
165
|
+
if np.max(intensity) > 255:
|
|
166
|
+
intensity = (intensity / 255).astype(np.uint32)
|
|
167
|
+
intensity = np.clip(intensity, 0, 255)
|
|
168
|
+
color = (intensity << 24) | rgb
|
|
160
169
|
dtype = [('xyz', '<f4', (3,)), ('irgb', '<u4')]
|
|
161
170
|
cloud = np.rec.fromarrays([xyz, color], dtype=dtype)
|
|
162
171
|
return cloud
|
|
163
172
|
|
|
164
173
|
def save_las(cloud, save_path):
|
|
174
|
+
import laspy
|
|
165
175
|
header = laspy.LasHeader(point_format=3, version="1.2")
|
|
166
176
|
las = laspy.LasData(header)
|
|
167
177
|
las.x = cloud['xyz'][:, 0]
|
|
@@ -229,6 +239,7 @@ def matrix_to_quaternion_wxyz(matrices):
|
|
|
229
239
|
|
|
230
240
|
|
|
231
241
|
def load_gs_ply(path, T=None):
|
|
242
|
+
import meshio
|
|
232
243
|
mesh = meshio.read(path)
|
|
233
244
|
vertices = mesh.points
|
|
234
245
|
pws = vertices[:, :3]
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright 2024 Panasonic Advanced Technology Development Co.,Ltd. (Liu Yang)
|
|
3
|
+
Distributed under MIT license. See LICENSE for more information.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from OpenGL.GL import *
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def rainbow(scalars, scalar_min=0, scalar_max=255):
|
|
11
|
+
range = scalar_max - scalar_min
|
|
12
|
+
values = 1.0 - (scalars - scalar_min) / range
|
|
13
|
+
# values = (scalars - scalar_min) / range # using inverted color
|
|
14
|
+
colors = np.zeros([scalars.shape[0], 3], dtype=np.float32)
|
|
15
|
+
values = np.clip(values, 0, 1)
|
|
16
|
+
|
|
17
|
+
h = values * 5.0 + 1.0
|
|
18
|
+
i = np.floor(h).astype(int)
|
|
19
|
+
f = h - i
|
|
20
|
+
f[np.logical_not(i % 2)] = 1 - f[np.logical_not(i % 2)]
|
|
21
|
+
n = 1 - f
|
|
22
|
+
|
|
23
|
+
# idx = i <= 1
|
|
24
|
+
colors[i <= 1, 0] = n[i <= 1] * 255
|
|
25
|
+
colors[i <= 1, 1] = 0
|
|
26
|
+
colors[i <= 1, 2] = 255
|
|
27
|
+
|
|
28
|
+
colors[i == 2, 0] = 0
|
|
29
|
+
colors[i == 2, 1] = n[i == 2] * 255
|
|
30
|
+
colors[i == 2, 2] = 255
|
|
31
|
+
|
|
32
|
+
colors[i == 3, 0] = 0
|
|
33
|
+
colors[i == 3, 1] = 255
|
|
34
|
+
colors[i == 3, 2] = n[i == 3] * 255
|
|
35
|
+
|
|
36
|
+
colors[i == 4, 0] = n[i == 4] * 255
|
|
37
|
+
colors[i == 4, 1] = 255
|
|
38
|
+
colors[i == 4, 2] = 0
|
|
39
|
+
|
|
40
|
+
colors[i >= 5, 0] = 255
|
|
41
|
+
colors[i >= 5, 1] = n[i >= 5] * 255
|
|
42
|
+
colors[i >= 5, 2] = 0
|
|
43
|
+
return colors
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def text_to_rgba(color_text, flat=False):
|
|
47
|
+
"""
|
|
48
|
+
Convert a color text to an RGBA tuple.
|
|
49
|
+
|
|
50
|
+
:param color_text: e.g. '#FF0000', '#FF0000FF', 'red', 'green', 'blue', 'yellow',
|
|
51
|
+
'black', 'white', 'magenta', 'cyan', 'r', 'g', 'b', 'y', 'k', 'w', 'm', 'c'
|
|
52
|
+
:return: RGBA tuple, e.g. (1.0, 0.0, 0.0, 1.0)
|
|
53
|
+
"""
|
|
54
|
+
from matplotlib.colors import to_rgba
|
|
55
|
+
|
|
56
|
+
rgba = to_rgba(color_text)
|
|
57
|
+
if flat:
|
|
58
|
+
r, g, b, _ = (np.array(rgba)*255).astype(np.uint32)
|
|
59
|
+
falt_rgb = ((r << 16) & 0xFF0000) | \
|
|
60
|
+
((g << 8) & 0x00FF00) | \
|
|
61
|
+
((b << 0) & 0x0000FF)
|
|
62
|
+
return falt_rgb
|
|
63
|
+
else:
|
|
64
|
+
return rgba
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def set_uniform(shader, content, name):
|
|
68
|
+
location = glGetUniformLocation(shader, name)
|
|
69
|
+
if location == -1:
|
|
70
|
+
raise ValueError(
|
|
71
|
+
f"Uniform '{name}' not found in shader program {shader}.")
|
|
72
|
+
|
|
73
|
+
if isinstance(content, int):
|
|
74
|
+
glUniform1i(location, content)
|
|
75
|
+
elif isinstance(content, float):
|
|
76
|
+
glUniform1f(location, content)
|
|
77
|
+
elif isinstance(content, np.ndarray):
|
|
78
|
+
if content.ndim == 1:
|
|
79
|
+
if content.shape[0] == 2:
|
|
80
|
+
glUniform2f(location, *content)
|
|
81
|
+
elif content.shape[0] == 3:
|
|
82
|
+
glUniform3f(location, *content)
|
|
83
|
+
else:
|
|
84
|
+
raise ValueError(
|
|
85
|
+
f"Unsupported 1D array size: {content.shape}.")
|
|
86
|
+
elif content.ndim == 2:
|
|
87
|
+
if content.shape == (4, 4):
|
|
88
|
+
glUniformMatrix4fv(location, 1, GL_FALSE,
|
|
89
|
+
content.T.astype(np.float32))
|
|
90
|
+
else:
|
|
91
|
+
raise ValueError(
|
|
92
|
+
f"Unsupported 2D array size: {content.shape}.")
|
|
93
|
+
else:
|
|
94
|
+
raise ValueError(f"Unsupported array dimension: {content.ndim}.")
|
|
95
|
+
else:
|
|
96
|
+
raise TypeError(
|
|
97
|
+
f"Unsupported type for uniform '{name}': {type(content)}.")
|
q3dviewer/utils/maths.py
CHANGED
|
@@ -10,7 +10,6 @@ https://github.com/scomup/MathematicalRobotics.git
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
import numpy as np
|
|
13
|
-
from matplotlib.colors import to_rgba
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
_epsilon_ = 1e-5
|
|
@@ -159,42 +158,6 @@ def frustum(left, right, bottom, top, near, far):
|
|
|
159
158
|
return matrix
|
|
160
159
|
|
|
161
160
|
|
|
162
|
-
def rainbow(scalars, scalar_min=0, scalar_max=255):
|
|
163
|
-
range = scalar_max - scalar_min
|
|
164
|
-
values = 1.0 - (scalars - scalar_min) / range
|
|
165
|
-
# values = (scalars - scalar_min) / range # using inverted color
|
|
166
|
-
colors = np.zeros([scalars.shape[0], 3], dtype=np.float32)
|
|
167
|
-
values = np.clip(values, 0, 1)
|
|
168
|
-
|
|
169
|
-
h = values * 5.0 + 1.0
|
|
170
|
-
i = np.floor(h).astype(int)
|
|
171
|
-
f = h - i
|
|
172
|
-
f[np.logical_not(i % 2)] = 1 - f[np.logical_not(i % 2)]
|
|
173
|
-
n = 1 - f
|
|
174
|
-
|
|
175
|
-
# idx = i <= 1
|
|
176
|
-
colors[i <= 1, 0] = n[i <= 1] * 255
|
|
177
|
-
colors[i <= 1, 1] = 0
|
|
178
|
-
colors[i <= 1, 2] = 255
|
|
179
|
-
|
|
180
|
-
colors[i == 2, 0] = 0
|
|
181
|
-
colors[i == 2, 1] = n[i == 2] * 255
|
|
182
|
-
colors[i == 2, 2] = 255
|
|
183
|
-
|
|
184
|
-
colors[i == 3, 0] = 0
|
|
185
|
-
colors[i == 3, 1] = 255
|
|
186
|
-
colors[i == 3, 2] = n[i == 3] * 255
|
|
187
|
-
|
|
188
|
-
colors[i == 4, 0] = n[i == 4] * 255
|
|
189
|
-
colors[i == 4, 1] = 255
|
|
190
|
-
colors[i == 4, 2] = 0
|
|
191
|
-
|
|
192
|
-
colors[i >= 5, 0] = 255
|
|
193
|
-
colors[i >= 5, 1] = n[i >= 5] * 255
|
|
194
|
-
colors[i >= 5, 2] = 0
|
|
195
|
-
return colors
|
|
196
|
-
|
|
197
|
-
|
|
198
161
|
def euler_to_matrix(rpy):
|
|
199
162
|
roll, pitch, yaw = rpy
|
|
200
163
|
Rx = np.array([[1, 0, 0],
|
|
@@ -294,27 +257,6 @@ def makeRt(T):
|
|
|
294
257
|
return R, t
|
|
295
258
|
|
|
296
259
|
|
|
297
|
-
def text_to_rgba(color_text, flat=False):
|
|
298
|
-
"""
|
|
299
|
-
Convert a color text to an RGBA tuple.
|
|
300
|
-
|
|
301
|
-
:param color_text: e.g. '#FF0000', '#FF0000FF', 'red', 'green', 'blue', 'yellow',
|
|
302
|
-
'black', 'white', 'magenta', 'cyan', 'r', 'g', 'b', 'y', 'k', 'w', 'm', 'c'
|
|
303
|
-
:return: RGBA tuple, e.g. (1.0, 0.0, 0.0, 1.0)
|
|
304
|
-
"""
|
|
305
|
-
rgba = to_rgba(color_text)
|
|
306
|
-
if flat:
|
|
307
|
-
r, g, b, _ = (np.array(rgba)*255).astype(np.uint32)
|
|
308
|
-
falt_rgb = ((r << 16) & 0xFF0000) | \
|
|
309
|
-
((g << 8) & 0x00FF00) | \
|
|
310
|
-
((b << 0) & 0x0000FF)
|
|
311
|
-
return falt_rgb
|
|
312
|
-
else:
|
|
313
|
-
return rgba
|
|
314
|
-
# except ValueError as e:
|
|
315
|
-
# raise ValueError(f"Invalid color text '{color_text}': {e}")
|
|
316
|
-
|
|
317
|
-
|
|
318
260
|
# euler = np.array([1, 0.1, 0.1])
|
|
319
261
|
# euler_angles = matrix_to_euler(euler_to_matrix(euler))
|
|
320
262
|
# print("Euler Angles:", euler_angles)
|
q3dviewer/utils/range_slider.py
CHANGED
|
@@ -3,9 +3,9 @@ Copyright 2024 Panasonic Advanced Technology Development Co.,Ltd. (Liu Yang)
|
|
|
3
3
|
Distributed under MIT license. See LICENSE for more information.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from
|
|
7
|
-
from
|
|
8
|
-
from
|
|
6
|
+
from q3dviewer.Qt.QtCore import Qt, Signal
|
|
7
|
+
from q3dviewer.Qt.QtGui import QPainter, QColor
|
|
8
|
+
from q3dviewer.Qt.QtWidgets import QSlider, QToolTip
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class RangeSlider(QSlider):
|
|
@@ -20,6 +20,10 @@ class RangeSlider(QSlider):
|
|
|
20
20
|
self.lower_value = vmin
|
|
21
21
|
self.upper_value = vmax
|
|
22
22
|
self.active_handle = None
|
|
23
|
+
self.bar_color = QColor(200, 200, 200) # Gray bar
|
|
24
|
+
self.highlight_color = QColor(100, 100, 255) # Blue for selected range
|
|
25
|
+
self.handle_color = QColor(50, 50, 255) # Blue handles
|
|
26
|
+
|
|
23
27
|
self.setTickPosition(QSlider.NoTicks) # Hide original ticks
|
|
24
28
|
# Hide slider handle
|
|
25
29
|
self.setStyleSheet("QSlider::handle { background: transparent; }")
|
|
@@ -41,35 +45,50 @@ class RangeSlider(QSlider):
|
|
|
41
45
|
if self.active_handle == "lower":
|
|
42
46
|
self.lower_value = max(
|
|
43
47
|
self.minimum(), min(pos, self.upper_value - 1))
|
|
48
|
+
QToolTip.showText(event.globalPos(), f"Lower: {self.lower_value:.1f}")
|
|
44
49
|
elif self.active_handle == "upper":
|
|
45
50
|
self.upper_value = min(
|
|
46
51
|
self.maximum(), max(pos, self.lower_value + 1))
|
|
52
|
+
QToolTip.showText(event.globalPos(), f"Upper: {self.upper_value:.1f}")
|
|
47
53
|
self.rangeChanged.emit(self.lower_value, self.upper_value)
|
|
48
54
|
self.update()
|
|
49
55
|
|
|
56
|
+
def mouseReleaseEvent(self, event):
|
|
57
|
+
"""Override to hide tooltip when mouse stops."""
|
|
58
|
+
QToolTip.hideText()
|
|
59
|
+
super().mouseReleaseEvent(event)
|
|
60
|
+
|
|
61
|
+
def enterEvent(self, event):
|
|
62
|
+
"""Show tooltips for lower and upper values when mouse enters."""
|
|
63
|
+
QToolTip.showText(self.mapToGlobal(self.rect().topLeft()),
|
|
64
|
+
f"Lower: {self.lower_value:.1f}, Upper: {self.upper_value:.1f}")
|
|
65
|
+
super().enterEvent(event)
|
|
66
|
+
|
|
67
|
+
def leaveEvent(self, event):
|
|
68
|
+
"""Hide tooltips when mouse leaves."""
|
|
69
|
+
QToolTip.hideText()
|
|
70
|
+
super().leaveEvent(event)
|
|
71
|
+
|
|
50
72
|
def paintEvent(self, event):
|
|
51
73
|
"""Override to paint custom range handles."""
|
|
52
74
|
painter = QPainter(self)
|
|
53
75
|
|
|
54
76
|
# Draw the range bar
|
|
55
|
-
bar_color = QColor(200, 200, 200) # Gray bar
|
|
56
|
-
highlight_color = QColor(100, 100, 255) # Blue for selected range
|
|
57
77
|
painter.setPen(Qt.NoPen)
|
|
58
78
|
|
|
59
79
|
bar_height = 6
|
|
60
80
|
bar_y = self.height() // 2 - bar_height // 2
|
|
61
|
-
painter.setBrush(bar_color)
|
|
81
|
+
painter.setBrush(self.bar_color)
|
|
62
82
|
painter.drawRect(0, bar_y, self.width(), bar_height)
|
|
63
83
|
|
|
64
84
|
# Draw the selected range
|
|
65
85
|
lower_x = int(self.valueToPixelPos(self.lower_value))
|
|
66
86
|
upper_x = int(self.valueToPixelPos(self.upper_value))
|
|
67
|
-
painter.setBrush(highlight_color)
|
|
87
|
+
painter.setBrush(self.highlight_color)
|
|
68
88
|
painter.drawRect(lower_x, bar_y, upper_x - lower_x, bar_height)
|
|
69
89
|
|
|
70
90
|
# Draw the range handles
|
|
71
|
-
handle_color
|
|
72
|
-
painter.setBrush(handle_color)
|
|
91
|
+
painter.setBrush(self.handle_color)
|
|
73
92
|
painter.drawEllipse(lower_x - 5, bar_y - 4, 12, 12)
|
|
74
93
|
painter.drawEllipse(upper_x - 5, bar_y - 4, 12, 12)
|
|
75
94
|
|
q3dviewer/viewer.py
CHANGED
|
@@ -6,7 +6,7 @@ Distributed under MIT license. See LICENSE for more information.
|
|
|
6
6
|
|
|
7
7
|
from q3dviewer.glwidget import *
|
|
8
8
|
import signal
|
|
9
|
-
from
|
|
9
|
+
from q3dviewer.Qt.QtWidgets import QMainWindow, QApplication, QHBoxLayout
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def handler(signal, frame):
|
|
@@ -17,7 +17,7 @@ def handler(signal, frame):
|
|
|
17
17
|
class Viewer(QMainWindow):
|
|
18
18
|
def __init__(self, name='Viewer', win_size=[1920, 1080],
|
|
19
19
|
gl_widget_class=GLWidget, update_interval=20):
|
|
20
|
-
|
|
20
|
+
self.set_quit_handler(handler)
|
|
21
21
|
super(Viewer, self).__init__()
|
|
22
22
|
self.setGeometry(0, 0, win_size[0], win_size[1])
|
|
23
23
|
self.gl_widget_class = gl_widget_class
|
|
@@ -27,6 +27,9 @@ class Viewer(QMainWindow):
|
|
|
27
27
|
self.setWindowTitle(name)
|
|
28
28
|
self.installEventFilter(self)
|
|
29
29
|
|
|
30
|
+
def set_quit_handler(self, handler):
|
|
31
|
+
signal.signal(signal.SIGINT, handler)
|
|
32
|
+
|
|
30
33
|
def init_ui(self):
|
|
31
34
|
center_widget = QWidget()
|
|
32
35
|
self.setCentralWidget(center_widget)
|
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: q3dviewer
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.7
|
|
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
|
|
7
|
-
License: UNKNOWN
|
|
8
|
-
Platform: UNKNOWN
|
|
9
7
|
Classifier: Programming Language :: Python :: 3
|
|
10
8
|
Classifier: License :: OSI Approved :: MIT License
|
|
11
9
|
Classifier: Operating System :: OS Independent
|
|
12
10
|
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: numpy
|
|
13
|
+
Requires-Dist: pyside6
|
|
13
14
|
Requires-Dist: PyOpenGL
|
|
15
|
+
Requires-Dist: meshio
|
|
16
|
+
Requires-Dist: pypcd4
|
|
17
|
+
Requires-Dist: pye57
|
|
18
|
+
Requires-Dist: laspy
|
|
14
19
|
Requires-Dist: imageio
|
|
15
20
|
Requires-Dist: imageio[ffmpeg]
|
|
16
|
-
Requires-Dist: laspy
|
|
17
21
|
Requires-Dist: matplotlib
|
|
18
|
-
Requires-Dist: meshio
|
|
19
|
-
Requires-Dist: numpy
|
|
20
|
-
Requires-Dist: pye57
|
|
21
|
-
Requires-Dist: pypcd4
|
|
22
|
-
Requires-Dist: pyside6
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|

|
|
@@ -27,7 +26,7 @@ Requires-Dist: pyside6
|
|
|
27
26
|
[](https://opensource.org/licenses/MIT)
|
|
28
27
|
[](https://badge.fury.io/py/q3dviewer)
|
|
29
28
|
|
|
30
|
-
`q3dviewer` is a library designed for quickly deploying a 3D viewer. It is based on Qt
|
|
29
|
+
`q3dviewer` is a library designed for quickly deploying a 3D viewer. It is based on Qt and provides efficient OpenGL items for displaying 3D objects (e.g., point clouds, cameras, and 3D Gaussians). You can use it to visualize your 3D data or set up an efficient viewer application. It is inspired by PyQtGraph but focuses more on efficient 3D rendering.
|
|
31
30
|
|
|
32
31
|
|
|
33
32
|
To show how to use `q3dviewer` as a library, we also provide some [very useful tools](#tools).
|
|
@@ -172,7 +171,7 @@ def main():
|
|
|
172
171
|
|
|
173
172
|
# Create a viewer
|
|
174
173
|
viewer = q3d.Viewer(name='example')
|
|
175
|
-
|
|
174
|
+
|
|
176
175
|
# Add items to the viewer
|
|
177
176
|
viewer.add_items({
|
|
178
177
|
'grid': grid_item,
|
|
@@ -206,7 +205,7 @@ In addition to the standard 3D items provided, you can visualize custom 3D items
|
|
|
206
205
|
from OpenGL.GL import *
|
|
207
206
|
import numpy as np
|
|
208
207
|
import q3dviewer as q3d
|
|
209
|
-
from
|
|
208
|
+
from q3dviewer.Qt.QtWidgets import QLabel, QSpinBox
|
|
210
209
|
|
|
211
210
|
class YourItem(q3d.BaseItem):
|
|
212
211
|
def __init__(self):
|
|
@@ -234,4 +233,3 @@ class YourItem(q3d.BaseItem):
|
|
|
234
233
|
```
|
|
235
234
|
|
|
236
235
|
Enjoy using `q3dviewer`!
|
|
237
|
-
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
q3dviewer/__init__.py,sha256=cjyfUE5zK6xohDGDQIWfb0DKkWChVznBd7CrVLg7whQ,376
|
|
2
|
+
q3dviewer/base_glwidget.py,sha256=6Z5rINQ1Y9KqtpBexr0hMX66pNTh6qvovlb7fJe5ZGM,12303
|
|
3
|
+
q3dviewer/base_item.py,sha256=63MarHyoWszPL40ox-vPoOAQ1N4ypekOjoRARdPik-E,1755
|
|
4
|
+
q3dviewer/basic_window.py,sha256=CFErOPRMysFcCqq3vhDsQ-xZzLArO3m1yABCTIhq5do,7946
|
|
5
|
+
q3dviewer/cloud_viewer.py,sha256=IxxrB6Sl6aPCr9P9QzKHGkMcDP_DjsBWbkmIbsAoIM4,2358
|
|
6
|
+
q3dviewer/gau_io.py,sha256=S6NmqL5vSMgHVxKR-eu4CWCqgZeWBJKYRoOMAwr8Xbo,5890
|
|
7
|
+
q3dviewer/glwidget.py,sha256=pkMQxPXNxVWp_sZUFX2r4IHuw_So9ok5e-ZdvBhArFQ,4631
|
|
8
|
+
q3dviewer/utils.py,sha256=evF0d-v17hbTmquC24fmMIp9CsXpUnSQZr4MVy2sfao,2426
|
|
9
|
+
q3dviewer/viewer.py,sha256=Vq3ucDlBcBBoiVVGmqG1sRjhLePl50heblx6wJpsc1A,2603
|
|
10
|
+
q3dviewer/Qt/__init__.py,sha256=CcwS6oSXBXTMr58JNbRNYcPMVubDD2jiPtJ55DoLm8o,2199
|
|
11
|
+
q3dviewer/custom_items/__init__.py,sha256=19z_BFXJEm8j31WqREICN31fiFcaIeUqvfo39d02vbk,509
|
|
12
|
+
q3dviewer/custom_items/axis_item.py,sha256=-WM2urosqV847zpTpOtxdLjb7y9NJqFCH13qqodcCTg,2572
|
|
13
|
+
q3dviewer/custom_items/camera_frame_item.py,sha256=VBsr3Avly_YWXViIh4DJkGc_HJt227GeOYLpGtbYTOw,5605
|
|
14
|
+
q3dviewer/custom_items/cloud_io_item.py,sha256=E3Qyc4nuVP-MQAff4zII9JB-xQjVRsviATpqvpLQveM,3507
|
|
15
|
+
q3dviewer/custom_items/cloud_item.py,sha256=ITOzVq4MAKFIQOGkIgY0Xc2a-yumwHWg3wIvZgjuyGc,13125
|
|
16
|
+
q3dviewer/custom_items/frame_item.py,sha256=bUzww3tSDah0JZeqtU6_cYHhhTVWzXhJVMcAa5pCXHI,7458
|
|
17
|
+
q3dviewer/custom_items/gaussian_item.py,sha256=JMubpahkTPh0E8ShL3FLTahv0e35ODzjgK5K1i0YXSU,9884
|
|
18
|
+
q3dviewer/custom_items/grid_item.py,sha256=LDB_MYACoxld-xvz01_MfAf12vLcRkH7R_WtGHHdSgk,4945
|
|
19
|
+
q3dviewer/custom_items/image_item.py,sha256=k7HNTqdL2ckTbxMx7A7eKaP4aksZ85-pBjNdbpm6PXM,5355
|
|
20
|
+
q3dviewer/custom_items/line_item.py,sha256=rel-lx8AgjDY7qyIecHxHQZzaswRn2ZTiOIjB_0Mrqo,4444
|
|
21
|
+
q3dviewer/custom_items/text_item.py,sha256=VdmoCgXAfqN58fMKydqrdnJHCT53VelRiv_88X9aCfQ,2185
|
|
22
|
+
q3dviewer/custom_items/trajectory_item.py,sha256=uoKQSrTs_m_m1M8iNAm3peiXnZ9uVPsYQLYas3Gksjg,2754
|
|
23
|
+
q3dviewer/shaders/cloud_frag.glsl,sha256=tbCsDUp9YlPe0hRWlFS724SH6TtMeLO-GVYROzEElZg,609
|
|
24
|
+
q3dviewer/shaders/cloud_vert.glsl,sha256=7VrNDbEVqzatpQOuIfFOLYgtbFVWG0Rxl2Od7DZ-l8U,2357
|
|
25
|
+
q3dviewer/shaders/gau_frag.glsl,sha256=5_UY84tWDts59bxP8x4I-wgnzY8aGeGuo28wX--LW7E,975
|
|
26
|
+
q3dviewer/shaders/gau_prep.glsl,sha256=eCT9nm65uz32w8NaDjeGKhyAZh42Aea-QTwr3yQVr9U,7218
|
|
27
|
+
q3dviewer/shaders/gau_vert.glsl,sha256=NNbVhv_JyqZDK9iXAyBAcIHAtim7G9yWbC9IaUfTL1w,1666
|
|
28
|
+
q3dviewer/shaders/sort_by_key.glsl,sha256=CA2zOcbyDGYAJSJEUvgjUqNshg9NAehf8ipL3Jsv4qE,1097
|
|
29
|
+
q3dviewer/tools/__init__.py,sha256=01wG7BGM6VX0QyFBKsqPmyf2e-vrmV_N3-mo-VQ1VBg,20
|
|
30
|
+
q3dviewer/tools/cloud_viewer.py,sha256=-yKVWQb-UWpP7h3khR3dipT_X8XLLL6JllGZJ1vaOM4,3877
|
|
31
|
+
q3dviewer/tools/example_viewer.py,sha256=sedL18GU3bTTjVJBREPVJ5hTLfSDFq_j91E4qXnG8TU,964
|
|
32
|
+
q3dviewer/tools/film_maker.py,sha256=CXsI2SocgnQProIWKJ6lvRXtFv4DoO-rm6YNfweAJmw,16678
|
|
33
|
+
q3dviewer/tools/gaussian_viewer.py,sha256=vIwWmiFhjNmknrEkBLzt2yiegeH7LP3OeNjnGM6GzaI,1633
|
|
34
|
+
q3dviewer/tools/lidar_calib.py,sha256=hHnsSaQh_Pkdh8tPntt0MgEW26nQyAdC_HQHq4I3sw8,10562
|
|
35
|
+
q3dviewer/tools/lidar_cam_calib.py,sha256=AyF3RipBo1R5LYJqm5RR8LUbEovRWJiBUEmUtnrx6e8,11318
|
|
36
|
+
q3dviewer/tools/ros_viewer.py,sha256=ARB3I5wohY3maP8dCu0O0hxObd6JFKuK2y7AApVgMWA,2551
|
|
37
|
+
q3dviewer/utils/__init__.py,sha256=dwTNAAebTiKY4ygv2G1O-w6-TbJnmnNVO2UfJXvJhaQ,107
|
|
38
|
+
q3dviewer/utils/cloud_io.py,sha256=xarfYakY0zgKwvZkgKSPO6b4DEo42hsq3mcvCbK64yg,12134
|
|
39
|
+
q3dviewer/utils/convert_ros_msg.py,sha256=sAoQfy3qLQKsIArBAVm8H--wlQXOcmkKK3-Ox9UCcrc,1686
|
|
40
|
+
q3dviewer/utils/gl_helper.py,sha256=dRY_kUqyPMr7NTcupUr6_VTvgnj53iE2C0Lk0-oFYsI,1435
|
|
41
|
+
q3dviewer/utils/helpers.py,sha256=SqR4YTQZi13FKbkVUYgodXce1JJ_YmrHEIRkUmnIUas,3085
|
|
42
|
+
q3dviewer/utils/maths.py,sha256=zHaPtvVZIuo8xepIXCMeSL9tpx8FahUrq0l4K1oXrBk,8834
|
|
43
|
+
q3dviewer/utils/range_slider.py,sha256=9djTxuzmzH54DgSwAljRpLGjsrIJ0hTxhaxFjPxsk8g,4007
|
|
44
|
+
q3dviewer-1.1.7.dist-info/LICENSE,sha256=81cMOyNfw8KLb1JnPYngGHJ5W83gSbZEBU9MEP3tl-E,1124
|
|
45
|
+
q3dviewer-1.1.7.dist-info/METADATA,sha256=ckr5ZX5GWsS3T7JmlUjlPzgwxRizYkjdV_vCAsBZYHo,7969
|
|
46
|
+
q3dviewer-1.1.7.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
47
|
+
q3dviewer-1.1.7.dist-info/entry_points.txt,sha256=aeUdGH7UIgMZEMFUc-0xPZWspY95GoPdZcZuLceq85g,361
|
|
48
|
+
q3dviewer-1.1.7.dist-info/top_level.txt,sha256=HFFDCbGu28txcGe2HPc46A7EPaguBa_b5oH7bufmxHM,10
|
|
49
|
+
q3dviewer-1.1.7.dist-info/RECORD,,
|
q3dviewer-1.1.5.dist-info/RECORD
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
q3dviewer/__init__.py,sha256=rP5XX_x8g7hxIMqNHlU89BN4dt5MSvoYYwip68fCmhc,173
|
|
2
|
-
q3dviewer/base_glwidget.py,sha256=yQb4ckj4ldmiFoKL_TdZAqZNeBnMeSRDhLbMaruM3nk,12298
|
|
3
|
-
q3dviewer/base_item.py,sha256=lzb04oRaS4rRJrAP6C1Bu4ugK237FgupMTB97zjNVFw,1768
|
|
4
|
-
q3dviewer/basic_window.py,sha256=CFErOPRMysFcCqq3vhDsQ-xZzLArO3m1yABCTIhq5do,7946
|
|
5
|
-
q3dviewer/cloud_viewer.py,sha256=IxxrB6Sl6aPCr9P9QzKHGkMcDP_DjsBWbkmIbsAoIM4,2358
|
|
6
|
-
q3dviewer/gau_io.py,sha256=S6NmqL5vSMgHVxKR-eu4CWCqgZeWBJKYRoOMAwr8Xbo,5890
|
|
7
|
-
q3dviewer/glwidget.py,sha256=2scii9IeY3ion12lFgWtGXO9JrlUD3tfp3zXt7gnFoQ,4689
|
|
8
|
-
q3dviewer/utils.py,sha256=evF0d-v17hbTmquC24fmMIp9CsXpUnSQZr4MVy2sfao,2426
|
|
9
|
-
q3dviewer/viewer.py,sha256=LH1INLFhi6pRjzazzQJ0AWT4hgyXI6GnmqoJFUwUZVE,2517
|
|
10
|
-
q3dviewer/custom_items/__init__.py,sha256=gOiAxdjDaAnFL8YbqSEWWWOwUrJfvzP9JLR34sCB9-4,434
|
|
11
|
-
q3dviewer/custom_items/axis_item.py,sha256=PTBSf5DmQI8ieSinYjY_aC7P8q1nzE-2Vc2GNd1O3Os,2568
|
|
12
|
-
q3dviewer/custom_items/camera_frame_item.py,sha256=VBsr3Avly_YWXViIh4DJkGc_HJt227GeOYLpGtbYTOw,5605
|
|
13
|
-
q3dviewer/custom_items/cloud_io_item.py,sha256=l7FGKb1s3kEFw1GT8Bro5oJfu4reuvunHJkM1pmpxz4,3038
|
|
14
|
-
q3dviewer/custom_items/cloud_item.py,sha256=JtjehxPYuzypVg_8ENfZvN7yEVO-Ac7GE8Dt3jzP6yk,12763
|
|
15
|
-
q3dviewer/custom_items/frame_item.py,sha256=9g4SxIGZCWFWaX5Xfd9G-P63VlonysxEC239lk7dRRg,7408
|
|
16
|
-
q3dviewer/custom_items/gaussian_item.py,sha256=CZoXMmj2JPFfMqu7v4q4dLUI2cg_WfE1DHWGXjEYn6M,9869
|
|
17
|
-
q3dviewer/custom_items/grid_item.py,sha256=58QUKli_9NEtYchulZt5Xhqk6k2DaL5RlEMaYyt7MSE,4965
|
|
18
|
-
q3dviewer/custom_items/image_item.py,sha256=3FYAVlNLEILKZplkt2wbL8y16ke124GmwxcSmWmJY8Q,5357
|
|
19
|
-
q3dviewer/custom_items/line_item.py,sha256=np8sORS5kZFWptOUa_Vlq1p7b9rMK3CpGsBd77Qpo2M,4445
|
|
20
|
-
q3dviewer/custom_items/text_item.py,sha256=G3PPpN_0yjUMWJKvNG5QFgqxmE6LUEW5VIUDdi3kwuk,2314
|
|
21
|
-
q3dviewer/custom_items/trajectory_item.py,sha256=uoKQSrTs_m_m1M8iNAm3peiXnZ9uVPsYQLYas3Gksjg,2754
|
|
22
|
-
q3dviewer/shaders/cloud_frag.glsl,sha256=tbCsDUp9YlPe0hRWlFS724SH6TtMeLO-GVYROzEElZg,609
|
|
23
|
-
q3dviewer/shaders/cloud_vert.glsl,sha256=Vxgw-Zrr0knAK0z4qMXKML6IC4EbffKMwYN2TMXROoI,2117
|
|
24
|
-
q3dviewer/shaders/gau_frag.glsl,sha256=5_UY84tWDts59bxP8x4I-wgnzY8aGeGuo28wX--LW7E,975
|
|
25
|
-
q3dviewer/shaders/gau_prep.glsl,sha256=eCT9nm65uz32w8NaDjeGKhyAZh42Aea-QTwr3yQVr9U,7218
|
|
26
|
-
q3dviewer/shaders/gau_vert.glsl,sha256=NNbVhv_JyqZDK9iXAyBAcIHAtim7G9yWbC9IaUfTL1w,1666
|
|
27
|
-
q3dviewer/shaders/sort_by_key.glsl,sha256=CA2zOcbyDGYAJSJEUvgjUqNshg9NAehf8ipL3Jsv4qE,1097
|
|
28
|
-
q3dviewer/tools/__init__.py,sha256=01wG7BGM6VX0QyFBKsqPmyf2e-vrmV_N3-mo-VQ1VBg,20
|
|
29
|
-
q3dviewer/tools/cloud_viewer.py,sha256=10f2LSWpmsXzxrGobXw188doVjJbgBfPoqZPUi35EtI,3867
|
|
30
|
-
q3dviewer/tools/example_viewer.py,sha256=yeVXT0k4-h1vTLKnGzWADZD3our6XUaYUTy0p5daTkE,959
|
|
31
|
-
q3dviewer/tools/film_maker.py,sha256=w97LMMmSpjTOMdG2j0ucK2kDoU3k__746jRVh2fJfvc,16598
|
|
32
|
-
q3dviewer/tools/gaussian_viewer.py,sha256=vIwWmiFhjNmknrEkBLzt2yiegeH7LP3OeNjnGM6GzaI,1633
|
|
33
|
-
q3dviewer/tools/lidar_calib.py,sha256=M01bGg2mT8LwVcYybolr4UW_UUaR-f-BFciEHtjeK-w,10488
|
|
34
|
-
q3dviewer/tools/lidar_cam_calib.py,sha256=SYNLDvi15MX7Q3aGn771fvu1cES9xeXgP0_WmDq33w4,11200
|
|
35
|
-
q3dviewer/tools/ros_viewer.py,sha256=ARB3I5wohY3maP8dCu0O0hxObd6JFKuK2y7AApVgMWA,2551
|
|
36
|
-
q3dviewer/utils/__init__.py,sha256=irm8Z_bT8l9kzhoMlds2Dal8g4iw4vjmqNPZSs4W6e0,157
|
|
37
|
-
q3dviewer/utils/cloud_io.py,sha256=xnsT3VEKS435BE1DwhciRHicwzuC-8-JASkImT8pKNk,11681
|
|
38
|
-
q3dviewer/utils/convert_ros_msg.py,sha256=sAoQfy3qLQKsIArBAVm8H--wlQXOcmkKK3-Ox9UCcrc,1686
|
|
39
|
-
q3dviewer/utils/gl_helper.py,sha256=dRY_kUqyPMr7NTcupUr6_VTvgnj53iE2C0Lk0-oFYsI,1435
|
|
40
|
-
q3dviewer/utils/maths.py,sha256=tHx2q_qAFPQQoFJbnwB0Ts-xtEibeGAhJrMHOH6aCPk,10575
|
|
41
|
-
q3dviewer/utils/range_slider.py,sha256=jZJQL-uQgnpgLvtYSWpKTrJlLkt3aqNpaRQAePEpNd0,3174
|
|
42
|
-
q3dviewer-1.1.5.dist-info/LICENSE,sha256=81cMOyNfw8KLb1JnPYngGHJ5W83gSbZEBU9MEP3tl-E,1124
|
|
43
|
-
q3dviewer-1.1.5.dist-info/METADATA,sha256=6DZkBF6Jsghr4qu0K2Wp-gzjP8qoflKCvSk6qi2EoP4,7984
|
|
44
|
-
q3dviewer-1.1.5.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
|
|
45
|
-
q3dviewer-1.1.5.dist-info/entry_points.txt,sha256=EOjker7XYaBk70ffvNB_knPcfA33Bnlg21ZjEeM1EyI,362
|
|
46
|
-
q3dviewer-1.1.5.dist-info/top_level.txt,sha256=HFFDCbGu28txcGe2HPc46A7EPaguBa_b5oH7bufmxHM,10
|
|
47
|
-
q3dviewer-1.1.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|