molde 0.1.0__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.
- molde/__init__.py +5 -0
- molde/__main__.py +63 -0
- molde/actors/__init__.py +4 -0
- molde/actors/ghost_actor.py +12 -0
- molde/actors/lines_actor.py +31 -0
- molde/actors/round_points_actor.py +7 -0
- molde/actors/square_points_actor.py +32 -0
- molde/colors/__init__.py +2 -0
- molde/colors/color.py +120 -0
- molde/colors/color_names.py +125 -0
- molde/fonts/IBMPlexMono-Bold.ttf +0 -0
- molde/fonts/IBMPlexMono-Regular.ttf +0 -0
- molde/icons/arrow_down_dark_theme.svg +1 -0
- molde/icons/arrow_down_disabled_dark_theme.svg +1 -0
- molde/icons/arrow_down_disabled_light_theme.svg +1 -0
- molde/icons/arrow_down_light_theme.svg +1 -0
- molde/icons/arrow_left_dark_theme.svg +1 -0
- molde/icons/arrow_left_light_theme.svg +1 -0
- molde/icons/arrow_right_dark_theme.svg +1 -0
- molde/icons/arrow_right_light_theme.svg +1 -0
- molde/icons/arrow_up_dark_theme.svg +1 -0
- molde/icons/arrow_up_disabled_dark_theme.svg +1 -0
- molde/icons/arrow_up_disabled_light_theme.svg +1 -0
- molde/icons/arrow_up_light_theme.svg +1 -0
- molde/icons/check_box_image.svg +1 -0
- molde/interactor_styles/__init__.py +2 -0
- molde/interactor_styles/arcball_camera_style.py +272 -0
- molde/interactor_styles/box_selection_style.py +70 -0
- molde/pickers/__init__.py +2 -0
- molde/pickers/cell_area_picker.py +61 -0
- molde/pickers/cell_property_area_picker.py +84 -0
- molde/poly_data/__init__.py +2 -0
- molde/poly_data/lines_data.py +23 -0
- molde/poly_data/vertices_data.py +24 -0
- molde/render_widgets/__init__.py +2 -0
- molde/render_widgets/animated_render_widget.py +164 -0
- molde/render_widgets/common_render_widget.py +433 -0
- molde/stylesheets/__init__.py +119 -0
- molde/stylesheets/common.qss +16 -0
- molde/stylesheets/create_color_page.py +61 -0
- molde/stylesheets/mainwindow.ui +611 -0
- molde/stylesheets/qcheckbox.qss +19 -0
- molde/stylesheets/qinputs.qss +79 -0
- molde/stylesheets/qlayouts.qss +22 -0
- molde/stylesheets/qmenubar.qss +12 -0
- molde/stylesheets/qprogressbar.qss +12 -0
- molde/stylesheets/qpushbutton.qss +91 -0
- molde/stylesheets/qradiobutton.qss +31 -0
- molde/stylesheets/qscrollbar.qss +30 -0
- molde/stylesheets/qslider.qss +61 -0
- molde/stylesheets/qtablewidget.qss +27 -0
- molde/stylesheets/qtabwidget.qss +30 -0
- molde/stylesheets/qtoolbar.qss +62 -0
- molde/stylesheets/qtoolbuttons.qss +14 -0
- molde/stylesheets/qtreewidget.qss +25 -0
- molde/utils/__init__.py +8 -0
- molde/utils/format_sequences.py +44 -0
- molde/utils/poly_data_utils.py +25 -0
- molde/utils/tree_info.py +52 -0
- molde-0.1.0.dist-info/METADATA +44 -0
- molde-0.1.0.dist-info/RECORD +62 -0
- molde-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,272 @@
|
|
1
|
+
import numpy as np
|
2
|
+
from vtkmodules.vtkCommonTransforms import vtkTransform
|
3
|
+
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
|
4
|
+
from vtkmodules.vtkRenderingCore import vtkPropPicker
|
5
|
+
|
6
|
+
from molde.actors import RoundPointsActor
|
7
|
+
|
8
|
+
|
9
|
+
class ArcballCameraInteractorStyle(vtkInteractorStyleTrackballCamera):
|
10
|
+
"""
|
11
|
+
Interactor style that rotates and zooms around the cursor.
|
12
|
+
"""
|
13
|
+
|
14
|
+
def __init__(self):
|
15
|
+
self.center_of_rotation = None
|
16
|
+
self.default_center_of_rotation = None
|
17
|
+
|
18
|
+
self.is_left_clicked = False
|
19
|
+
self.is_right_clicked = False
|
20
|
+
self.is_mid_clicked = False
|
21
|
+
|
22
|
+
self.is_rotating = False
|
23
|
+
self.is_panning = False
|
24
|
+
|
25
|
+
# cor = center of rotation
|
26
|
+
self.cor_actor = self._make_default_cor_actor()
|
27
|
+
self._create_observers()
|
28
|
+
|
29
|
+
def set_default_center_of_rotation(self, center):
|
30
|
+
self.default_center_of_rotation = center
|
31
|
+
|
32
|
+
def set_cor_actor(self, actor):
|
33
|
+
self.cor_actor = actor
|
34
|
+
|
35
|
+
def _create_observers(self):
|
36
|
+
self.AddObserver("LeftButtonPressEvent", self._left_button_press_event)
|
37
|
+
self.AddObserver("LeftButtonReleaseEvent", self._left_button_release_event)
|
38
|
+
self.AddObserver("RightButtonPressEvent", self._right_button_press_event)
|
39
|
+
self.AddObserver("RightButtonReleaseEvent", self._right_button_release_event)
|
40
|
+
self.AddObserver("MouseMoveEvent", self._mouse_move_event)
|
41
|
+
self.AddObserver("MouseWheelForwardEvent", self._mouse_wheel_forward_event)
|
42
|
+
self.AddObserver("MouseWheelBackwardEvent", self._mouse_wheel_backward_event)
|
43
|
+
self.AddObserver("MiddleButtonPressEvent", self._click_mid_button_press_event)
|
44
|
+
self.AddObserver(
|
45
|
+
"MiddleButtonReleaseEvent", self._click_mid_button_release_event
|
46
|
+
)
|
47
|
+
|
48
|
+
def _left_button_press_event(self, obj, event):
|
49
|
+
# Implemented to stop the superclass movement
|
50
|
+
self.is_left_clicked = True
|
51
|
+
|
52
|
+
def _left_button_release_event(self, obj, event):
|
53
|
+
# Implemented to stop the superclass movement
|
54
|
+
self.is_left_clicked = False
|
55
|
+
|
56
|
+
def _right_button_press_event(self, obj, event):
|
57
|
+
self.is_right_clicked = True
|
58
|
+
self.is_rotating = True
|
59
|
+
|
60
|
+
cursor = self.GetInteractor().GetEventPosition()
|
61
|
+
self.FindPokedRenderer(cursor[0], cursor[1])
|
62
|
+
|
63
|
+
renderer = self.GetCurrentRenderer() or self.GetDefaultRenderer()
|
64
|
+
camera = renderer.GetActiveCamera()
|
65
|
+
|
66
|
+
if renderer is None:
|
67
|
+
return
|
68
|
+
|
69
|
+
picker = vtkPropPicker()
|
70
|
+
picker.Pick(cursor[0], cursor[1], 0, renderer)
|
71
|
+
pos = picker.GetPickPosition()
|
72
|
+
|
73
|
+
if pos != (0, 0, 0):
|
74
|
+
self.center_of_rotation = pos
|
75
|
+
|
76
|
+
elif self.default_center_of_rotation is not None:
|
77
|
+
self.center_of_rotation = self.default_center_of_rotation
|
78
|
+
|
79
|
+
else:
|
80
|
+
x0, x1, y0, y1, z0, z1 = renderer.ComputeVisiblePropBounds()
|
81
|
+
self.center_of_rotation = [(x0 + x1) / 2, (y0 + y1) / 2, (z0 + z1) / 2]
|
82
|
+
|
83
|
+
dx, dy, dz = np.array(camera.GetPosition()) - np.array(camera.GetFocalPoint())
|
84
|
+
distance_factor = np.sqrt(dx**2 + dy**2 + dz**2)
|
85
|
+
|
86
|
+
self.cor_actor.SetPosition(self.center_of_rotation)
|
87
|
+
self.cor_actor.SetScale(
|
88
|
+
(distance_factor / 3.5, distance_factor / 3.5, distance_factor / 3.5)
|
89
|
+
)
|
90
|
+
renderer.AddActor(self.cor_actor)
|
91
|
+
|
92
|
+
def _right_button_release_event(self, obj, event):
|
93
|
+
self.is_right_clicked = False
|
94
|
+
self.is_rotating = False
|
95
|
+
renderer = self.GetDefaultRenderer() or self.GetCurrentRenderer()
|
96
|
+
renderer.RemoveActor(self.cor_actor)
|
97
|
+
self.GetInteractor().Render()
|
98
|
+
self.EndDolly()
|
99
|
+
|
100
|
+
def _click_mid_button_press_event(self, obj, event):
|
101
|
+
self.is_mid_clicked = True
|
102
|
+
self.is_panning = True
|
103
|
+
int_pos = self.GetInteractor().GetEventPosition()
|
104
|
+
self.FindPokedRenderer(int_pos[0], int_pos[1])
|
105
|
+
|
106
|
+
def _click_mid_button_release_event(self, obj, event):
|
107
|
+
self.is_mid_clicked = False
|
108
|
+
self.is_panning = False
|
109
|
+
|
110
|
+
def _mouse_move_event(self, obj, event):
|
111
|
+
if self.is_rotating:
|
112
|
+
self.rotate()
|
113
|
+
|
114
|
+
if self.is_panning:
|
115
|
+
self.Pan()
|
116
|
+
|
117
|
+
self.OnMouseMove()
|
118
|
+
|
119
|
+
def _mouse_wheel_forward_event(self, obj, event):
|
120
|
+
int_pos = self.GetInteractor().GetEventPosition()
|
121
|
+
|
122
|
+
self.FindPokedRenderer(int_pos[0], int_pos[1])
|
123
|
+
|
124
|
+
if self.GetCurrentRenderer() is None:
|
125
|
+
return
|
126
|
+
|
127
|
+
motion_factor = 10
|
128
|
+
mouse_motion_factor = 1
|
129
|
+
|
130
|
+
factor = motion_factor * 0.2 * mouse_motion_factor
|
131
|
+
|
132
|
+
self.dolly(1.1**factor)
|
133
|
+
|
134
|
+
self.ReleaseFocus()
|
135
|
+
|
136
|
+
def _mouse_wheel_backward_event(self, obj, event):
|
137
|
+
int_pos = self.GetInteractor().GetEventPosition()
|
138
|
+
|
139
|
+
self.FindPokedRenderer(int_pos[0], int_pos[1])
|
140
|
+
|
141
|
+
if self.GetCurrentRenderer() is None:
|
142
|
+
return
|
143
|
+
|
144
|
+
motion_factor = 10
|
145
|
+
mouse_motion_factor = 1
|
146
|
+
|
147
|
+
factor = motion_factor * -0.2 * mouse_motion_factor
|
148
|
+
|
149
|
+
self.dolly(1.1**factor)
|
150
|
+
|
151
|
+
self.ReleaseFocus()
|
152
|
+
|
153
|
+
def rotate(self):
|
154
|
+
renderer = self.GetDefaultRenderer() or self.GetCurrentRenderer()
|
155
|
+
if renderer is None:
|
156
|
+
return
|
157
|
+
|
158
|
+
rwi = self.GetInteractor()
|
159
|
+
delta_mouse = np.array(rwi.GetEventPosition()) - np.array(
|
160
|
+
rwi.GetLastEventPosition()
|
161
|
+
)
|
162
|
+
size = np.array(renderer.GetRenderWindow().GetSize())
|
163
|
+
motion_factor = 10
|
164
|
+
elevation_azimuth = -20 / size
|
165
|
+
rotation_factor = delta_mouse * motion_factor * elevation_azimuth
|
166
|
+
|
167
|
+
camera = renderer.GetActiveCamera()
|
168
|
+
|
169
|
+
self.rotate_around_center(rotation_factor[0], rotation_factor[1])
|
170
|
+
|
171
|
+
camera.OrthogonalizeViewUp()
|
172
|
+
|
173
|
+
renderer.ResetCameraClippingRange()
|
174
|
+
|
175
|
+
if rwi.GetLightFollowCamera():
|
176
|
+
renderer.UpdateLightsGeometryToFollowCamera()
|
177
|
+
|
178
|
+
rwi.Render()
|
179
|
+
|
180
|
+
def rotate_around_center(self, anglex, angley):
|
181
|
+
renderer = self.GetDefaultRenderer() or self.GetCurrentRenderer()
|
182
|
+
camera = renderer.GetActiveCamera()
|
183
|
+
|
184
|
+
transform_camera = vtkTransform()
|
185
|
+
transform_camera.Identity()
|
186
|
+
|
187
|
+
axis = [
|
188
|
+
-camera.GetViewTransformObject().GetMatrix().GetElement(0, 0),
|
189
|
+
-camera.GetViewTransformObject().GetMatrix().GetElement(0, 1),
|
190
|
+
-camera.GetViewTransformObject().GetMatrix().GetElement(0, 2),
|
191
|
+
]
|
192
|
+
|
193
|
+
saved_view_up = camera.GetViewUp()
|
194
|
+
transform_camera.RotateWXYZ(angley, axis)
|
195
|
+
new_view_up = transform_camera.TransformPoint(camera.GetViewUp())
|
196
|
+
camera.SetViewUp(new_view_up)
|
197
|
+
transform_camera.Identity()
|
198
|
+
|
199
|
+
cor = self.center_of_rotation
|
200
|
+
|
201
|
+
transform_camera.Translate(+cor[0], +cor[1], +cor[2])
|
202
|
+
transform_camera.RotateWXYZ(anglex, camera.GetViewUp())
|
203
|
+
transform_camera.RotateWXYZ(angley, axis)
|
204
|
+
transform_camera.Translate(-cor[0], -cor[1], -cor[2])
|
205
|
+
|
206
|
+
new_camera_position = transform_camera.TransformPoint(camera.GetPosition())
|
207
|
+
camera.SetPosition(new_camera_position)
|
208
|
+
|
209
|
+
new_focal_point = transform_camera.TransformPoint(camera.GetFocalPoint())
|
210
|
+
camera.SetFocalPoint(new_focal_point)
|
211
|
+
|
212
|
+
camera.SetViewUp(saved_view_up)
|
213
|
+
|
214
|
+
camera.Modified()
|
215
|
+
|
216
|
+
def dolly(self, factor):
|
217
|
+
renderer = self.GetDefaultRenderer() or self.GetCurrentRenderer()
|
218
|
+
camera = renderer.GetActiveCamera()
|
219
|
+
cursor = self.GetInteractor().GetEventPosition()
|
220
|
+
|
221
|
+
if factor <= 0:
|
222
|
+
return
|
223
|
+
|
224
|
+
cam_up = np.array(camera.GetViewUp())
|
225
|
+
cam_in = np.array(camera.GetDirectionOfProjection())
|
226
|
+
cam_side = np.cross(cam_in, cam_up)
|
227
|
+
|
228
|
+
displacements = self.get_dolly_displacements(
|
229
|
+
factor,
|
230
|
+
cursor,
|
231
|
+
camera,
|
232
|
+
renderer,
|
233
|
+
)
|
234
|
+
|
235
|
+
camera_position = np.array(camera.GetPosition())
|
236
|
+
focal_point = np.array(camera.GetFocalPoint())
|
237
|
+
rotated_displacements = cam_side * displacements[0] + cam_up * displacements[1]
|
238
|
+
camera.SetPosition(camera_position + rotated_displacements)
|
239
|
+
camera.SetFocalPoint(focal_point + rotated_displacements)
|
240
|
+
|
241
|
+
if camera.GetParallelProjection():
|
242
|
+
camera.SetParallelScale(camera.GetParallelScale() / factor)
|
243
|
+
else:
|
244
|
+
camera.Dolly(factor)
|
245
|
+
if self.GetAutoAdjustCameraClippingRange():
|
246
|
+
renderer.ResetCameraClippingRange()
|
247
|
+
|
248
|
+
if self.GetInteractor().GetLightFollowCamera():
|
249
|
+
renderer.UpdateLightsGeometryToFollowCamera()
|
250
|
+
|
251
|
+
self.GetInteractor().Render()
|
252
|
+
|
253
|
+
def get_dolly_displacements(self, factor, cursor, camera, renderer):
|
254
|
+
cursor = np.array(cursor)
|
255
|
+
view_center = np.array(renderer.GetSize()) / 2
|
256
|
+
cursor_to_center = cursor - view_center
|
257
|
+
|
258
|
+
if camera.GetParallelProjection():
|
259
|
+
view_height = 2 * camera.GetParallelScale()
|
260
|
+
else:
|
261
|
+
correction = camera.GetDistance()
|
262
|
+
view_height = 2 * correction * np.tan(0.5 * camera.GetViewAngle() / 57.296)
|
263
|
+
|
264
|
+
scale = view_height / renderer.GetSize()[1]
|
265
|
+
return cursor_to_center * scale * (1 - 1 / factor)
|
266
|
+
|
267
|
+
def _make_default_cor_actor(self):
|
268
|
+
actor = RoundPointsActor([(0, 0, 0)])
|
269
|
+
actor.appear_in_front(True)
|
270
|
+
actor.GetProperty().SetColor(1, 0, 0)
|
271
|
+
actor.GetProperty().SetPointSize(10)
|
272
|
+
return actor
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import numpy as np
|
2
|
+
from vtkmodules.vtkCommonCore import vtkUnsignedCharArray
|
3
|
+
|
4
|
+
from .arcball_camera_style import ArcballCameraInteractorStyle
|
5
|
+
|
6
|
+
|
7
|
+
class BoxSelectionInteractorStyle(ArcballCameraInteractorStyle):
|
8
|
+
def __init__(self) -> None:
|
9
|
+
ArcballCameraInteractorStyle.__init__(self)
|
10
|
+
|
11
|
+
self.is_selecting = False
|
12
|
+
self._click_position = (0, 0)
|
13
|
+
self._mouse_position = (0, 0)
|
14
|
+
self._saved_pixels = vtkUnsignedCharArray()
|
15
|
+
self.selection_color = (255, 0, 0, 255)
|
16
|
+
|
17
|
+
def _left_button_press_event(self, obj, event):
|
18
|
+
super()._left_button_press_event(obj, event)
|
19
|
+
self._click_position = self.GetInteractor().GetEventPosition()
|
20
|
+
self.start_selection()
|
21
|
+
|
22
|
+
def _left_button_release_event(self, obj, event):
|
23
|
+
super()._left_button_release_event(obj, event)
|
24
|
+
self.stop_selection()
|
25
|
+
|
26
|
+
def _mouse_move_event(self, obj, event):
|
27
|
+
super()._mouse_move_event(obj, event)
|
28
|
+
self._mouse_position = self.GetInteractor().GetEventPosition()
|
29
|
+
self.update_selection()
|
30
|
+
|
31
|
+
def start_selection(self):
|
32
|
+
self.is_selecting = True
|
33
|
+
|
34
|
+
size = self.GetInteractor().GetSize()
|
35
|
+
render_window = self.GetInteractor().GetRenderWindow()
|
36
|
+
render_window.Render()
|
37
|
+
# Save the current screen state
|
38
|
+
render_window.GetRGBACharPixelData(
|
39
|
+
0, 0, size[0] - 1, size[1] - 1, 0, self._saved_pixels
|
40
|
+
)
|
41
|
+
|
42
|
+
def update_selection(self):
|
43
|
+
if not self.is_selecting:
|
44
|
+
return
|
45
|
+
|
46
|
+
size = self.GetInteractor().GetSize()
|
47
|
+
min_x, max_x = sorted([self._click_position[0], self._mouse_position[0]])
|
48
|
+
min_y, max_y = sorted([self._click_position[1], self._mouse_position[1]])
|
49
|
+
min_x, max_x = np.clip([min_x, max_x], 0, size[0])
|
50
|
+
min_y, max_y = np.clip([min_y, max_y], 0, size[1])
|
51
|
+
|
52
|
+
# Copy the saved screen state and draw over it
|
53
|
+
selected_pixels = vtkUnsignedCharArray()
|
54
|
+
selected_pixels.DeepCopy(self._saved_pixels)
|
55
|
+
|
56
|
+
for x in range(min_x, max_x, 2):
|
57
|
+
for y in range(min_y, max_y, 2):
|
58
|
+
pixel = y * size[0] + x
|
59
|
+
selected_pixels.SetTuple(pixel, self.selection_color)
|
60
|
+
|
61
|
+
renderWindow = self.GetInteractor().GetRenderWindow()
|
62
|
+
renderWindow.SetRGBACharPixelData(
|
63
|
+
0, 0, size[0] - 1, size[1] - 1, selected_pixels, 0
|
64
|
+
)
|
65
|
+
renderWindow.Frame()
|
66
|
+
|
67
|
+
def stop_selection(self):
|
68
|
+
self.is_selecting = False
|
69
|
+
render_window = self.GetInteractor().GetRenderWindow()
|
70
|
+
render_window.Render()
|
@@ -0,0 +1,61 @@
|
|
1
|
+
from vtkmodules.vtkCommonDataModel import vtkPolyData
|
2
|
+
from vtkmodules.vtkFiltersGeneral import vtkExtractSelectedFrustum
|
3
|
+
from vtkmodules.vtkRenderingCore import (
|
4
|
+
vtkActor,
|
5
|
+
vtkAreaPicker,
|
6
|
+
vtkCellPicker,
|
7
|
+
vtkPropPicker,
|
8
|
+
vtkRenderer,
|
9
|
+
)
|
10
|
+
|
11
|
+
|
12
|
+
class CellAreaPicker(vtkPropPicker):
|
13
|
+
def __init__(self) -> None:
|
14
|
+
super().__init__()
|
15
|
+
self._picked_cells = []
|
16
|
+
self._picked_actors = []
|
17
|
+
self._picked = dict()
|
18
|
+
|
19
|
+
self._area_picker = vtkAreaPicker()
|
20
|
+
self._cell_picker = vtkCellPicker()
|
21
|
+
self._cell_picker.SetTolerance(0.01)
|
22
|
+
|
23
|
+
def pick(self, x: float, y: float, z: float, renderer: vtkRenderer):
|
24
|
+
self._picked.clear()
|
25
|
+
self._cell_picker.Pick(x, y, z, renderer)
|
26
|
+
self._picked[self._cell_picker.GetActor()] = [self._cell_picker.GetCellId()]
|
27
|
+
|
28
|
+
# # select a small area around the mouse click
|
29
|
+
# delta = 10
|
30
|
+
# self.area_pick(x-delta, y-delta, x+delta, y+delta, renderer)
|
31
|
+
|
32
|
+
# # keep at most a single cell selected for every picked actor
|
33
|
+
# for actor, selection in self._picked.items():
|
34
|
+
# self._picked[actor] = selection[:1]
|
35
|
+
|
36
|
+
def area_pick(
|
37
|
+
self, x0: float, y0: float, x1: float, y1: float, renderer: vtkRenderer
|
38
|
+
):
|
39
|
+
self._picked.clear()
|
40
|
+
self._area_picker.AreaPick(x0, y0, x1, y1, renderer)
|
41
|
+
extractor = vtkExtractSelectedFrustum()
|
42
|
+
extractor.SetFrustum(self._area_picker.GetFrustum())
|
43
|
+
|
44
|
+
for actor in self._area_picker.GetProp3Ds():
|
45
|
+
if not isinstance(actor, vtkActor):
|
46
|
+
continue
|
47
|
+
|
48
|
+
data: vtkPolyData = actor.GetMapper().GetInput()
|
49
|
+
if data is None:
|
50
|
+
continue
|
51
|
+
|
52
|
+
cells = []
|
53
|
+
for i in range(data.GetNumberOfCells()):
|
54
|
+
bounds = [0, 0, 0, 0, 0, 0]
|
55
|
+
data.GetCellBounds(i, bounds)
|
56
|
+
if extractor.OverallBoundsTest(bounds):
|
57
|
+
cells.append(i)
|
58
|
+
self._picked[actor] = cells
|
59
|
+
|
60
|
+
def get_picked(self):
|
61
|
+
return dict(self._picked)
|
@@ -0,0 +1,84 @@
|
|
1
|
+
from vtkmodules.vtkCommonDataModel import vtkPolyData
|
2
|
+
from vtkmodules.vtkFiltersGeneral import vtkExtractSelectedFrustum
|
3
|
+
from vtkmodules.vtkRenderingCore import (
|
4
|
+
vtkActor,
|
5
|
+
vtkAreaPicker,
|
6
|
+
vtkCellPicker,
|
7
|
+
vtkPropPicker,
|
8
|
+
vtkRenderer,
|
9
|
+
)
|
10
|
+
|
11
|
+
|
12
|
+
class CellPropertyAreaPicker(vtkPropPicker):
|
13
|
+
def __init__(self, property_name: str, desired_actor: vtkActor) -> None:
|
14
|
+
super().__init__()
|
15
|
+
|
16
|
+
self.property_name = property_name
|
17
|
+
self.desired_actor = desired_actor
|
18
|
+
self._picked = set()
|
19
|
+
|
20
|
+
self._cell_picker = vtkCellPicker()
|
21
|
+
self._area_picker = vtkAreaPicker()
|
22
|
+
self._cell_picker.SetTolerance(0.005)
|
23
|
+
|
24
|
+
def pick(self, x: float, y: float, z: float, renderer: vtkRenderer):
|
25
|
+
# maybe a behaviour like the one implemented in CellAreaPicker
|
26
|
+
# would fit nicely here
|
27
|
+
self._picked.clear()
|
28
|
+
self._cell_picker.Pick(x, y, z, renderer)
|
29
|
+
|
30
|
+
if self.desired_actor != self._cell_picker.GetActor():
|
31
|
+
return self.get_picked()
|
32
|
+
|
33
|
+
data: vtkPolyData = self.desired_actor.GetMapper().GetInput()
|
34
|
+
if data is None:
|
35
|
+
return self.get_picked()
|
36
|
+
|
37
|
+
property_array = data.GetCellData().GetArray(self.property_name)
|
38
|
+
if property_array is None:
|
39
|
+
return self.get_picked()
|
40
|
+
|
41
|
+
cell = self._cell_picker.GetCellId()
|
42
|
+
property_val = property_array.GetValue(cell)
|
43
|
+
self._picked.add(property_val)
|
44
|
+
return self.get_picked()
|
45
|
+
|
46
|
+
def area_pick(
|
47
|
+
self, x0: float, y0: float, x1: float, y1: float, renderer: vtkRenderer
|
48
|
+
):
|
49
|
+
self._picked.clear()
|
50
|
+
self._area_picker.AreaPick(x0, y0, x1, y1, renderer)
|
51
|
+
extractor = vtkExtractSelectedFrustum()
|
52
|
+
extractor.SetFrustum(self._area_picker.GetFrustum())
|
53
|
+
|
54
|
+
if self.desired_actor not in self._area_picker.GetProp3Ds():
|
55
|
+
return self.get_picked()
|
56
|
+
|
57
|
+
data: vtkPolyData = self.desired_actor.GetMapper().GetInput()
|
58
|
+
if data is None:
|
59
|
+
return self.get_picked()
|
60
|
+
|
61
|
+
property_array = data.GetCellData().GetArray(self.property_name)
|
62
|
+
if property_array is None:
|
63
|
+
return self.get_picked()
|
64
|
+
|
65
|
+
if property_array.GetNumberOfValues() < data.GetNumberOfCells():
|
66
|
+
return self.get_picked()
|
67
|
+
|
68
|
+
for cell in range(data.GetNumberOfCells()):
|
69
|
+
property_val = property_array.GetValue(cell)
|
70
|
+
|
71
|
+
# if the property was already picked
|
72
|
+
# we don't even need to check if the cell
|
73
|
+
# is inside the selection box
|
74
|
+
if property_val in self._picked:
|
75
|
+
continue
|
76
|
+
|
77
|
+
bounds = [0, 0, 0, 0, 0, 0]
|
78
|
+
data.GetCellBounds(cell, bounds)
|
79
|
+
if extractor.OverallBoundsTest(bounds):
|
80
|
+
self._picked.add(property_val)
|
81
|
+
return self.get_picked()
|
82
|
+
|
83
|
+
def get_picked(self):
|
84
|
+
return set(self._picked)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from vtkmodules.vtkCommonCore import vtkPoints
|
2
|
+
from vtkmodules.vtkCommonDataModel import VTK_LINE, vtkPolyData
|
3
|
+
|
4
|
+
|
5
|
+
class LinesData(vtkPolyData):
|
6
|
+
def __init__(self, lines_list) -> None:
|
7
|
+
super().__init__()
|
8
|
+
|
9
|
+
self.lines_list = lines_list
|
10
|
+
self.build()
|
11
|
+
|
12
|
+
def build(self):
|
13
|
+
points = vtkPoints()
|
14
|
+
self.Allocate(len(self.lines_list))
|
15
|
+
|
16
|
+
current_point = 0
|
17
|
+
for x0, y0, z0, x1, y1, z1 in self.lines_list:
|
18
|
+
points.InsertPoint(current_point, x0, y0, z0)
|
19
|
+
points.InsertPoint(current_point + 1, x1, y1, z1)
|
20
|
+
self.InsertNextCell(VTK_LINE, 2, [current_point, current_point + 1])
|
21
|
+
current_point += 2
|
22
|
+
|
23
|
+
self.SetPoints(points)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
from vtkmodules.vtkCommonCore import vtkPoints
|
2
|
+
from vtkmodules.vtkCommonDataModel import VTK_VERTEX, vtkPolyData
|
3
|
+
|
4
|
+
|
5
|
+
class VerticesData(vtkPolyData):
|
6
|
+
"""
|
7
|
+
This class describes a polydata composed by a set of points.
|
8
|
+
"""
|
9
|
+
|
10
|
+
def __init__(self, points_list: list[tuple[int, int, int]]) -> None:
|
11
|
+
super().__init__()
|
12
|
+
|
13
|
+
self.points_list = points_list
|
14
|
+
self.build()
|
15
|
+
|
16
|
+
def build(self):
|
17
|
+
points = vtkPoints()
|
18
|
+
self.Allocate(len(self.points_list))
|
19
|
+
|
20
|
+
for i, (x, y, z) in enumerate(self.points_list):
|
21
|
+
points.InsertNextPoint(x, y, z)
|
22
|
+
self.InsertNextCell(VTK_VERTEX, 1, [i])
|
23
|
+
|
24
|
+
self.SetPoints(points)
|