Skip to content

Commit bb1d713

Browse files
feat: Add optional tree structure to MeshObjectPlot class
1 parent 5339a2f commit bb1d713

File tree

4 files changed

+223
-2
lines changed

4 files changed

+223
-2
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright (C) 2024 - 2025 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+
"""
24+
.. _ref_plain_usage:
25+
26+
=============================
27+
MeshObjectPlot tree structure
28+
=============================
29+
30+
This example shows how to add a tree structure of MeshObjectPlot to the plotter.
31+
"""
32+
import pyvista as pv
33+
from ansys.tools.visualization_interface import Plotter
34+
35+
class CustomObject:
36+
def __init__(self):
37+
self.name = "CustomObject"
38+
self.mesh = pv.Cube(center=(1, 1, 0))
39+
40+
def get_mesh(self):
41+
return self.mesh
42+
43+
def name(self):
44+
return self.name
45+
46+
47+
48+
# Create a custom objects
49+
custom_cube = CustomObject()
50+
custom_cube.name = "CustomCube"
51+
52+
custom_sphere = CustomObject()
53+
custom_sphere.mesh = pv.Sphere(center=(0, 0, 5))
54+
custom_sphere.name = "CustomSphere"
55+
56+
custom_sphere1 = CustomObject()
57+
custom_sphere1.mesh = pv.Sphere(center=(5, 0, 5))
58+
custom_sphere1.name = "CustomSphere"
59+
60+
from ansys.tools.visualization_interface import MeshObjectPlot
61+
62+
# Create an instance
63+
mesh_object_cube = MeshObjectPlot(custom_cube, custom_cube.get_mesh())
64+
mesh_object_sphere = MeshObjectPlot(custom_sphere, custom_sphere.get_mesh())
65+
mesh_object_sphere1 = MeshObjectPlot(custom_sphere1, custom_sphere1.get_mesh())
66+
67+
mesh_object_cube.add_child(mesh_object_sphere)
68+
mesh_object_sphere.add_child(mesh_object_sphere1)
69+
70+
pl = Plotter()
71+
pl.plot(mesh_object_cube, plot_children=True)
72+
73+
74+
pl.backend._pl.hide_children(mesh_object_cube)
75+
pl.show()

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

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,15 @@ def clip(
186186
return mesh.clip(normal=[elem for elem in plane.normal],
187187
origin=plane.origin)
188188

189-
def plot_meshobject(self, custom_object: MeshObjectPlot, **plotting_options):
189+
def plot_meshobject(self, custom_object: MeshObjectPlot, plot_children: bool = True, **plotting_options):
190190
"""Plot a generic ``MeshObjectPlot`` object to the scene.
191191
192192
Parameters
193193
----------
194194
plottable_object : MeshObjectPlot
195195
Object to add to the scene.
196+
plot_children : bool, default: True
197+
Whether to plot the children of the object.
196198
**plotting_options : dict, default: None
197199
Keyword arguments. For allowable keyword arguments, see the
198200
:meth:`Plotter.add_mesh <pyvista.Plotter.add_mesh>` method.
@@ -205,6 +207,11 @@ def plot_meshobject(self, custom_object: MeshObjectPlot, **plotting_options):
205207
actor = self.scene.add_mesh(dataset, **plotting_options)
206208
custom_object.actor = actor
207209
self._object_to_actors_map[actor] = custom_object
210+
211+
if plot_children:
212+
for child in custom_object._children:
213+
self.plot_meshobject(child, plot_children=plot_children, **plotting_options)
214+
208215
return actor.name
209216

210217
def plot_edges(self, custom_object: MeshObjectPlot, **plotting_options) -> None:
@@ -242,10 +249,40 @@ def plot_edges(self, custom_object: MeshObjectPlot, **plotting_options) -> None:
242249
else:
243250
logger.warning("The object does not have edges.")
244251

252+
253+
def hide_children(self, custom_object: MeshObjectPlot) -> None:
254+
"""Hide all the children of a given ``MeshObjectPlot`` object.
255+
256+
Parameters
257+
----------
258+
custom_object : MeshObjectPlot
259+
Custom object whose children will be hidden.
260+
261+
"""
262+
for child in custom_object._children:
263+
if child.actor:
264+
child.actor.SetVisibility(False)
265+
self.hide_children(child)
266+
267+
def show_children(self, custom_object: MeshObjectPlot) -> None:
268+
"""Show all the children of a given ``MeshObjectPlot`` object.
269+
270+
Parameters
271+
----------
272+
custom_object : MeshObjectPlot
273+
Custom object whose children will be shown.
274+
275+
"""
276+
for child in custom_object._children:
277+
if child.actor:
278+
child.actor.SetVisibility(True)
279+
self.show_children(child)
280+
245281
def plot(
246282
self,
247283
plottable_object: Union[pv.PolyData, pv.MultiBlock, MeshObjectPlot, pv.UnstructuredGrid],
248284
name_filter: str = None,
285+
plot_children: bool = False,
249286
**plotting_options,
250287
) -> None:
251288
"""Plot any type of object to the scene.
@@ -287,7 +324,7 @@ def plot(
287324
else:
288325
self.scene.add_composite(plottable_object, **plotting_options)
289326
elif isinstance(plottable_object, MeshObjectPlot):
290-
self.plot_meshobject(plottable_object, **plotting_options)
327+
self.plot_meshobject(plottable_object, plot_children=plot_children, **plotting_options)
291328
else:
292329
logger.warning("The object type is not supported. ")
293330

src/ansys/tools/visualization_interface/types/mesh_object_plot.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ def __init__(
4040
mesh: Union[pv.PolyData, pv.MultiBlock, "Mesh3d"],
4141
actor: pv.Actor = None,
4242
edges: List[EdgePlot] = None,
43+
children: List["MeshObjectPlot"] = None,
44+
parent: "MeshObjectPlot" = None,
4345
) -> None:
4446
"""Relates a custom object with a mesh provided by the consumer library.
4547
@@ -63,6 +65,51 @@ def __init__(
6365
self._mesh = mesh
6466
self._actor = actor
6567
self._edges = edges
68+
self._children: List["MeshObjectPlot"] = children if children is not None else []
69+
self._parent: "MeshObjectPlot" = parent
70+
71+
def add_child(self, child: "MeshObjectPlot"):
72+
"""Set a child MeshObjectPlot to the current object.
73+
74+
This method is used to set a child MeshObjectPlot to the current object.
75+
It is useful when the custom object has a hierarchical structure, and
76+
the consumer library wants to relate the child objects with their meshes.
77+
78+
Parameters
79+
----------
80+
child : MeshObjectPlot
81+
Child MeshObjectPlot to be set.
82+
83+
"""
84+
child.parent = self
85+
self._children.append(child)
86+
87+
@property
88+
def parent(self) -> "MeshObjectPlot":
89+
"""Get the parent MeshObjectPlot of the current object.
90+
91+
This method is used to set a parent MeshObjectPlot to the current object.
92+
It is useful when the custom object has a hierarchical structure, and
93+
the consumer library wants to relate the parent objects with their meshes.
94+
95+
Parameters
96+
----------
97+
parent : MeshObjectPlot
98+
Parent MeshObjectPlot to be set.
99+
100+
"""
101+
return self._parent
102+
103+
@parent.setter
104+
def parent(self, parent: "MeshObjectPlot"):
105+
"""Set the parent MeshObjectPlot of the current object.
106+
107+
Parameters
108+
----------
109+
parent : MeshObjectPlot
110+
Parent MeshObjectPlot to be set.
111+
"""
112+
self._parent = parent
66113

67114
@property
68115
def mesh(self) -> Union[pv.PolyData, pv.MultiBlock, "Mesh3d"]:

tests/test_meshobject.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Copyright (C) 2024 - 2025 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+
"""Test module for the generic plotter."""
23+
import os
24+
25+
import pyvista as pv
26+
27+
from ansys.tools.visualization_interface import MeshObjectPlot
28+
29+
IN_GITHUB_ACTIONS = os.getenv("IN_GITHUB_ACTIONS") == "true"
30+
31+
32+
class CustomTestClass:
33+
"""Mock custom class for testing MeshObjectPlot."""
34+
35+
def __init__(self, name) -> None:
36+
"""Mock init."""
37+
self.name = name
38+
39+
40+
41+
def test_mesh_object_plot_tree():
42+
"""Test that basic parent-child relationships work."""
43+
parent_mesh = pv.Sphere()
44+
child_mesh = pv.Cube()
45+
46+
parent_obj = MeshObjectPlot(CustomTestClass("parent"), parent_mesh)
47+
child_obj = MeshObjectPlot(CustomTestClass("child"), child_mesh)
48+
49+
parent_obj.add_child(child_obj)
50+
51+
52+
# assert that the child's parent is set correctly
53+
assert child_obj.parent == parent_obj
54+
55+
# assert that the parent's children contain the child
56+
assert child_obj in parent_obj._children
57+
58+
# assert that the parent's parent is None
59+
assert parent_obj.parent is None
60+
61+
# assert that the child has no children
62+
assert len(child_obj._children) == 0

0 commit comments

Comments
 (0)