Skip to content

Commit 7480408

Browse files
Merge branch 'main' into feat/customization-api
2 parents 4205584 + 5cffcfa commit 7480408

7 files changed

Lines changed: 122 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Feat: Add parallel projection button

src/ansys/tools/visualization_interface/backends/pyvista/pyvista.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
from ansys.tools.visualization_interface.backends.pyvista.widgets.mesh_slider import (
4848
MeshSliderWidget,
4949
)
50+
from ansys.tools.visualization_interface.backends.pyvista.widgets.parallel_projection import ParallelProjectionButton
5051
from ansys.tools.visualization_interface.backends.pyvista.widgets.pick_rotation_center import PickRotCenterButton
5152
from ansys.tools.visualization_interface.backends.pyvista.widgets.ruler import Ruler
5253
from ansys.tools.visualization_interface.backends.pyvista.widgets.screenshot import ScreenshotButton
@@ -220,6 +221,7 @@ def enable_widgets(self, dark_mode: bool = False) -> None:
220221
self._widgets.append(HideButton(self, dark_mode))
221222
self._widgets.append(PickRotCenterButton(self, dark_mode))
222223
self._widgets.append(DarkModeButton(self, dark_mode))
224+
self._widgets.append(ParallelProjectionButton(self, dark_mode))
223225
# Add dynamic tree menu widget (always available)
224226
tree_menu = DynamicTreeMenuWidget(self, dark_mode=dark_mode)
225227
self._widgets.append(tree_menu)

src/ansys/tools/visualization_interface/backends/pyvista/pyvista_interface.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,14 @@ def view_zy(self) -> None:
157157
"""View the scene from the ZY plane."""
158158
self.scene.view_zy()
159159

160+
def enable_parallel_projection(self) -> None:
161+
"""Enable parallel projection for the camera."""
162+
self.scene.camera.enable_parallel_projection()
163+
164+
def disable_parallel_projection(self) -> None:
165+
"""Disable parallel projection for the camera."""
166+
self.scene.camera.disable_parallel_projection()
167+
160168
def clip(
161169
self, mesh: Union[pv.PolyData, pv.MultiBlock, pv.UnstructuredGrid], plane: ClipPlane
162170
) -> Union[pv.PolyData, pv.MultiBlock]:

src/ansys/tools/visualization_interface/backends/pyvista/trame_local.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def __init__(self) -> None:
5959
self.state.measure_active = False
6060
self.state.mesh_slider_active = False
6161
self.state.ruler_active = False
62+
self.state.parallel_projection = False
6263

6364
# Store reference to plotter for controller methods
6465
self.plotter = None
@@ -197,6 +198,19 @@ def toggle_dark_mode():
197198
except Exception as e:
198199
print(f"Error toggling dark mode: {e}")
199200

201+
@self.ctrl.set("toggle_parallel_projection")
202+
def toggle_parallel_projection():
203+
"""Toggle parallel projection for camera."""
204+
try:
205+
self.state.parallel_projection = not self.state.parallel_projection
206+
if self.state.parallel_projection:
207+
self.plotter.scene.camera.enable_parallel_projection()
208+
else:
209+
self.plotter.scene.camera.disable_parallel_projection()
210+
self.ctrl.view_update()
211+
except Exception as e:
212+
print(f"Error toggling parallel projection: {e}")
213+
200214
@self.ctrl.set("displace_camera_x_up")
201215
def displace_camera_x_up():
202216
"""Move camera in X+ direction."""
@@ -495,6 +509,12 @@ def view_isometric():
495509
with vue.VListItemContent():
496510
vue.VListItemTitle("Dark Mode")
497511

512+
with vue.VListItem(click=self.ctrl.toggle_parallel_projection):
513+
with vue.VListItemIcon():
514+
vue.VIcon("mdi-projector")
515+
with vue.VListItemContent():
516+
vue.VListItemTitle("Parallel Projection")
517+
498518
# Hide footer with trame watermark
499519
layout.footer.hide()
500520

3.81 KB
Loading
4.86 KB
Loading
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Copyright (C) 2024 - 2026 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 the parallel projection button widget."""
23+
from pathlib import Path
24+
from typing import TYPE_CHECKING
25+
26+
from vtk import vtkActor, vtkButtonWidget, vtkPNGReader
27+
28+
from ansys.tools.visualization_interface.backends.pyvista.widgets.widget import PlotterWidget
29+
30+
if TYPE_CHECKING:
31+
from ansys.tools.visualization_interface.backends.pyvista.pyvista import Plotter
32+
33+
34+
class ParallelProjectionButton(PlotterWidget):
35+
"""Toggle parallel projection for the camera.
36+
37+
Parameters
38+
----------
39+
plotter : Plotter
40+
Plotter to add the widget to.
41+
dark_mode : bool, optional
42+
Whether dark mode is active.
43+
44+
"""
45+
46+
def __init__(self, plotter: "Plotter", dark_mode: bool = False) -> None:
47+
"""Initialize the button."""
48+
super().__init__(plotter._pl.scene)
49+
self._dark_mode = dark_mode
50+
self._actor: vtkActor = None
51+
self._plotter = plotter
52+
self._button: vtkButtonWidget = self._plotter._pl.scene.add_checkbox_button_widget(
53+
self.callback, position=(5, 50), size=30, border_size=3
54+
)
55+
self.update()
56+
57+
def callback(self, state: bool) -> None:
58+
"""Toggle parallel projection.
59+
60+
Parameters
61+
----------
62+
state : bool
63+
Button state from PyVista.
64+
65+
"""
66+
if state:
67+
self._plotter.scene.camera.enable_parallel_projection()
68+
else:
69+
self._plotter.scene.camera.disable_parallel_projection()
70+
71+
def update(self) -> None:
72+
"""Update the button appearance."""
73+
if self._dark_mode:
74+
is_inv = "_inv"
75+
else:
76+
is_inv = ""
77+
78+
show_vr = self._button.GetRepresentation()
79+
icon_file = Path(Path(__file__).parent / "_images" / f"parallel_projection{is_inv}.png")
80+
show_r_on = vtkPNGReader()
81+
show_r_on.SetFileName(icon_file)
82+
show_r_on.Update()
83+
image_on = show_r_on.GetOutput()
84+
85+
show_r_off = vtkPNGReader()
86+
show_r_off.SetFileName(icon_file)
87+
show_r_off.Update()
88+
image_off = show_r_off.GetOutput()
89+
90+
show_vr.SetButtonTexture(0, image_off)
91+
show_vr.SetButtonTexture(1, image_on)

0 commit comments

Comments
 (0)