ansys-tools-visualization-interface 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.
- ansys/tools/visualization_interface/__init__.py +39 -0
- ansys/tools/visualization_interface/backends/__init__.py +22 -0
- ansys/tools/visualization_interface/backends/_base.py +45 -0
- ansys/tools/visualization_interface/backends/pyvista/__init__.py +26 -0
- ansys/tools/visualization_interface/backends/pyvista/pyvista.py +505 -0
- ansys/tools/visualization_interface/backends/pyvista/pyvista_interface.py +358 -0
- ansys/tools/visualization_interface/backends/pyvista/trame_local.py +72 -0
- ansys/tools/visualization_interface/backends/pyvista/trame_remote.py +63 -0
- ansys/tools/visualization_interface/backends/pyvista/trame_service.py +125 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/__init__.py +25 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+xy.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+xz.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+yz.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-xy.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-xz.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-yz.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/designpoint.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/downarrow.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/isometric.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/measurement.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/ruler.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upxarrow.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upyarrow.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upzarrow.png +0 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/button.py +80 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/displace_arrows.py +95 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/measure.py +90 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/ruler.py +93 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/view_button.py +91 -0
- ansys/tools/visualization_interface/backends/pyvista/widgets/widget.py +63 -0
- ansys/tools/visualization_interface/plotter.py +61 -0
- ansys/tools/visualization_interface/types/__init__.py +22 -0
- ansys/tools/visualization_interface/types/edge_plot.py +112 -0
- ansys/tools/visualization_interface/types/mesh_object_plot.py +175 -0
- ansys/tools/visualization_interface/utils/__init__.py +22 -0
- ansys/tools/visualization_interface/utils/clip_plane.py +96 -0
- ansys/tools/visualization_interface/utils/color.py +40 -0
- ansys/tools/visualization_interface/utils/logger.py +118 -0
- ansys_tools_visualization_interface-0.1.0.dist-info/LICENSE +21 -0
- ansys_tools_visualization_interface-0.1.0.dist-info/METADATA +126 -0
- ansys_tools_visualization_interface-0.1.0.dist-info/RECORD +42 -0
- ansys_tools_visualization_interface-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
"""Visualization Interface tool is a Python client library for visualizing the results of Ansys simulations."""
|
|
23
|
+
import os
|
|
24
|
+
|
|
25
|
+
import pkg_resources
|
|
26
|
+
|
|
27
|
+
__version__ = pkg_resources.get_distribution("ansys-tools-visualization-interface").version
|
|
28
|
+
|
|
29
|
+
USE_TRAME: bool = False
|
|
30
|
+
DOCUMENTATION_BUILD: bool = False
|
|
31
|
+
TESTING_MODE: bool = os.environ.get("PYANSYS_VISUALIZER_TESTMODE", "false").lower() == "true"
|
|
32
|
+
|
|
33
|
+
from ansys.tools.visualization_interface.plotter import Plotter # noqa: F401, E402
|
|
34
|
+
from ansys.tools.visualization_interface.types.edge_plot import EdgePlot # noqa: F401, E402
|
|
35
|
+
from ansys.tools.visualization_interface.types.mesh_object_plot import ( # noqa: F401, E402
|
|
36
|
+
MeshObjectPlot,
|
|
37
|
+
)
|
|
38
|
+
from ansys.tools.visualization_interface.utils.clip_plane import ClipPlane # noqa: F401, E402
|
|
39
|
+
from ansys.tools.visualization_interface.utils.color import Color # noqa: F401, E402
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
"""Provides interfaces."""
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Copyright (C) 2024 ANSYS, Inc. and/or its affiliates.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
|
|
23
|
+
"""Module for the backend base class."""
|
|
24
|
+
from abc import ABC, abstractmethod
|
|
25
|
+
|
|
26
|
+
from beartype.typing import Any, Iterable
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class BaseBackend(ABC):
|
|
30
|
+
"""Base class for plotting backends."""
|
|
31
|
+
|
|
32
|
+
@abstractmethod
|
|
33
|
+
def plot(self, object: Any, **plotting_options):
|
|
34
|
+
"""Plot the specified object."""
|
|
35
|
+
raise NotImplementedError("plot method must be implemented")
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def plot_iter(self, object: Iterable):
|
|
39
|
+
"""Plot the elements of an iterable."""
|
|
40
|
+
raise NotImplementedError("plot_iter method must be implemented")
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def show(self):
|
|
44
|
+
"""Show the plotted objects."""
|
|
45
|
+
raise NotImplementedError("show method must be implemented")
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
"""Provides interfaces."""
|
|
23
|
+
from ansys.tools.visualization_interface.backends.pyvista.pyvista import ( # noqa: F401
|
|
24
|
+
PyVistaBackend,
|
|
25
|
+
PyVistaBackendInterface,
|
|
26
|
+
)
|
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
"""Provides a wrapper to aid in plotting."""
|
|
23
|
+
from abc import abstractmethod
|
|
24
|
+
|
|
25
|
+
from beartype.typing import Any, Dict, List, Optional, Union
|
|
26
|
+
import numpy as np
|
|
27
|
+
import pyvista as pv
|
|
28
|
+
|
|
29
|
+
from ansys.tools.visualization_interface import USE_TRAME
|
|
30
|
+
from ansys.tools.visualization_interface.backends._base import BaseBackend
|
|
31
|
+
from ansys.tools.visualization_interface.backends.pyvista.pyvista_interface import PyVistaInterface
|
|
32
|
+
from ansys.tools.visualization_interface.backends.pyvista.trame_local import (
|
|
33
|
+
_HAS_TRAME,
|
|
34
|
+
TrameVisualizer,
|
|
35
|
+
)
|
|
36
|
+
from ansys.tools.visualization_interface.backends.pyvista.widgets.displace_arrows import (
|
|
37
|
+
CameraPanDirection,
|
|
38
|
+
DisplacementArrow,
|
|
39
|
+
)
|
|
40
|
+
from ansys.tools.visualization_interface.backends.pyvista.widgets.measure import MeasureWidget
|
|
41
|
+
from ansys.tools.visualization_interface.backends.pyvista.widgets.ruler import Ruler
|
|
42
|
+
from ansys.tools.visualization_interface.backends.pyvista.widgets.view_button import (
|
|
43
|
+
ViewButton,
|
|
44
|
+
ViewDirection,
|
|
45
|
+
)
|
|
46
|
+
from ansys.tools.visualization_interface.backends.pyvista.widgets.widget import PlotterWidget
|
|
47
|
+
from ansys.tools.visualization_interface.types.edge_plot import EdgePlot
|
|
48
|
+
from ansys.tools.visualization_interface.types.mesh_object_plot import MeshObjectPlot
|
|
49
|
+
from ansys.tools.visualization_interface.utils.color import Color
|
|
50
|
+
from ansys.tools.visualization_interface.utils.logger import logger
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class PyVistaBackendInterface(BaseBackend):
|
|
54
|
+
"""Provides the interface for the Visualization Interface tool plotter.
|
|
55
|
+
|
|
56
|
+
This class is intended to be used as a base class for the custom plotters
|
|
57
|
+
in the different PyAnsys libraries. It provides the basic plotter functionalities,
|
|
58
|
+
such as adding objects and enabling widgets and picking capabilities. It also
|
|
59
|
+
provides the ability to show the plotter using the `trame <https://kitware.github.io/trame/index.html>`_
|
|
60
|
+
service.
|
|
61
|
+
|
|
62
|
+
You can override the ``plot_iter()``, ``plot()``, and ``picked_operation()`` methods.
|
|
63
|
+
The ``plot_iter()`` method is intended to plot a list of objects to the plotter, while the
|
|
64
|
+
``plot()`` method is intended to plot a single object to the plotter. The ``show()`` method is
|
|
65
|
+
intended to show the plotter. The ``picked_operation()`` method is
|
|
66
|
+
intended to perform an operation on the picked objects.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
use_trame : Optional[bool], default: None
|
|
71
|
+
Whether to activate the usage of the trame UI instead of the Python window.
|
|
72
|
+
allow_picking : Optional[bool], default: False
|
|
73
|
+
Whether to allow picking capabilities in the window.
|
|
74
|
+
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
def __init__(
|
|
78
|
+
self,
|
|
79
|
+
use_trame: Optional[bool] = None,
|
|
80
|
+
allow_picking: Optional[bool] = False,
|
|
81
|
+
plot_picked_names: Optional[bool] = False,
|
|
82
|
+
show_plane: Optional[bool] = False,
|
|
83
|
+
**plotter_kwargs,
|
|
84
|
+
) -> None:
|
|
85
|
+
"""Initialize the ``use_trame`` parameter and save the current ``pv.OFF_SCREEN`` value."""
|
|
86
|
+
# Check if the use of trame was requested
|
|
87
|
+
if use_trame is None:
|
|
88
|
+
use_trame = USE_TRAME
|
|
89
|
+
|
|
90
|
+
self._use_trame = use_trame
|
|
91
|
+
self._allow_picking = allow_picking
|
|
92
|
+
self._pv_off_screen_original = bool(pv.OFF_SCREEN)
|
|
93
|
+
self._plot_picked_names = plot_picked_names
|
|
94
|
+
# Map that relates PyVista actors with PyAnsys objects
|
|
95
|
+
self._object_to_actors_map = {}
|
|
96
|
+
|
|
97
|
+
# PyVista plotter
|
|
98
|
+
self._pl = None
|
|
99
|
+
|
|
100
|
+
# List of picked objects in MeshObject format.
|
|
101
|
+
self._picked_list = set()
|
|
102
|
+
|
|
103
|
+
# Map that relates PyVista actors with the added actors by the picker
|
|
104
|
+
self._picker_added_actors_map = {}
|
|
105
|
+
|
|
106
|
+
# Map that relates PyVista actors with EdgePlot objects
|
|
107
|
+
self._edge_actors_map = {}
|
|
108
|
+
|
|
109
|
+
# List of widgets added to the plotter.
|
|
110
|
+
self._widgets = []
|
|
111
|
+
|
|
112
|
+
# Map that saves original colors of the plotted objects.
|
|
113
|
+
self._origin_colors = {}
|
|
114
|
+
|
|
115
|
+
# Enable the use of trame if requested and available
|
|
116
|
+
if self._use_trame and _HAS_TRAME:
|
|
117
|
+
# avoids GUI window popping up
|
|
118
|
+
pv.OFF_SCREEN = True
|
|
119
|
+
self._pl = PyVistaInterface(
|
|
120
|
+
enable_widgets=False, show_plane=show_plane, **plotter_kwargs
|
|
121
|
+
)
|
|
122
|
+
elif self._use_trame and not _HAS_TRAME:
|
|
123
|
+
warn_msg = (
|
|
124
|
+
"'use_trame' is active but trame dependencies are not installed."
|
|
125
|
+
"Consider installing 'pyvista[trame]' to use this functionality."
|
|
126
|
+
)
|
|
127
|
+
logger.warning(warn_msg)
|
|
128
|
+
self._pl = PyVistaInterface(show_plane=show_plane)
|
|
129
|
+
else:
|
|
130
|
+
self._pl = PyVistaInterface(show_plane=show_plane)
|
|
131
|
+
|
|
132
|
+
self._enable_widgets = self._pl._enable_widgets
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def pv_interface(self) -> PyVistaInterface:
|
|
136
|
+
"""PyVista interface."""
|
|
137
|
+
return self._pl
|
|
138
|
+
|
|
139
|
+
def enable_widgets(self):
|
|
140
|
+
"""Enable the widgets for the plotter."""
|
|
141
|
+
# Create Plotter widgets
|
|
142
|
+
if self._enable_widgets:
|
|
143
|
+
self._widgets: List[PlotterWidget] = []
|
|
144
|
+
self._widgets.append(Ruler(self._pl._scene))
|
|
145
|
+
[
|
|
146
|
+
self._widgets.append(DisplacementArrow(self._pl._scene, direction=dir))
|
|
147
|
+
for dir in CameraPanDirection
|
|
148
|
+
]
|
|
149
|
+
[
|
|
150
|
+
self._widgets.append(ViewButton(self._pl._scene, direction=dir))
|
|
151
|
+
for dir in ViewDirection
|
|
152
|
+
]
|
|
153
|
+
self._widgets.append(MeasureWidget(self))
|
|
154
|
+
|
|
155
|
+
def add_widget(self, widget: Union[PlotterWidget, List[PlotterWidget]]):
|
|
156
|
+
"""Add one or more custom widgets to the plotter.
|
|
157
|
+
|
|
158
|
+
Parameters
|
|
159
|
+
----------
|
|
160
|
+
widget : Union[PlotterWidget, List[PlotterWidget]]
|
|
161
|
+
One or more custom widgets.
|
|
162
|
+
|
|
163
|
+
"""
|
|
164
|
+
if isinstance(widget, list):
|
|
165
|
+
self._widgets.extend(widget)
|
|
166
|
+
widget.update()
|
|
167
|
+
else:
|
|
168
|
+
self._widgets.append(widget)
|
|
169
|
+
widget.update()
|
|
170
|
+
|
|
171
|
+
def select_object(self, custom_object: Union[MeshObjectPlot, EdgePlot], pt: np.ndarray) -> None:
|
|
172
|
+
"""Select a custom object in the plotter.
|
|
173
|
+
|
|
174
|
+
This method highlights the edges of a body and adds a label. It also adds
|
|
175
|
+
the object to the ``_picked_list`` and the actor to the ``_picker_added_actors_map``.
|
|
176
|
+
|
|
177
|
+
Parameters
|
|
178
|
+
----------
|
|
179
|
+
custom_object : Union[MeshObjectPlot, EdgePlot]
|
|
180
|
+
Custom object to select.
|
|
181
|
+
pt : ~numpy.ndarray
|
|
182
|
+
Set of points to determine the label position.
|
|
183
|
+
|
|
184
|
+
"""
|
|
185
|
+
added_actors = []
|
|
186
|
+
|
|
187
|
+
# Add edges if selecting an object
|
|
188
|
+
if isinstance(custom_object, MeshObjectPlot):
|
|
189
|
+
self._origin_colors[custom_object] = custom_object.actor.prop.color
|
|
190
|
+
custom_object.actor.prop.color = Color.PICKED.value
|
|
191
|
+
children_list = custom_object.edges
|
|
192
|
+
if children_list is not None:
|
|
193
|
+
for edge in children_list:
|
|
194
|
+
edge.actor.SetVisibility(True)
|
|
195
|
+
edge.actor.prop.color = Color.EDGE.value
|
|
196
|
+
elif isinstance(custom_object, EdgePlot):
|
|
197
|
+
custom_object.actor.prop.color = Color.PICKED_EDGE.value
|
|
198
|
+
|
|
199
|
+
text = custom_object.name
|
|
200
|
+
|
|
201
|
+
if self._plot_picked_names:
|
|
202
|
+
label_actor = self._pl.scene.add_point_labels(
|
|
203
|
+
[pt],
|
|
204
|
+
[text],
|
|
205
|
+
always_visible=True,
|
|
206
|
+
point_size=0,
|
|
207
|
+
render_points_as_spheres=False,
|
|
208
|
+
show_points=False,
|
|
209
|
+
)
|
|
210
|
+
added_actors.append(label_actor)
|
|
211
|
+
|
|
212
|
+
if custom_object not in self._picked_list:
|
|
213
|
+
self._picked_list.add(custom_object)
|
|
214
|
+
|
|
215
|
+
self._picker_added_actors_map[custom_object.actor.name] = added_actors
|
|
216
|
+
|
|
217
|
+
def unselect_object(self, custom_object: Union[MeshObjectPlot, EdgePlot]) -> None:
|
|
218
|
+
"""Unselect a custom object in the plotter.
|
|
219
|
+
|
|
220
|
+
This method removes edge highlighting and the label from a plotter actor and removes
|
|
221
|
+
the object from the Visualization Interface tool object selection.
|
|
222
|
+
|
|
223
|
+
Parameters
|
|
224
|
+
----------
|
|
225
|
+
custom_object : Union[MeshObjectPlot, EdgePlot]
|
|
226
|
+
Custom object to unselect.
|
|
227
|
+
|
|
228
|
+
"""
|
|
229
|
+
# remove actor from picked list and from scene
|
|
230
|
+
if custom_object in self._picked_list:
|
|
231
|
+
self._picked_list.remove(custom_object)
|
|
232
|
+
|
|
233
|
+
if isinstance(custom_object, MeshObjectPlot) and custom_object in self._origin_colors:
|
|
234
|
+
custom_object.actor.prop.color = self._origin_colors[custom_object]
|
|
235
|
+
elif isinstance(custom_object, EdgePlot):
|
|
236
|
+
custom_object.actor.prop.color = Color.EDGE.value
|
|
237
|
+
|
|
238
|
+
if custom_object.actor.name in self._picker_added_actors_map:
|
|
239
|
+
self._pl.scene.remove_actor(self._picker_added_actors_map[custom_object.actor.name])
|
|
240
|
+
|
|
241
|
+
# remove actor and its children(edges) from the scene
|
|
242
|
+
if isinstance(custom_object, MeshObjectPlot):
|
|
243
|
+
if custom_object.edges is not None:
|
|
244
|
+
for edge in custom_object.edges:
|
|
245
|
+
# hide edges in the scene
|
|
246
|
+
edge.actor.SetVisibility(False)
|
|
247
|
+
# recursion
|
|
248
|
+
self.unselect_object(edge)
|
|
249
|
+
self._picker_added_actors_map.pop(custom_object.actor.name)
|
|
250
|
+
|
|
251
|
+
def picker_callback(self, actor: "pv.Actor") -> None:
|
|
252
|
+
"""Define the callback for the element picker.
|
|
253
|
+
|
|
254
|
+
Parameters
|
|
255
|
+
----------
|
|
256
|
+
actor : ~pyvista.Actor
|
|
257
|
+
Actor to select for the picker.
|
|
258
|
+
|
|
259
|
+
"""
|
|
260
|
+
pt = self._pl.scene.picked_point
|
|
261
|
+
|
|
262
|
+
# if object is a body/component
|
|
263
|
+
if actor in self._object_to_actors_map:
|
|
264
|
+
body_plot = self._object_to_actors_map[actor]
|
|
265
|
+
if body_plot not in self._picked_list:
|
|
266
|
+
self.select_object(body_plot, pt)
|
|
267
|
+
else:
|
|
268
|
+
self.unselect_object(body_plot)
|
|
269
|
+
|
|
270
|
+
# if object is an edge
|
|
271
|
+
elif actor in self._edge_actors_map and actor.GetVisibility():
|
|
272
|
+
edge = self._edge_actors_map[actor]
|
|
273
|
+
if edge not in self._picked_list:
|
|
274
|
+
self.select_object(edge, pt)
|
|
275
|
+
else:
|
|
276
|
+
self.unselect_object(edge)
|
|
277
|
+
actor.prop.color = Color.EDGE.value
|
|
278
|
+
|
|
279
|
+
def compute_edge_object_map(self) -> Dict[pv.Actor, EdgePlot]:
|
|
280
|
+
"""Compute the mapping between plotter actors and ``EdgePlot`` objects.
|
|
281
|
+
|
|
282
|
+
Returns
|
|
283
|
+
-------
|
|
284
|
+
Dict[~pyvista.Actor, EdgePlot]
|
|
285
|
+
Dictionary defining the mapping between plotter actors and ``EdgePlot`` objects.
|
|
286
|
+
|
|
287
|
+
"""
|
|
288
|
+
for mesh_object in self._object_to_actors_map.values():
|
|
289
|
+
# get edges only from bodies
|
|
290
|
+
if mesh_object.edges is not None:
|
|
291
|
+
for edge in mesh_object.edges:
|
|
292
|
+
self._edge_actors_map[edge.actor] = edge
|
|
293
|
+
|
|
294
|
+
def enable_picking(self):
|
|
295
|
+
"""Enable picking capabilities in the plotter."""
|
|
296
|
+
self._pl.scene.enable_mesh_picking(
|
|
297
|
+
callback=self.picker_callback,
|
|
298
|
+
use_actor=True,
|
|
299
|
+
show=False,
|
|
300
|
+
show_message=False,
|
|
301
|
+
picker="cell",
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
def disable_picking(self):
|
|
305
|
+
"""Disable picking capabilities in the plotter."""
|
|
306
|
+
self._pl.scene.disable_picking()
|
|
307
|
+
|
|
308
|
+
def show(
|
|
309
|
+
self,
|
|
310
|
+
object: Any = None,
|
|
311
|
+
screenshot: Optional[str] = None,
|
|
312
|
+
view_2d: Dict = None,
|
|
313
|
+
filter: str = None,
|
|
314
|
+
**plotting_options,
|
|
315
|
+
) -> List[Any]:
|
|
316
|
+
"""Plot and show any PyAnsys object.
|
|
317
|
+
|
|
318
|
+
The types of objects supported are ``MeshObjectPlot``,
|
|
319
|
+
``pv.MultiBlock``, and ``pv.PolyData``.
|
|
320
|
+
|
|
321
|
+
Parameters
|
|
322
|
+
----------
|
|
323
|
+
object : Any, default: None
|
|
324
|
+
Object or list of objects to plot.
|
|
325
|
+
screenshot : str, default: None
|
|
326
|
+
Path for saving a screenshot of the image that is being represented.
|
|
327
|
+
view_2d : Dict, default: None
|
|
328
|
+
Dictionary with the plane and the viewup vectors of the 2D plane.
|
|
329
|
+
filter : str, default: None
|
|
330
|
+
Regular expression with the desired name or names to include in the plotter.
|
|
331
|
+
**plotting_options : dict, default: None
|
|
332
|
+
Keyword arguments. For allowable keyword arguments, see the
|
|
333
|
+
:meth:`Plotter.add_mesh <pyvista.Plotter.add_mesh>` method.
|
|
334
|
+
|
|
335
|
+
Returns
|
|
336
|
+
-------
|
|
337
|
+
List[Any]
|
|
338
|
+
List with the picked bodies in the picked order.
|
|
339
|
+
|
|
340
|
+
"""
|
|
341
|
+
self.plot(object, filter, **plotting_options)
|
|
342
|
+
if self._pl._object_to_actors_map:
|
|
343
|
+
self._object_to_actors_map = self._pl._object_to_actors_map
|
|
344
|
+
else:
|
|
345
|
+
logger.warning("No actors were added to the plotter.")
|
|
346
|
+
|
|
347
|
+
# Compute mapping between the objects and its edges.
|
|
348
|
+
_ = self.compute_edge_object_map()
|
|
349
|
+
|
|
350
|
+
if view_2d is not None:
|
|
351
|
+
self._pl.scene.view_vector(
|
|
352
|
+
vector=view_2d["vector"],
|
|
353
|
+
viewup=view_2d["viewup"],
|
|
354
|
+
)
|
|
355
|
+
# Enable widgets and picking capabilities
|
|
356
|
+
self.enable_widgets()
|
|
357
|
+
if self._allow_picking:
|
|
358
|
+
self.enable_picking()
|
|
359
|
+
|
|
360
|
+
# Update all buttons/widgets
|
|
361
|
+
[widget.update() for widget in self._widgets]
|
|
362
|
+
|
|
363
|
+
self.show_plotter(screenshot)
|
|
364
|
+
|
|
365
|
+
picked_objects_list = []
|
|
366
|
+
if isinstance(object, list):
|
|
367
|
+
# Keep them ordered based on picking
|
|
368
|
+
for meshobject in self._picked_list:
|
|
369
|
+
for elem in object:
|
|
370
|
+
if hasattr(elem, "name") and elem.name == meshobject.name:
|
|
371
|
+
picked_objects_list.append(elem)
|
|
372
|
+
elif hasattr(object, "name") and object in self._picked_list:
|
|
373
|
+
picked_objects_list = [object]
|
|
374
|
+
|
|
375
|
+
return picked_objects_list
|
|
376
|
+
|
|
377
|
+
def show_plotter(self, screenshot: Optional[str] = None) -> None:
|
|
378
|
+
"""Show the plotter or start the `trame <https://kitware.github.io/trame/index.html>`_ service.
|
|
379
|
+
|
|
380
|
+
Parameters
|
|
381
|
+
----------
|
|
382
|
+
plotter : Plotter
|
|
383
|
+
Visualization Interface tool plotter with the meshes added.
|
|
384
|
+
screenshot : str, default: None
|
|
385
|
+
Path for saving a screenshot of the image that is being represented.
|
|
386
|
+
|
|
387
|
+
"""
|
|
388
|
+
if self._use_trame and _HAS_TRAME:
|
|
389
|
+
visualizer = TrameVisualizer()
|
|
390
|
+
visualizer.set_scene(self._pl)
|
|
391
|
+
visualizer.show()
|
|
392
|
+
else:
|
|
393
|
+
self.pv_interface.show(screenshot=screenshot)
|
|
394
|
+
|
|
395
|
+
pv.OFF_SCREEN = self._pv_off_screen_original
|
|
396
|
+
|
|
397
|
+
@abstractmethod
|
|
398
|
+
def plot_iter(self, object: Any, filter: str = None, **plotting_options):
|
|
399
|
+
"""Plot one or more compatible objects to the plotter.
|
|
400
|
+
|
|
401
|
+
Parameters
|
|
402
|
+
----------
|
|
403
|
+
object : Any
|
|
404
|
+
One or more objects to add.
|
|
405
|
+
filter : str, default: None.
|
|
406
|
+
Regular expression with the desired name or names to include in the plotter.
|
|
407
|
+
**plotting_options : dict, default: None
|
|
408
|
+
Keyword arguments. For allowable keyword arguments, see the
|
|
409
|
+
:meth:`Plotter.add_mesh <pyvista.Plotter.add_mesh>` method.
|
|
410
|
+
|
|
411
|
+
"""
|
|
412
|
+
pass
|
|
413
|
+
|
|
414
|
+
@abstractmethod
|
|
415
|
+
def plot(self, object: Any, filter: str = None, **plotting_options):
|
|
416
|
+
"""Plot a single object to the plotter.
|
|
417
|
+
|
|
418
|
+
Parameters
|
|
419
|
+
----------
|
|
420
|
+
object : Any
|
|
421
|
+
Object to add.
|
|
422
|
+
filter : str
|
|
423
|
+
Regular expression with the desired name or names to include in the plotter.
|
|
424
|
+
**plotting_options : dict, default: None
|
|
425
|
+
Keyword arguments. For allowable keyword arguments, see the
|
|
426
|
+
:meth:`Plotter.add_mesh <pyvista.Plotter.add_mesh>` method.
|
|
427
|
+
|
|
428
|
+
"""
|
|
429
|
+
pass
|
|
430
|
+
|
|
431
|
+
def picked_operation(self) -> None:
|
|
432
|
+
"""Perform an operation on the picked objects."""
|
|
433
|
+
pass
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
class PyVistaBackend(PyVistaBackendInterface):
|
|
437
|
+
"""Provides the generic plotter implementation for PyAnsys libraries.
|
|
438
|
+
|
|
439
|
+
This class accepts ``MeshObjectPlot``, ``pv.MultiBlock`` and ``pv.PolyData`` objects.
|
|
440
|
+
|
|
441
|
+
Parameters
|
|
442
|
+
----------
|
|
443
|
+
use_trame : bool, default: None
|
|
444
|
+
Whether to enable the use of `trame <https://kitware.github.io/trame/index.html>`_.
|
|
445
|
+
The default is ``None``, in which case the ``USE_TRAME`` global setting
|
|
446
|
+
is used.
|
|
447
|
+
allow_picking: bool, default: False
|
|
448
|
+
Whether to enable the picking capabilities in the PyVista plotter.
|
|
449
|
+
|
|
450
|
+
"""
|
|
451
|
+
|
|
452
|
+
def __init__(
|
|
453
|
+
self, use_trame: Optional[bool] = None, allow_picking: Optional[bool] = False
|
|
454
|
+
) -> None:
|
|
455
|
+
"""Initialize the generic plotter."""
|
|
456
|
+
super().__init__(use_trame, allow_picking)
|
|
457
|
+
|
|
458
|
+
def plot_iter(
|
|
459
|
+
self,
|
|
460
|
+
plotting_list: List[Any],
|
|
461
|
+
filter: str = None,
|
|
462
|
+
**plotting_options,
|
|
463
|
+
) -> None:
|
|
464
|
+
"""Plot the elements of an iterable of any type of object to the scene.
|
|
465
|
+
|
|
466
|
+
The types of objects supported are ``Body``, ``Component``, ``List[pv.PolyData]``,
|
|
467
|
+
``pv.MultiBlock``, and ``Sketch``.
|
|
468
|
+
|
|
469
|
+
Parameters
|
|
470
|
+
----------
|
|
471
|
+
plotting_list : List[Any]
|
|
472
|
+
List of objects to plot.
|
|
473
|
+
filter : str, default: None
|
|
474
|
+
Regular expression with the desired name or names to include in the plotter.
|
|
475
|
+
**plotting_options : dict, default: None
|
|
476
|
+
Keyword arguments. For allowable keyword arguments, see the
|
|
477
|
+
:meth:`Plotter.add_mesh <pyvista.Plotter.add_mesh>` method.
|
|
478
|
+
|
|
479
|
+
"""
|
|
480
|
+
for object in plotting_list:
|
|
481
|
+
self.plot(object, filter, **plotting_options)
|
|
482
|
+
|
|
483
|
+
def plot(self, object: Any, filter: str = None, **plotting_options):
|
|
484
|
+
"""Plot a ``pyansys`` or ``PyVista`` object to the plotter.
|
|
485
|
+
|
|
486
|
+
Parameters
|
|
487
|
+
----------
|
|
488
|
+
object : Any
|
|
489
|
+
Object to add.
|
|
490
|
+
filter : str
|
|
491
|
+
Regular expression with the desired name or names to include in the plotter.
|
|
492
|
+
**plotting_options : dict, default: None
|
|
493
|
+
Keyword arguments. For allowable keyword arguments, see the
|
|
494
|
+
:meth:`Plotter.add_mesh <pyvista.Plotter.add_mesh>` method.
|
|
495
|
+
|
|
496
|
+
"""
|
|
497
|
+
if hasattr(object, "__iter__"):
|
|
498
|
+
logger.debug("Plotting objects in list...")
|
|
499
|
+
self.pv_interface.plot_iter(object, filter, **plotting_options)
|
|
500
|
+
else:
|
|
501
|
+
self.pv_interface.plot(object, filter, **plotting_options)
|
|
502
|
+
|
|
503
|
+
def show(self):
|
|
504
|
+
"""Show the rendered scene."""
|
|
505
|
+
self.pv_interface.show()
|