Boolean Fragments 2D

../_images/fragments2.png
from compas.geometry import Point, Vector, Frame, Polyline
from compas.geometry import Box
from compas.geometry import Translation
from compas.datastructures import Mesh

from compas_view2.app import App
from compas_gmsh.models import ShapeModel

# ==============================================================================
# Geometry
# ==============================================================================

b1 = Box(1)
b2 = Box(1, 1, 1, frame=Frame(b1.vertices[6], Vector.Xaxis(), Vector.Yaxis()))

# ==============================================================================
# CSG Model
# ==============================================================================

model = ShapeModel(name="booleans")

model.options.mesh.lmin = 0.2
model.options.mesh.lmax = 0.2

model.boolean_fragment([model.add_box(b1)], [model.add_box(b2)])

model.generate_mesh(2)
model.optimize_mesh()

# ==============================================================================
# Fragments
# ==============================================================================

# this needs to be integrated in the lib
# PRs very welcome! :)

nodes = model.mesh.get_nodes()
node_tags = nodes[0]
node_coords = nodes[1].reshape((-1, 3), order="C")
vertices = {}
for tag, coords in zip(node_tags, node_coords):
    vertices[int(tag)] = coords

fragments = []

for dimtag in model.model.get_entities(2):
    faces = []
    elements = model.mesh.get_elements(*dimtag)
    for etype, etags, ntags in zip(*elements):
        for i, etag in enumerate(etags):
            n = model.mesh.get_element_properties(etype)[3]
            faces.append(ntags[i * n : i * n + n])
    mesh = Mesh.from_vertices_and_faces(vertices, faces)
    mesh.remove_unused_vertices()
    fragments.append(mesh)

# ==============================================================================
# Visualization with viewer
# ==============================================================================

viewer = App(width=1600, height=900)

viewer.view.camera.rz = 0
viewer.view.camera.rx = -75
viewer.view.camera.tx = 0
viewer.view.camera.ty = 0
viewer.view.camera.distance = 10

viewer.add(b1, opacity=0.7, facecolor=(1, 0, 0), linewidth=2)
viewer.add(b2, opacity=0.7, facecolor=(0, 1, 0), linewidth=2)

T2 = Translation.from_vector([3, 0, 0])

point = Point(0, 0, 0)
for mesh in fragments:
    centroid = Point(*mesh.centroid())
    vector = centroid - point
    T1 = Translation.from_vector(vector * 0.2)

    mesh.transform(T2 * T1)

    viewer.add(mesh, show_lines=False)
    viewer.add(
        Polyline(
            mesh.vertices_attributes("xyz", keys=list(mesh.vertices_on_boundary()))
        ),
        linewidth=2,
    )

viewer.run()