Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor silhouette from add_mesh #1689

Merged
93 changes: 70 additions & 23 deletions pyvista/plotting/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -1875,31 +1875,11 @@ def add_mesh(self, mesh, color=None, style=None, scalars=None,

##### Plot a single PyVista mesh #####

silhouette_params = self._theme.silhouette.to_dict()
if isinstance(silhouette, dict):
silhouette_params.update(silhouette)
silhouette = True
if silhouette:
if not isinstance(mesh, pyvista.PolyData):
raise TypeError(f"Expected type is `PolyData` but {type(mesh)} was given.")
if isinstance(silhouette_params["decimate"], float):
silhouette_mesh = mesh.decimate(silhouette_params["decimate"])
else:
silhouette_mesh = mesh
alg = _vtk.vtkPolyDataSilhouette()
alg.SetInputData(silhouette_mesh)
alg.SetCamera(self.renderer.camera)
if silhouette_params["feature_angle"] is not None:
alg.SetEnableFeatureAngle(True)
alg.SetFeatureAngle(silhouette_params["feature_angle"])
if isinstance(silhouette, dict):
self.add_silhouette(mesh, silhouette)
else:
alg.SetEnableFeatureAngle(False)
mapper = make_mapper(_vtk.vtkDataSetMapper)
mapper.SetInputConnection(alg.GetOutputPort())
_, prop = self.add_actor(mapper)
prop.SetColor(parse_color(silhouette_params["color"]))
prop.SetOpacity(silhouette_params["opacity"])
prop.SetLineWidth(silhouette_params["line_width"])
self.add_silhouette(mesh)

# Compute surface normals if using smooth shading
if smooth_shading:
Expand Down Expand Up @@ -2694,6 +2674,73 @@ def add_volume(self, volume, scalars=None, clim=None, resolution=None,

return actor

def add_silhouette(self, mesh, params=None):
"""Add a silhouette of a PyVista/VTK mesh or dataset that PyVista can wrap to the scene.

A silhouette can also be generated directly in
:func:`pyvista.BasePlotter.add_mesh`. See also :ref:`silhouette_example`.

Parameters
----------
mesh : pyvista.PolyData

MatthewFlamm marked this conversation as resolved.
Show resolved Hide resolved
params : dict, optional
* If not supplied, the default theme values will be used.
* ``color``: ``str`` or 3-item ``list``, color of the silhouette
* ``line_width``: ``float``, edge width
* ``opacity``: ``float`` between 0 and 1, edge transparency
* ``feature_angle``: If a ``float``, display sharp edges
exceeding that angle in degrees.
* ``decimate``: ``float`` between 0 and 1, level of decimation

Returns
-------
vtk.vtkActor
VTK actor of the silhouette.

Examples
--------
>>> import pyvista
>>> from pyvista import examples
>>> bunny = examples.download_bunny()
>>> plotter = pyvista.Plotter()
>>> _ = plotter.add_mesh(bunny, color='tan')
>>> _ = plotter.add_silhouette(bunny,
... params={'color': 'red', 'line_width': 8.0})
>>> plotter.view_xy()
>>> plotter.show()

"""
silhouette_params = self._theme.silhouette.to_dict()
if params:
silhouette_params.update(params)

if not is_pyvista_dataset(mesh):
mesh = wrap(mesh)
if not isinstance(mesh, pyvista.PolyData):
raise TypeError(f"Expected type is `PolyData` but {type(mesh)} was given.")

if isinstance(silhouette_params["decimate"], float):
silhouette_mesh = mesh.decimate(silhouette_params["decimate"])
else:
silhouette_mesh = mesh
alg = _vtk.vtkPolyDataSilhouette()
alg.SetInputData(silhouette_mesh)
alg.SetCamera(self.renderer.camera)
if silhouette_params["feature_angle"] is not None:
alg.SetEnableFeatureAngle(True)
alg.SetFeatureAngle(silhouette_params["feature_angle"])
else:
alg.SetEnableFeatureAngle(False)
mapper = make_mapper(_vtk.vtkDataSetMapper)
mapper.SetInputConnection(alg.GetOutputPort())
actor, prop = self.add_actor(mapper)
prop.SetColor(parse_color(silhouette_params["color"]))
prop.SetOpacity(silhouette_params["opacity"])
prop.SetLineWidth(silhouette_params["line_width"])

return actor

def update_scalar_bar_range(self, clim, name=None):
"""Update the value range of the active or named scalar bar.

Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions tests/plotting/test_plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,25 @@ def test_plot_silhouette(tri_cylinder):
plotter.show(before_close_callback=verify_cache_image)


def test_plot_silhouette_method(tri_cylinder):
plotter = pyvista.Plotter()

plotter.add_mesh(tri_cylinder)
actors = list(plotter.renderer.GetActors())
assert len(actors) == 1 # cylinder

plotter.add_silhouette(tri_cylinder)
actors = list(plotter.renderer.GetActors())
assert len(actors) == 2 # cylinder + silhouette

actor = actors[1] # get silhouette actor
props = actor.GetProperty()
assert props.GetColor() == pyvista.parse_color(pyvista.global_theme.silhouette.color)
assert props.GetOpacity() == pyvista.global_theme.silhouette.opacity
assert props.GetLineWidth() == pyvista.global_theme.silhouette.line_width
plotter.show(before_close_callback=verify_cache_image)


def test_plot_silhouette_options(tri_cylinder):
# cover other properties
plotter = pyvista.Plotter()
Expand Down