Skip to content

Commit 36f5906

Browse files
authored
Merge branch 'main' into feat/add-design-points-and-modify-named-selection
2 parents 85b2733 + 00fdab0 commit 36f5906

File tree

13 files changed

+292
-132
lines changed

13 files changed

+292
-132
lines changed

pyproject.toml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ classifiers = [
2525
]
2626

2727
dependencies = [
28-
"ansys-api-geometry==0.2.1",
28+
"ansys-api-geometry==0.2.2",
2929
"beartype>=0.11.0",
3030
"google-api-python-client>=1.7.11",
3131
"googleapis-common-protos>=1.52.0",
@@ -41,6 +41,12 @@ dependencies = [
4141
]
4242

4343
[project.optional-dependencies]
44+
all = [
45+
"pyvista[trame]>=0.38.1",
46+
"docker>=6.0.1",
47+
"ansys-platform-instancemanagement>=1.0.3",
48+
]
49+
4450
tests = [
4551
"beartype==0.12.0",
4652
"google-api-python-client==2.78.0",
@@ -50,7 +56,7 @@ tests = [
5056
"numpy==1.24.2",
5157
"Pint==0.20.1",
5258
"protobuf==3.20.3",
53-
"pyvista==0.37.0",
59+
"pyvista[trame]==0.38.2",
5460
"scipy==1.10.0",
5561
"six==1.16.0",
5662
"ansys-platform-instancemanagement==1.0.3",
@@ -71,7 +77,7 @@ doc = [
7177
"notebook==6.5.2",
7278
"numpydoc==1.5.0",
7379
"panel==0.14.3",
74-
"pyvista==0.37.0",
80+
"pyvista[trame]==0.38.2",
7581
"Sphinx==5.1.1", # PR349 - Duplicated documentation entries...
7682
"sphinx-autoapi==2.0.1",
7783
"sphinx-autodoc-typehints==1.19.1", # PR349 - Duplicated documentation entries...

src/ansys/geometry/core/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,9 @@
2222
)
2323
from ansys.geometry.core.logger import LOG
2424
from ansys.geometry.core.modeler import Modeler
25+
26+
# Global config constants
27+
# ------------------------------------------------------------------------------
28+
29+
USE_TRAME = False
30+
"""Global constant for checking the use of trame or not."""

src/ansys/geometry/core/designer/body.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -517,8 +517,9 @@ def tessellate(self, merge: Optional[bool] = False) -> Union["PolyData", "MultiB
517517

518518
def plot(
519519
self,
520-
merge: Optional[bool] = False,
520+
merge: bool = False,
521521
screenshot: Optional[str] = None,
522+
use_trame: Optional[bool] = None,
522523
**plotting_options: Optional[dict],
523524
) -> None:
524525
"""Plot the body.
@@ -529,9 +530,12 @@ def plot(
529530
Whether to merge the body into a single mesh. By default, the
530531
number of triangles are preserved and only the topology is merged.
531532
When ``True``, the individual faces of the tessellation are merged.
532-
screenshot : str, default: None
533+
screenshot : str, optional
533534
Save a screenshot of the image being represented. The image is
534535
stored in the path provided as an argument.
536+
use_trame : bool, optional
537+
Enables/disables the usage of the trame web visualizer. Defaults to the
538+
global setting ``USE_TRAME``.
535539
**plotting_options : dict, default: None
536540
Keyword arguments. For allowable keyword arguments, see the
537541
:func:`pyvista.Plotter.add_mesh` method.
@@ -561,11 +565,13 @@ def plot(
561565
562566
"""
563567
# lazy import here to improve initial module load time
564-
from ansys.geometry.core.plotting import Plotter
565568

566-
pl = Plotter()
569+
from ansys.geometry.core.plotting import PlotterHelper
570+
571+
pl_helper = PlotterHelper(use_trame=use_trame)
572+
pl = pl_helper.init_plotter()
567573
pl.add_body(self, merge=merge, **plotting_options)
568-
pl.show(screenshot=screenshot)
574+
pl_helper.show_plotter(pl, screenshot=screenshot)
569575

570576
def __repr__(self) -> str:
571577
"""String representation of the body."""

src/ansys/geometry/core/designer/component.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ def tessellate(
717717
>>> from ansys.geometry.core import Modeler
718718
>>> from ansys.geometry.core.math import Point2D, Point3D, Plane
719719
>>> from ansys.geometry.core.misc import UNITS
720-
>>> from ansys.geometry.core.plotting.plotter import Plotter
720+
>>> from ansys.geometry.core.plotting import Plotter
721721
>>> modeler = Modeler("10.54.0.72", "50051")
722722
>>> sketch_1 = Sketch()
723723
>>> box = sketch_1.box(
@@ -778,6 +778,7 @@ def plot(
778778
merge_component: bool = False,
779779
merge_bodies: bool = False,
780780
screenshot: Optional[str] = None,
781+
use_trame: Optional[bool] = None,
781782
**plotting_options: Optional[dict],
782783
) -> None:
783784
"""Plot this component.
@@ -792,9 +793,12 @@ def plot(
792793
Whether to merge each body into a single dataset. When ``True``,
793794
all the faces of each individual body are effectively merged
794795
into a single dataset without separating faces.
795-
screenshot : str, default: None
796+
screenshot : str, optional
796797
Save a screenshot of the image being represented. The image is
797798
stored in the path provided as an argument.
799+
use_trame : bool, optional
800+
Enables/disables the usage of the trame web visualizer. Defaults to the
801+
global setting ``USE_TRAME``.
798802
**plotting_options : dict, default: None
799803
Keyword arguments. For allowable keyword arguments, see the
800804
:func:`pyvista.Plotter.add_mesh` method.
@@ -835,13 +839,15 @@ def plot(
835839
>>> mycomp.plot(pbr=True, metallic=1.0)
836840
837841
"""
838-
from ansys.geometry.core.plotting import Plotter
839842

840-
pl = Plotter()
843+
from ansys.geometry.core.plotting import PlotterHelper
844+
845+
pl_helper = PlotterHelper(use_trame=use_trame)
846+
pl = pl_helper.init_plotter()
841847
pl.add_component(
842848
self, merge_bodies=merge_bodies, merge_component=merge_component, **plotting_options
843849
)
844-
pl.show(screenshot=screenshot)
850+
pl_helper.show_plotter(pl, screenshot=screenshot)
845851

846852
def __repr__(self) -> str:
847853
"""String representation of the component."""

src/ansys/geometry/core/designer/design.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ def delete_named_selection(self, named_selection: Union[NamedSelection, str]) ->
266266
"""
267267
if isinstance(named_selection, str):
268268
removal_name = named_selection
269-
removal_id = self._named_selections.get(named_selection, None)
269+
removal = self._named_selections.get(named_selection, None)
270+
removal_id = removal.id if removal else None
270271
else:
271272
removal_name = named_selection.name
272273
removal_id = named_selection.id
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
"""Provides the PyGeometry ``plotting`` subpackage."""
22

3-
from ansys.geometry.core.plotting.plotter import Plotter
3+
from ansys.geometry.core.plotting.plotter import Plotter, PlotterHelper
4+
from ansys.geometry.core.plotting.trame_gui import _HAS_TRAME, TrameVisualizer

src/ansys/geometry/core/plotting/plotter.py

Lines changed: 95 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
from pyvista.plotting.tools import create_axes_marker
66

77
from ansys.geometry.core.designer import Body, Component
8+
from ansys.geometry.core.logger import LOG as logger
89
from ansys.geometry.core.math import Frame, Plane
10+
from ansys.geometry.core.plotting.trame_gui import _HAS_TRAME, TrameVisualizer
911
from ansys.geometry.core.plotting.widgets import (
1012
CameraPanDirection,
1113
DisplacementArrow,
@@ -18,50 +20,56 @@
1820

1921

2022
class Plotter:
21-
"""Provides for plotting sketches and bodies."""
23+
"""Provides for plotting sketches and bodies.
24+
25+
Parameters
26+
----------
27+
scene : ~pyvista.Plotter, default: None
28+
Scene instance for rendering the objects.
29+
color_opts : dict, default: None
30+
Dictionary containing the background and top colors.
31+
num_points : int, default: 100
32+
Number of points to use to render the shapes.
33+
enable_widgets: bool, default: True
34+
Enables/disables widget buttons in the plotter window.
35+
They must be disabled for trame viewer.
36+
"""
2237

2338
def __init__(
2439
self,
2540
scene: Optional[pv.Plotter] = None,
26-
background_opts: Optional[Dict] = None,
41+
color_opts: Optional[Dict] = None,
2742
num_points: int = 100,
43+
enable_widgets: bool = True,
2844
):
29-
"""Initializes the plotter.
45+
"""Initializes the plotter."""
3046

31-
Parameters
32-
----------
33-
scene : ~pyvista.Plotter, default: None
34-
Scene instance for rendering the objects.
35-
background_opts : dict, default: None
36-
Dictionary containing the background and top colors.
37-
num_points : int, default: 100
38-
Number of points to use to render the shapes.
39-
"""
4047
# Generate custom scene if ``None`` is provided
4148
if scene is None:
4249
scene = pv.Plotter()
4350

4451
# If required, use a white background with no gradient
45-
if not background_opts:
46-
background_opts = dict(color="white")
52+
if not color_opts:
53+
color_opts = dict(color="white")
4754

4855
# Create the scene
4956
self._scene = scene
5057
# Scene: assign the background
51-
self._scene.set_background(**background_opts)
58+
self._scene.set_background(**color_opts)
5259
view_box = self._scene.add_axes(line_width=5, color="black")
5360

5461
# Save the desired number of points
5562
self._num_points = num_points
5663

5764
# Create Plotter widgets
58-
self._widgets: List[PlotterWidget] = []
59-
self._widgets.append(Ruler(self._scene))
60-
[
61-
self._widgets.append(DisplacementArrow(self._scene, direction=dir))
62-
for dir in CameraPanDirection
63-
]
64-
[self._widgets.append(ViewButton(self._scene, direction=dir)) for dir in ViewDirection]
65+
if enable_widgets:
66+
self._widgets: List[PlotterWidget] = []
67+
self._widgets.append(Ruler(self._scene))
68+
[
69+
self._widgets.append(DisplacementArrow(self._scene, direction=dir))
70+
for dir in CameraPanDirection
71+
]
72+
[self._widgets.append(ViewButton(self._scene, direction=dir)) for dir in ViewDirection]
6573

6674
@property
6775
def scene(self) -> pv.Plotter:
@@ -322,3 +330,68 @@ def __set_add_mesh_defaults(self, plotting_options: Optional[Dict]) -> None:
322330
# This method should only be applied in 3D objects: bodies, components
323331
plotting_options.setdefault("smooth_shading", True)
324332
plotting_options.setdefault("color", "#D6F7D1")
333+
334+
335+
class PlotterHelper:
336+
"""This class simplifies the selection of Trame visualizer in plot()
337+
functions.
338+
339+
Parameters
340+
----------
341+
use_trame: bool, optional
342+
Enables/disables the usage of the trame web visualizer. Defaults to the
343+
global setting ``USE_TRAME``.
344+
"""
345+
346+
def __init__(self, use_trame: Optional[bool] = None) -> None:
347+
"""Initializes use_trame and saves current pv.OFF_SCREEN value."""
348+
# Check if the use of trame was requested
349+
if use_trame is None:
350+
import ansys.geometry.core as pygeom
351+
352+
use_trame = pygeom.USE_TRAME
353+
354+
self._use_trame = use_trame
355+
self._pv_off_screen_original = bool(pv.OFF_SCREEN)
356+
357+
def init_plotter(self):
358+
"""Initializes the plotter with or without trame visualizer.
359+
360+
Returns
361+
-------
362+
Plotter
363+
PyGeometry plotter initialized.
364+
"""
365+
if self._use_trame and _HAS_TRAME:
366+
# avoids GUI window popping up
367+
pv.OFF_SCREEN = True
368+
pl = Plotter(enable_widgets=False)
369+
elif self._use_trame and not _HAS_TRAME:
370+
warn_msg = (
371+
"'use_trame' is active but Trame dependencies are not installed."
372+
"Consider installing 'pyvista[trame]' to use this functionality."
373+
)
374+
logger.warning(warn_msg)
375+
pl = Plotter()
376+
else:
377+
pl = Plotter()
378+
return pl
379+
380+
def show_plotter(self, plotter, screenshot):
381+
"""Shows the plotter or starts Trame service.
382+
383+
Parameters
384+
----------
385+
plotter : Plotter
386+
PyGeometry plotter with the meshes added.
387+
screenshot : str, default: None
388+
Save a screenshot of the image being represented. The image is
389+
stored in the path provided as an argument.
390+
"""
391+
if self._use_trame and _HAS_TRAME:
392+
visualizer = TrameVisualizer()
393+
visualizer.set_scene(plotter)
394+
visualizer.show()
395+
else:
396+
plotter.show(screenshot=screenshot)
397+
pv.OFF_SCREEN = self._pv_off_screen_original
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""Module for the trame visualizer."""
2+
try:
3+
from pyvista.trame.ui import plotter_ui
4+
from trame.app import get_server
5+
from trame.ui.vuetify import SinglePageLayout
6+
7+
_HAS_TRAME = True
8+
9+
except ModuleNotFoundError: # pragma: no cover
10+
_HAS_TRAME = False
11+
12+
13+
class TrameVisualizer:
14+
"""Trame visualizer class. It will define how the trame view layout will be."""
15+
16+
def __init__(self) -> None:
17+
"""Inits server and server related variables."""
18+
if not _HAS_TRAME: # pragma: no cover
19+
raise ModuleNotFoundError(
20+
"The package 'pyvista[trame]' is required to use this function."
21+
)
22+
23+
self.server = get_server()
24+
self.state, self.ctrl = self.server.state, self.server.controller
25+
26+
def set_scene(self, plotter):
27+
"""Sets the trame layout view and the mesh to show
28+
through the pyvista plotter.
29+
30+
Parameters
31+
----------
32+
plotter : pv.Plotter
33+
PyVista plotter with the mesh rendered.
34+
"""
35+
self.state.trame__title = "PyGeometry Viewer"
36+
37+
with SinglePageLayout(self.server) as layout:
38+
layout.icon.click = self.ctrl.view_reset_camera
39+
layout.title.set_text("PyGeometry")
40+
41+
with layout.content:
42+
# Use PyVista UI template for Plotters
43+
view = plotter_ui(plotter.scene)
44+
self.ctrl.view_update = view.update
45+
46+
# hide footer with trame watermark
47+
layout.footer.hide()
48+
49+
def show(self):
50+
"""Starts the server and shows the mesh."""
51+
self.server.start()

0 commit comments

Comments
 (0)