456 lines
13 KiB
Python
456 lines
13 KiB
Python
"""Wrap :vtk:`vtkActor` module."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
import numpy as np
|
|
|
|
import pyvista
|
|
from pyvista._deprecate_positional_args import _deprecate_positional_args
|
|
|
|
from . import _vtk
|
|
from ._property import Property
|
|
from .prop3d import Prop3D
|
|
|
|
if TYPE_CHECKING:
|
|
from typing_extensions import Self
|
|
|
|
from .mapper import _BaseMapper
|
|
|
|
|
|
class Actor(Prop3D, _vtk.vtkActor):
|
|
"""Wrap :vtk:`vtkActor`.
|
|
|
|
This class represents the geometry & properties in a rendered
|
|
scene. Normally, a :class:`pyvista.Actor` is constructed from
|
|
:func:`pyvista.Plotter.add_mesh`, but there may be times when it is more
|
|
convenient to construct an actor directly from a
|
|
:class:`pyvista.DataSetMapper`.
|
|
|
|
Parameters
|
|
----------
|
|
mapper : pyvista.DataSetMapper, optional
|
|
DataSetMapper.
|
|
|
|
prop : pyvista.Property, optional
|
|
Property of the actor.
|
|
|
|
name : str, optional
|
|
The name of this actor used when tracking on a plotter.
|
|
|
|
Examples
|
|
--------
|
|
Create an actor without using :class:`pyvista.Plotter`.
|
|
|
|
>>> import pyvista as pv
|
|
>>> mesh = pv.Sphere()
|
|
>>> mapper = pv.DataSetMapper(mesh)
|
|
>>> actor = pv.Actor(mapper=mapper)
|
|
>>> actor
|
|
Actor (...)
|
|
Center: (0.0, 0.0, 0.0)
|
|
Pickable: True
|
|
Position: (0.0, 0.0, 0.0)
|
|
Scale: (1.0, 1.0, 1.0)
|
|
Visible: True
|
|
X Bounds -4.993E-01, 4.993E-01
|
|
Y Bounds -4.965E-01, 4.965E-01
|
|
Z Bounds -5.000E-01, 5.000E-01
|
|
User matrix: Identity
|
|
Has mapper: True
|
|
...
|
|
|
|
Change the actor properties and plot the actor.
|
|
|
|
>>> import pyvista as pv
|
|
>>> mesh = pv.Sphere()
|
|
>>> mapper = pv.DataSetMapper(mesh)
|
|
>>> actor = pv.Actor(mapper=mapper)
|
|
>>> actor.prop.color = 'blue'
|
|
>>> actor.plot()
|
|
|
|
Create an actor using the :class:`pyvista.Plotter` and then change the
|
|
visibility of the actor.
|
|
|
|
>>> import pyvista as pv
|
|
>>> pl = pv.Plotter()
|
|
>>> mesh = pv.Sphere()
|
|
>>> actor = pl.add_mesh(mesh)
|
|
>>> actor.visibility = False
|
|
>>> actor.visibility
|
|
False
|
|
|
|
"""
|
|
|
|
def __init__(self, mapper=None, prop=None, name=None) -> None:
|
|
"""Initialize actor."""
|
|
super().__init__()
|
|
if mapper is not None:
|
|
self.mapper = mapper
|
|
if prop is None:
|
|
self.prop = Property()
|
|
else:
|
|
self.prop = prop
|
|
self._name = name
|
|
|
|
@property
|
|
def mapper(self) -> _BaseMapper: # numpydoc ignore=RT01
|
|
"""Return or set the mapper of the actor.
|
|
|
|
Examples
|
|
--------
|
|
Create an actor and assign a mapper to it.
|
|
|
|
>>> import pyvista as pv
|
|
>>> dataset = pv.Sphere()
|
|
>>> actor = pv.Actor()
|
|
>>> actor.mapper = pv.DataSetMapper(dataset)
|
|
>>> actor.mapper
|
|
DataSetMapper (...)
|
|
Scalar visibility: True
|
|
Scalar range: (0.0, 1.0)
|
|
Interpolate before mapping: True
|
|
Scalar map mode: default
|
|
Color mode: direct
|
|
<BLANKLINE>
|
|
Attached dataset:
|
|
PolyData (...)
|
|
N Cells: 1680
|
|
N Points: 842
|
|
N Strips: 0
|
|
X Bounds: -4.993e-01, 4.993e-01
|
|
Y Bounds: -4.965e-01, 4.965e-01
|
|
Z Bounds: -5.000e-01, 5.000e-01
|
|
N Arrays: 1
|
|
|
|
"""
|
|
return self.GetMapper() # type: ignore[return-value]
|
|
|
|
@mapper.setter
|
|
def mapper(self, obj) -> None:
|
|
self.SetMapper(obj)
|
|
|
|
@property
|
|
def prop(self): # numpydoc ignore=RT01
|
|
"""Return or set the property of this actor.
|
|
|
|
Examples
|
|
--------
|
|
Modify the properties of an actor after adding a dataset to the plotter.
|
|
|
|
>>> import pyvista as pv
|
|
>>> pl = pv.Plotter()
|
|
>>> actor = pl.add_mesh(pv.Sphere())
|
|
>>> prop = actor.prop
|
|
>>> prop.diffuse = 0.6
|
|
>>> pl.show()
|
|
|
|
"""
|
|
return self.GetProperty()
|
|
|
|
@prop.setter
|
|
def prop(self, obj: Property) -> None:
|
|
self.SetProperty(obj)
|
|
|
|
@property
|
|
def texture(self): # numpydoc ignore=RT01
|
|
"""Return or set the actor texture.
|
|
|
|
Notes
|
|
-----
|
|
The mapper dataset must have texture coordinates for the texture to be
|
|
used.
|
|
|
|
Examples
|
|
--------
|
|
Create an actor and add a texture to it. Note how the
|
|
:class:`pyvista.PolyData` has texture coordinates by default.
|
|
|
|
>>> import pyvista as pv
|
|
>>> from pyvista import examples
|
|
>>> plane = pv.Plane()
|
|
>>> plane.active_texture_coordinates is not None
|
|
True
|
|
>>> pl = pv.Plotter()
|
|
>>> actor = pl.add_mesh(plane)
|
|
>>> actor.texture = examples.download_masonry_texture()
|
|
>>> actor.texture
|
|
Texture (...)
|
|
Components: 3
|
|
Cube Map: False
|
|
Dimensions: 256, 256
|
|
|
|
"""
|
|
return self.GetTexture()
|
|
|
|
@texture.setter
|
|
def texture(self, obj) -> None:
|
|
self.SetTexture(obj)
|
|
|
|
@property
|
|
def memory_address(self): # numpydoc ignore=RT01
|
|
"""Return the memory address of this actor."""
|
|
return self.GetAddressAsString('')
|
|
|
|
@property
|
|
def pickable(self) -> bool: # numpydoc ignore=RT01
|
|
"""Return or set actor pickability.
|
|
|
|
Examples
|
|
--------
|
|
Create an actor using the :class:`pyvista.Plotter` and then make the
|
|
actor unpickable.
|
|
|
|
>>> import pyvista as pv
|
|
>>> pl = pv.Plotter()
|
|
>>> actor = pl.add_mesh(pv.Sphere())
|
|
>>> actor.pickable = False
|
|
>>> actor.pickable
|
|
False
|
|
|
|
"""
|
|
return bool(self.GetPickable())
|
|
|
|
@pickable.setter
|
|
def pickable(self, value) -> None:
|
|
self.SetPickable(value)
|
|
|
|
@property
|
|
def visibility(self) -> bool: # numpydoc ignore=RT01
|
|
"""Return or set actor visibility.
|
|
|
|
See Also
|
|
--------
|
|
use_bounds
|
|
pyvista.Plotter.compute_bounds
|
|
|
|
Examples
|
|
--------
|
|
Create an actor using the :class:`pyvista.Plotter` and then change the
|
|
visibility of the actor.
|
|
|
|
>>> import pyvista as pv
|
|
>>> from pyvista import examples
|
|
>>> mesh = examples.load_airplane()
|
|
>>> pl = pv.Plotter()
|
|
>>> actor = pl.add_mesh(mesh)
|
|
>>> pl.bounds
|
|
BoundsTuple(x_min = 139.06100463867188,
|
|
x_max = 1654.9300537109375,
|
|
y_min = 32.09429931640625,
|
|
y_max = 1319.949951171875,
|
|
z_min = -17.741199493408203,
|
|
z_max = 282.1300048828125)
|
|
|
|
>>> actor.visibility = False
|
|
>>> pl.bounds
|
|
BoundsTuple(x_min = -1.0,
|
|
x_max = 1.0,
|
|
y_min = -1.0,
|
|
y_max = 1.0,
|
|
z_min = -1.0,
|
|
z_max = 1.0)
|
|
|
|
"""
|
|
return bool(self.GetVisibility())
|
|
|
|
@visibility.setter
|
|
def visibility(self, value: bool) -> None:
|
|
self.SetVisibility(value)
|
|
|
|
@property
|
|
def use_bounds(self) -> bool: # numpydoc ignore=RT01
|
|
"""Return or set the use of actor's bounds.
|
|
|
|
.. versionadded:: 0.45
|
|
|
|
See Also
|
|
--------
|
|
visibility
|
|
pyvista.Plotter.compute_bounds
|
|
|
|
Examples
|
|
--------
|
|
Create an actor using the :class:`pyvista.Plotter` and then change the
|
|
use of bounds for the actor.
|
|
|
|
>>> import pyvista as pv
|
|
>>> from pyvista import examples
|
|
>>> mesh = examples.load_airplane()
|
|
>>> pl = pv.Plotter()
|
|
>>> actor = pl.add_mesh(mesh)
|
|
>>> pl.bounds
|
|
BoundsTuple(x_min = 139.06100463867188,
|
|
x_max = 1654.9300537109375,
|
|
y_min = 32.09429931640625,
|
|
y_max = 1319.949951171875,
|
|
z_min = -17.741199493408203,
|
|
z_max = 282.1300048828125)
|
|
|
|
>>> actor.use_bounds = False
|
|
>>> pl.bounds
|
|
BoundsTuple(x_min = -1.0,
|
|
x_max = 1.0,
|
|
y_min = -1.0,
|
|
y_max = 1.0,
|
|
z_min = -1.0,
|
|
z_max = 1.0)
|
|
|
|
Although the actor's bounds are no longer used, the actor remains visible.
|
|
|
|
>>> actor.visibility
|
|
True
|
|
|
|
"""
|
|
return bool(self.GetUseBounds())
|
|
|
|
@use_bounds.setter
|
|
def use_bounds(self, value: bool) -> None:
|
|
self.SetUseBounds(value)
|
|
|
|
def plot(self, **kwargs) -> None:
|
|
"""Plot just the actor.
|
|
|
|
This may be useful when interrogating or debugging individual actors.
|
|
|
|
Parameters
|
|
----------
|
|
**kwargs : dict, optional
|
|
Optional keyword arguments passed to :func:`pyvista.Plotter.show`.
|
|
|
|
Examples
|
|
--------
|
|
Create an actor without the :class:`pyvista.Plotter`, change its
|
|
properties, and plot it.
|
|
|
|
>>> import pyvista as pv
|
|
>>> mesh = pv.Sphere()
|
|
>>> mapper = pv.DataSetMapper(mesh)
|
|
>>> actor = pv.Actor(mapper=mapper)
|
|
>>> actor.prop.color = 'red'
|
|
>>> actor.prop.show_edges = True
|
|
>>> actor.plot()
|
|
|
|
"""
|
|
pl = pyvista.Plotter()
|
|
pl.add_actor(self)
|
|
pl.show(**kwargs)
|
|
|
|
@_deprecate_positional_args
|
|
def copy(self: Self, deep: bool = True) -> Self: # noqa: FBT001, FBT002
|
|
"""Create a copy of this actor.
|
|
|
|
Parameters
|
|
----------
|
|
deep : bool, default: True
|
|
Create a shallow or deep copy of the actor. A deep copy will have a
|
|
new property and mapper, while a shallow copy will use the mapper
|
|
and property of this actor.
|
|
|
|
Returns
|
|
-------
|
|
Actor
|
|
Deep or shallow copy of this actor.
|
|
|
|
Examples
|
|
--------
|
|
Create an actor of a cube by adding it to a :class:`~pyvista.Plotter`
|
|
and then copy the actor, change the properties, and add it back to the
|
|
:class:`~pyvista.Plotter`.
|
|
|
|
>>> import pyvista as pv
|
|
>>> mesh = pv.Cube()
|
|
>>> pl = pv.Plotter()
|
|
>>> actor = pl.add_mesh(mesh, color='b')
|
|
>>> new_actor = actor.copy()
|
|
>>> new_actor.prop.style = 'wireframe'
|
|
>>> new_actor.prop.line_width = 5
|
|
>>> new_actor.prop.color = 'r'
|
|
>>> new_actor.prop.lighting = False
|
|
>>> _ = pl.add_actor(new_actor)
|
|
>>> pl.show()
|
|
|
|
"""
|
|
new_actor = type(self)()
|
|
if deep:
|
|
if self.mapper is not None:
|
|
new_actor.mapper = self.mapper.copy()
|
|
new_actor.prop = self.prop.copy()
|
|
else:
|
|
new_actor.ShallowCopy(self)
|
|
return new_actor
|
|
|
|
def __repr__(self):
|
|
"""Representation of the actor."""
|
|
mat_info = 'Identity' if np.array_equal(self.user_matrix, np.eye(4)) else 'Set'
|
|
bnd = self.bounds
|
|
attr = [
|
|
f'{type(self).__name__} ({hex(id(self))})',
|
|
f' Center: {self.center}',
|
|
f' Pickable: {self.pickable}',
|
|
f' Position: {self.position}',
|
|
f' Scale: {self.scale}',
|
|
f' Visible: {self.visibility}',
|
|
f' X Bounds {bnd[0]:.3E}, {bnd[1]:.3E}',
|
|
f' Y Bounds {bnd[2]:.3E}, {bnd[3]:.3E}',
|
|
f' Z Bounds {bnd[4]:.3E}, {bnd[5]:.3E}',
|
|
f' User matrix: {mat_info}',
|
|
f' Has mapper: {self.mapper is not None}',
|
|
'',
|
|
repr(self.prop),
|
|
]
|
|
if self.mapper is not None:
|
|
attr.append('')
|
|
attr.append(repr(self.mapper))
|
|
return '\n'.join(attr)
|
|
|
|
@property
|
|
def backface_prop(self) -> pyvista.Property | None: # numpydoc ignore=RT01
|
|
"""Return or set the backface property.
|
|
|
|
By default this property matches the frontface property
|
|
:attr:`Actor.prop`. Once accessed or modified, this backface
|
|
property becomes independent of the frontface property. In
|
|
order to restore the fallback to frontface property, assign
|
|
``None`` to the property.
|
|
|
|
Returns
|
|
-------
|
|
pyvista.Property
|
|
The object describing backfaces.
|
|
|
|
See Also
|
|
--------
|
|
:ref:`backface_prop_example`
|
|
|
|
Examples
|
|
--------
|
|
Clip a sphere by a plane and color the inside of the clipped sphere
|
|
light blue using the ``backface_prop``.
|
|
|
|
>>> import numpy as np
|
|
>>> import pyvista as pv
|
|
>>> plane = pv.Plane(i_size=1.5, j_size=1.5)
|
|
>>> mesh = pv.Sphere().clip_surface(plane, invert=False)
|
|
>>> pl = pv.Plotter()
|
|
>>> actor = pl.add_mesh(mesh, smooth_shading=True)
|
|
>>> actor.backface_prop.color = 'lightblue'
|
|
>>> _ = pl.add_mesh(
|
|
... plane,
|
|
... opacity=0.25,
|
|
... show_edges=True,
|
|
... color='grey',
|
|
... lighting=False,
|
|
... )
|
|
>>> pl.show()
|
|
|
|
"""
|
|
if self.GetBackfaceProperty() is None:
|
|
self.SetBackfaceProperty(self.prop.copy())
|
|
return self.GetBackfaceProperty() # type: ignore[return-value]
|
|
|
|
@backface_prop.setter
|
|
def backface_prop(self, value: pyvista.Property) -> None:
|
|
self.SetBackfaceProperty(value)
|