# Examples from pyvista.DataSetFilters.voxelize_binary_mask
# =========================================================

# Generate a binary mask from a coarse mesh.
import numpy as np
import pyvista as pv
from pyvista import examples
poly = examples.download_bunny_coarse()
mask = poly.voxelize_binary_mask()

# The mask is stored as `ImageData` with point data scalars
# (zeros for background, ones for foreground).
mask

np.unique(mask.point_data['mask'])

# To visualize it as voxel cells, use `points_to_cells()`,
# then use `threshold()` to extract the foreground.
# We also plot the voxel cells in blue and the input poly data in green for
# comparison.
def mask_and_polydata_plotter(mask, poly):
    voxel_cells = mask.points_to_cells().threshold(0.5)

    pl = pv.Plotter()
    _ = pl.add_mesh(voxel_cells, color='blue')
    _ = pl.add_mesh(poly, color='lime')
    pl.camera_position = 'xy'
    return pl

pl = mask_and_polydata_plotter(mask, poly)
pl.show()

# The spacing of the mask image is automatically adjusted to match the
# density of the input.
# Repeat the previous example with a finer mesh.
poly = examples.download_bunny()
mask = poly.voxelize_binary_mask()
pl = mask_and_polydata_plotter(mask, poly)
pl.show()

# Control the spacing manually instead. Here, a very coarse spacing is used.
mask = poly.voxelize_binary_mask(spacing=(0.01, 0.04, 0.02))
pl = mask_and_polydata_plotter(mask, poly)
pl.show()

# Note that the spacing is only approximate. Check the mask's actual spacing.
mask.spacing

# The actual values may be greater or less than the specified values. Use
# `rounding_func=np.floor` to force all values to be greater.
mask = poly.voxelize_binary_mask(
    spacing=(0.01, 0.04, 0.02), rounding_func=np.floor
)
mask.spacing

# Set the dimensions instead of the spacing.
mask = poly.voxelize_binary_mask(dimensions=(10, 20, 30))
pl = mask_and_polydata_plotter(mask, poly)
pl.show()

mask.dimensions

# Create a mask using a reference volume. First load a label map,
# crop it to the frog's head, and generate polydata from it.
volume = examples.load_frog_tissues()
volume = volume.crop(extent=(300, 499, 110, 350, 0, 100))
poly = volume.contour_labels()

# Now create the mask from the polydata using the volume as a reference.
mask = poly.voxelize_binary_mask(reference_volume=volume)
pl = mask_and_polydata_plotter(mask, poly)
pl.show()

# The mask is mottled where the surface is not closed. Smoothed surfaces from
# `contour_labels()` have gaps wherever the labels
# touch only along a voxel edge, and the cut contours are closed heuristically
# there.
# Visualize the effect of internal surfaces.
mesh = pv.Cylinder() + pv.Cylinder(center=(0, 0.75, 0))
binary_mask = mesh.voxelize_binary_mask(
    dimensions=(1, 100, 50)
).points_to_cells()
pl = pv.Plotter()
_ = pl.add_mesh(binary_mask)
_ = pl.add_mesh(mesh.slice(), color='red')
pl.show(cpos='yz')

# Note how the intersection is excluded from the mask.
# To include the voxels delimited by internal surfaces in the foreground, the internal
# surfaces should be removed, for instance by applying a boolean union. Note that
# this operation in unreliable in VTK but may be performed with external tools such
# as vtkbool.
# Alternatively, the intersecting parts of the mesh can be processed sequentially.
cylinder_1 = pv.Cylinder()
cylinder_2 = pv.Cylinder(center=(0, 0.75, 0))

reference_volume = pv.ImageData(
    dimensions=(1, 100, 50),
    spacing=(1, 0.0175, 0.02),
    origin=(0, -0.5 + 0.0175 / 2, -0.5 + 0.02 / 2),
)

binary_mask_1 = cylinder_1.voxelize_binary_mask(
    reference_volume=reference_volume
).points_to_cells()
binary_mask_2 = cylinder_2.voxelize_binary_mask(
    reference_volume=reference_volume
).points_to_cells()

binary_mask_1['mask'] = binary_mask_1['mask'] | binary_mask_2['mask']

pl = pv.Plotter()
_ = pl.add_mesh(binary_mask_1)
_ = pl.add_mesh(cylinder_1.slice(), color='red')
_ = pl.add_mesh(cylinder_2.slice(), color='red')
pl.show(cpos='yz')

# When multiple internal surfaces are nested, they are successively treated as
# interfaces between background and foreground.
mesh = pv.Tube(radius=2) + pv.Tube(radius=3) + pv.Tube(radius=4)
binary_mask = mesh.voxelize_binary_mask(
    dimensions=(1, 50, 50)
).points_to_cells()
pl = pv.Plotter()
_ = pl.add_mesh(binary_mask)
_ = pl.add_mesh(mesh.slice(), color='red')
pl.show(cpos='yz')

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