Skip to content

Boolean Operations

Boolean Operations

The four core pairwise boolean operations on two triangle meshes (a box and an offset sphere): difference, intersection, union, and mesh splitting. Every result is a valid, watertight, oriented 2-manifold — Manifold guarantees this for all operations.

Run it (requires compas_viewer):

python docs/examples/example_booleans.py
from compas.datastructures import Mesh
from compas.geometry import Box
from compas.geometry import Polyhedron
from compas.geometry import Sphere
from compas.geometry import Translation
from compas_viewer import Viewer

from compas_manifold.booleans import boolean_difference_mesh_mesh
from compas_manifold.booleans import boolean_intersection_mesh_mesh
from compas_manifold.booleans import boolean_union_mesh_mesh
from compas_manifold.booleans import split_mesh_mesh


def inputs():
    """Create a box and an offset sphere as triangle meshes."""
    box = Box(2)
    A = box.to_vertices_and_faces(triangulated=True)
    sphere = Sphere(1.0, point=[1, 1, 1])
    B = sphere.to_vertices_and_faces(u=64, v=64, triangulated=True)
    return A, B


def boolean_difference():
    A, B = inputs()
    V, F = boolean_difference_mesh_mesh(A, B)
    return Polyhedron(V.tolist(), F.tolist()).to_mesh()


def boolean_intersection():
    A, B = inputs()
    V, F = boolean_intersection_mesh_mesh(A, B)
    return Polyhedron(V.tolist(), F.tolist()).to_mesh()


def boolean_union():
    A, B = inputs()
    V, F = boolean_union_mesh_mesh(A, B)
    return Polyhedron(V.tolist(), F.tolist()).to_mesh()


def split():
    A, B = inputs()
    V, F = split_mesh_mesh(A, B)
    mesh = Mesh.from_vertices_and_faces(V, F)
    return mesh.exploded()


# =============================================================================
# Compute
# =============================================================================

difference = boolean_difference()
intersection = boolean_intersection()
union = boolean_union()
splits = split()

# =============================================================================
# Spread out for display
# =============================================================================

difference.transform(Translation.from_vector([-6, 0, 0]))
intersection.transform(Translation.from_vector([-2, 0, 0]))
union.transform(Translation.from_vector([2, 0, 0]))
for m in splits:
    m.transform(Translation.from_vector([6, 0, 0]))

# =============================================================================
# Visualize
# =============================================================================

viewer = Viewer()
viewer.scene.add(difference, lineswidth=1, show_points=False)
viewer.scene.add(intersection, lineswidth=1, show_points=False)
viewer.scene.add(union, lineswidth=1, show_points=False)
group = viewer.scene.add_group(name="Splits")
group.add_from_list(splits, lineswidth=1, show_points=False)
viewer.show()