Meshing

../_images/example_meshing_plane.png
import math

from compas.colors import Color
from compas.datastructures import Mesh
from compas.geometry import Plane
from compas.geometry import Rotation
from compas.geometry import Scale
from compas_viewer import Viewer

import compas_libigl as igl

# Load and transform mesh
mesh = Mesh.from_off(igl.get_beetle())
R = Rotation.from_axis_and_angle([1, 0, 0], math.radians(90))
S = Scale.from_factors([10, 10, 10])
mesh.transform(S * R)

# Calculate signed distances to plane
plane = Plane([0, 0, 0], [0, 1, 1])
distances = [plane.normal.dot(plane.point - mesh.vertex_coordinates(v)) for v in mesh.vertices()]

# Split mesh along plane
V, F, L = igl.trimesh_remesh_along_isoline(mesh.to_vertices_and_faces(), distances, 0)

# Create meshes for parts below and above plane
below = Mesh.from_vertices_and_faces(V, [F[i] for i, l in enumerate(L) if l == 0])
above = Mesh.from_vertices_and_faces(V, [F[i] for i, l in enumerate(L) if l == 1])

# Visualize
viewer = Viewer()
viewer.scene.add(below, facecolor=Color.red(), show_lines=False)
viewer.scene.add(above, facecolor=Color.blue(), show_lines=False)
viewer.show()
../_images/example_meshing_planes.png
import math

from compas.colors import ColorMap
from compas.datastructures import Mesh
from compas.geometry import Rotation
from compas.geometry import Scale
from compas_viewer import Viewer

import compas_libigl as igl

# Load mesh
mesh = Mesh.from_off(igl.get_beetle())
R = Rotation.from_axis_and_angle([1, 0, 0], math.radians(90))
S = Scale.from_factors([10, 10, 10])
mesh.transform(S * R)

# Get z-coordinates as scalar field
scalar_values = mesh.vertices_attribute("z")
min_val, max_val = min(scalar_values), max(scalar_values)

# Create 4 isolines
num_isolines = 4
isovalues = [min_val + i * (max_val - min_val) / num_isolines for i in range(1, num_isolines + 1)]

# Split mesh along isolines
V, F, S, G = igl.trimesh_remesh_along_isolines(mesh.to_vertices_and_faces(), scalar_values, isovalues)

# Visualize each piece in a different color
color_map = ColorMap.from_mpl("viridis")
viewer = Viewer()

# Create separate mesh for each group
for i, group_id in enumerate(set(G)):
    faces = [F[j] for j in range(len(F)) if G[j] == group_id]
    if faces:
        piece = Mesh.from_vertices_and_faces(V, faces)
        viewer.scene.add(piece, facecolor=color_map(i / (num_isolines + 1)), show_lines=False)

viewer.show()
../_images/example_meshing_waves.png
import math

from compas.colors import ColorMap
from compas.datastructures import Mesh
from compas.geometry import Rotation
from compas.geometry import Scale
from compas_viewer import Viewer

import compas_libigl as igl

# Load mesh
mesh = Mesh.from_off(igl.get_beetle())
R = Rotation.from_axis_and_angle([1, 0, 0], math.radians(90))
S = Scale.from_factors([10, 10, 10])
mesh.transform(S * R)

scalar_values = []
frequency = 2
for v in mesh.vertices():
    x, y, z = mesh.vertex_coordinates(v)
    val = math.sin(frequency * x) * math.cos(frequency * y) + math.sin(frequency * z)
    scalar_values.append(val)


# Get range and create isolines
min_val, max_val = min(scalar_values), max(scalar_values)
num_isolines = 7
isovalues = [min_val + i * (max_val - min_val) / num_isolines for i in range(1, num_isolines + 1)]

# Split mesh along isolines
V, F, S, G = igl.trimesh_remesh_along_isolines(mesh.to_vertices_and_faces(), scalar_values, isovalues)

# Visualize each piece in a different color
color_map = ColorMap.from_mpl("plasma")
viewer = Viewer()

# Create separate mesh for each group
for i, group_id in enumerate(set(G)):
    faces = [F[j] for j in range(len(F)) if G[j] == group_id]
    if faces:
        piece = Mesh.from_vertices_and_faces(V, faces)
        viewer.scene.add(piece, facecolor=color_map(i / (num_isolines + 1)), show_lines=False)

viewer.show()
../_images/example_meshing_geodesic.png
import math

from compas.colors import ColorMap
from compas.datastructures import Mesh
from compas.geometry import Point
from compas.geometry import Rotation
from compas.geometry import Scale
from compas_viewer import Viewer

import compas_libigl as igl

# ==============================================================================
# Input geometry
# ==============================================================================

mesh = Mesh.from_off(igl.get("camelhead.off"))
R = Rotation.from_axis_and_angle([1, 0, 0], math.radians(90))
S = Scale.from_factors([10, 10, 10])
mesh.transform(S * R)

# Convert to triangle mesh
trimesh = mesh.copy()
trimesh.quads_to_triangles()

# ==============================================================================
# Compute geodesic distances from boundary
# ==============================================================================

# Get boundary vertices
boundary_vertices = list(trimesh.vertices_on_boundary())

# Calculate geodesic distances using multiple source points
distances = igl.trimesh_geodistance_multiple(trimesh.to_vertices_and_faces(), boundary_vertices, method="exact")

# ==============================================================================
# Create isolines and remesh
# ==============================================================================

# Get range and create isolines
min_dist, max_dist = min(distances), max(distances)
num_isolines = 5
isovalues = [min_dist + i * (max_dist - min_dist) / num_isolines for i in range(1, num_isolines + 1)]

# Split mesh along isolines of geodesic distance
V, F, S, G = igl.trimesh_remesh_along_isolines(trimesh.to_vertices_and_faces(), distances, isovalues)

# ==============================================================================
# Visualization
# ==============================================================================

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

# Create separate mesh for each geodesic distance group
color_map = ColorMap.from_mpl("viridis")
for i, group_id in enumerate(sorted(set(G))):
    faces = [F[j] for j in range(len(F)) if G[j] == group_id]
    if faces:
        piece = Mesh.from_vertices_and_faces(V, faces)
        viewer.scene.add(piece, facecolor=color_map(i / (num_isolines + 1)), show_lines=False, linewidth=1, linecolor=(0.2, 0.2, 0.2))

# Highlight boundary vertices
for vertex in boundary_vertices:
    point = Point(*trimesh.vertex_attributes(vertex, "xyz"))
    viewer.scene.add(point, pointsize=20, pointcolor=(1, 0, 0))

viewer.show()