# 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.
surface = examples.download_lucy().triangulate()
surface

# 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.
open_boundary.n_cells, closed_clip.n_open_edges

# ----------------------------------------------------------------------
# Generated by sphinx-examples-as-code https://github.com/pyvista/sphinx-examples-as-code

