Note
Go to the end to download the full example code.
Clip and Cap a Closed Surface#
Compare a standard planar clip, which leaves an open boundary, with
pyvista.PolyDataFilters.clip_closed_surface(), which seals the cut face.
import pyvista as pv
from pyvista import examples
Load a closed surface#
The download_lucy() scan is a watertight,
manifold PolyData surface with no open edges.
Define an oblique cutting plane#
The same plane is reused for both the open and the closed-surface clip.
plane_origin = surface.center
plane_normal = (1, 0.3, 0)
plane_size = surface.length * 1.2
plane = pv.Plane(
center=plane_origin, direction=plane_normal, i_size=plane_size, j_size=plane_size
)
pl = pv.Plotter()
pl.add_mesh(surface, color='wheat', smooth_shading=True)
pl.add_mesh(plane, style='wireframe', color='black', line_width=2)
pl.view_xz()
pl.camera.azimuth = 35
pl.show()

Compare an open cut to a capped cut#
A standard clip leaves a boundary loop along the cut. The closed-surface clip caps that loop with new triangles and stays watertight.
open_clip = surface.clip(normal=plane_normal, origin=plane_origin)
closed_clip = surface.clip_closed_surface(normal=plane_normal, origin=plane_origin)
open_boundary = open_clip.extract_feature_edges(
boundary_edges=True,
feature_edges=False,
manifold_edges=False,
non_manifold_edges=False,
)
pl = pv.Plotter(shape=(1, 2))
pl.subplot(0, 0)
pl.add_mesh(open_clip, color='wheat', smooth_shading=True)
pl.add_mesh(open_boundary, color='tomato', line_width=6)
pl.add_mesh(plane, style='wireframe', color='black', line_width=2)
pl.view_xz()
pl.camera.azimuth = 35
pl.subplot(0, 1)
pl.add_mesh(closed_clip, color='wheat', smooth_shading=True)
pl.add_mesh(plane, style='wireframe', color='black', line_width=2)
pl.view_xz()
pl.camera.azimuth = 35
pl.link_views()
pl.show()

Confirm that the capped result is watertight#
The open clip carries hundreds of boundary edges; the capped result has none.
(1082, 0)
Total running time of the script: (0 minutes 1.939 seconds)