"""Factory function for VTK PolyData objects."""
from typing import Any, Callable, Optional, Tuple, Union
from typing import Dict as TypingDict
from typing import List as TypingList
import numpy as np
from ..helpers import check_attribute_color_range
from ..objects import Mesh
from ..transform import process_transform_arguments
from .common import default_colormap, factory_color
# Type aliases for better readability
ArrayLike = Union[TypingList, np.ndarray, Tuple]
ColorMap = Union[TypingList[TypingList[float]], TypingDict[str, Any], np.ndarray]
ColorRange = TypingList[float]
OpacityFunction = TypingList[float]
# Optional dependency, imported on first use rather than at import time: loading it pulls in
# ~160 extension modules and is a third of `import k3d` for everyone who has it installed, which
# includes everyone who installed pyvista for something else. Only vtk_poly_data touches it.
vtk = None
nps = None
def _require_vtk():
"""Import VTK, raising what the module-scope guard used to raise when it is missing."""
global vtk, nps
if vtk is not None:
return
try:
import vtk as vtk_module
from vtk.util import numpy_support
except ImportError:
raise RuntimeError("vtk module is not available") from None
vtk = vtk_module
nps = numpy_support
[docs]
def vtk_poly_data(
poly_data: Any, # vtk.vtkPolyData
color: Optional[int] = None,
color_attribute: Optional[Tuple[str, float, float]] = None,
color_map: Optional[ColorMap] = None,
side: str = "front",
slice_planes: ArrayLike = None,
wireframe: bool = False,
opacity: float = 1.0,
volume: ArrayLike = None,
volume_bounds: ArrayLike = None,
opacity_function: OpacityFunction = None,
color_range: ColorRange = None,
cell_color_attribute: Optional[Tuple[str, float, float]] = None,
flat_shading: bool = True,
roughness: float = 0.4,
metalness: float = 0.0,
shininess: float = None,
name: Optional[str] = None,
group: Optional[str] = None,
custom_data: Optional[TypingDict[str, Any]] = None,
compression_level: int = 0,
visible: bool = True,
click_callback: Optional[Callable] = None,
hover_callback: Optional[Callable] = None,
**kwargs: Any,
) -> Mesh:
"""
Create a Mesh drawable from a vtkPolyData object.
Parameters
----------
poly_data : vtkPolyData
The polygonal data to convert. Cells with more than three points, and triangle strips, are
triangulated first.
color : int, optional
Packed RGB color of the mesh (0xff0000 is red, 0xff is blue). It multiplies the
colormap. Default is 255, or white when a color attribute is given.
color_attribute : tuple, optional
Attribute to colour by, as (array name, min, max) read from the point data. Default is
None.
color_map : list, optional
A list of float quadruplets (attribute value, R, G, B), sorted by attribute value. The
first quadruplet should have value 0.0, the last 1.0; R, G, B are RGB color components in
the range 0.0 to 1.0. Default is None.
side : str, optional
Which faces of the mesh are drawn: 'front', 'back' or 'double'. Default is 'front'.
slice_planes : list, optional
Planes [a, b, c, d] the section outline is drawn along, up to eight of them. The outline
is drawn in the object colour. Default is None.
wireframe : bool, optional
Whether mesh should display as wireframe. Default is False.
opacity : float, optional
Opacity of mesh. Default is 1.0.
volume : array_like, optional
3D array sampled for the colour of each fragment, with volume_bounds giving the box it
spans. Default is None.
volume_bounds : array_like, optional
Bounding box [xmin, xmax, ymin, ymax, zmin, zmax] of `volume`. Default is None.
opacity_function : list, optional
A list of float tuples (attribute value, opacity), sorted by attribute value. The first
tuple should have value 0.0, the last 1.0; opacity is in the range 0.0 to 1.0. Default is
None.
color_range : list, optional
A pair [min_value, max_value], which determines the levels of color attribute mapped to 0
and 1 in the color map respectively. Default is None.
cell_color_attribute : tuple, optional
Attribute to colour by, as (array name, min, max) read from the cell data. Default is
None.
flat_shading : bool, optional
Whether mesh should display with flat shading. Default is True.
roughness : float, optional
Roughness of object material. Default is 0.4.
metalness : float, optional
Metalness of object material. Default is 0.0.
shininess : float, optional
Removed in 3.0.0; passing it raises. Use roughness and metalness. Default is None.
name : str, optional
A name of the object. Default is None.
group : str, optional
A name of a group. Default is None.
custom_data : dict, optional
An object with custom data attached to object. Default is None.
compression_level : int, optional
Level of compression [-1, 9]. Default is 0.
visible : bool, optional
Whether the object is drawn. Default is True.
click_callback : callable, optional
Called with the picking parameters when the object is clicked, while the plot is
in mode='callback'. Default is None.
hover_callback : callable, optional
Called with the picking parameters when the cursor is over the object, while the
plot is in mode='callback'. Default is None.
**kwargs
Additional keyword arguments passed to process_transform_arguments.
Returns
-------
Mesh
The created Mesh object.
"""
if slice_planes is None:
slice_planes = []
if volume is None:
volume = []
if volume_bounds is None:
volume_bounds = []
if opacity_function is None:
opacity_function = []
if color_range is None:
color_range = []
if color_map is None:
color_map = default_colormap
_require_vtk()
# indices below read GetPolys() only, so strips have to be triangulated whatever their
# size: a strip of exactly 3 points left the mesh with no indices at all
if (
max(
poly_data.GetPolys().GetMaxCellSize(),
poly_data.GetStrips().GetMaxCellSize(),
)
> 3
or poly_data.GetStrips().GetNumberOfCells() > 0
):
cut_triangles = vtk.vtkTriangleFilter()
cut_triangles.SetInputData(poly_data)
cut_triangles.Update()
poly_data = cut_triangles.GetOutput()
attribute = []
triangles_attribute = []
if color_attribute is not None:
attribute = nps.vtk_to_numpy(
poly_data.GetPointData().GetArray(color_attribute[0])
)
color_range = color_attribute[1:3]
elif cell_color_attribute is not None:
triangles_attribute = nps.vtk_to_numpy(
poly_data.GetCellData().GetArray(cell_color_attribute[0])
)
color_range = cell_color_attribute[1:3]
elif len(volume) > 0:
color_range = check_attribute_color_range(volume, color_range)
color = factory_color(color, attribute, triangles_attribute)
vertices = nps.vtk_to_numpy(poly_data.GetPoints().GetData())
indices = nps.vtk_to_numpy(poly_data.GetPolys().GetData()).reshape(-1, 4)[:, 1:4]
volume_bounds = (
np.array(volume_bounds, np.float32)
if type(volume_bounds) is not dict
else volume_bounds
)
return process_transform_arguments(
Mesh(
vertices=np.array(vertices, np.float32),
indices=np.array(indices, np.uint32),
normals=[],
color=color,
colors=[],
opacity=opacity,
attribute=np.array(attribute, np.float32),
triangles_attribute=np.array(triangles_attribute, np.float32),
color_range=color_range,
color_map=np.array(color_map, np.float32),
wireframe=wireframe,
volume=volume,
volume_bounds=volume_bounds,
texture=None,
opacity_function=opacity_function,
side=side,
flat_shading=flat_shading,
roughness=roughness,
metalness=metalness,
shininess=shininess,
slice_planes=slice_planes,
name=name,
group=group,
custom_data=custom_data,
compression_level=compression_level,
visible=visible,
click_callback=click_callback,
hover_callback=hover_callback,
),
**kwargs,
)