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.
Files changed (42) hide show
  1. ansys/tools/visualization_interface/__init__.py +39 -0
  2. ansys/tools/visualization_interface/backends/__init__.py +22 -0
  3. ansys/tools/visualization_interface/backends/_base.py +45 -0
  4. ansys/tools/visualization_interface/backends/pyvista/__init__.py +26 -0
  5. ansys/tools/visualization_interface/backends/pyvista/pyvista.py +505 -0
  6. ansys/tools/visualization_interface/backends/pyvista/pyvista_interface.py +358 -0
  7. ansys/tools/visualization_interface/backends/pyvista/trame_local.py +72 -0
  8. ansys/tools/visualization_interface/backends/pyvista/trame_remote.py +63 -0
  9. ansys/tools/visualization_interface/backends/pyvista/trame_service.py +125 -0
  10. ansys/tools/visualization_interface/backends/pyvista/widgets/__init__.py +25 -0
  11. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+xy.png +0 -0
  12. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+xz.png +0 -0
  13. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/+yz.png +0 -0
  14. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-xy.png +0 -0
  15. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-xz.png +0 -0
  16. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/-yz.png +0 -0
  17. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/designpoint.png +0 -0
  18. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/downarrow.png +0 -0
  19. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/isometric.png +0 -0
  20. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/measurement.png +0 -0
  21. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/ruler.png +0 -0
  22. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upxarrow.png +0 -0
  23. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upyarrow.png +0 -0
  24. ansys/tools/visualization_interface/backends/pyvista/widgets/_images/upzarrow.png +0 -0
  25. ansys/tools/visualization_interface/backends/pyvista/widgets/button.py +80 -0
  26. ansys/tools/visualization_interface/backends/pyvista/widgets/displace_arrows.py +95 -0
  27. ansys/tools/visualization_interface/backends/pyvista/widgets/measure.py +90 -0
  28. ansys/tools/visualization_interface/backends/pyvista/widgets/ruler.py +93 -0
  29. ansys/tools/visualization_interface/backends/pyvista/widgets/view_button.py +91 -0
  30. ansys/tools/visualization_interface/backends/pyvista/widgets/widget.py +63 -0
  31. ansys/tools/visualization_interface/plotter.py +61 -0
  32. ansys/tools/visualization_interface/types/__init__.py +22 -0
  33. ansys/tools/visualization_interface/types/edge_plot.py +112 -0
  34. ansys/tools/visualization_interface/types/mesh_object_plot.py +175 -0
  35. ansys/tools/visualization_interface/utils/__init__.py +22 -0
  36. ansys/tools/visualization_interface/utils/clip_plane.py +96 -0
  37. ansys/tools/visualization_interface/utils/color.py +40 -0
  38. ansys/tools/visualization_interface/utils/logger.py +118 -0
  39. ansys_tools_visualization_interface-0.1.0.dist-info/LICENSE +21 -0
  40. ansys_tools_visualization_interface-0.1.0.dist-info/METADATA +126 -0
  41. ansys_tools_visualization_interface-0.1.0.dist-info/RECORD +42 -0
  42. 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()