Skip to content

Commit c2f4449

Browse files
FIX multi iso-values remeshing.
1 parent cb447a2 commit c2f4449

File tree

9 files changed

+150
-520
lines changed

9 files changed

+150
-520
lines changed

See

Whitespace-only changes.

docs/examples/meshing_multi_isolines.py

Lines changed: 0 additions & 44 deletions
This file was deleted.

docs/examples/meshing_multiple_planes.py

Lines changed: 0 additions & 146 deletions
This file was deleted.

docs/examples/meshing_plane.py

Lines changed: 13 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,29 @@
11
import math
22
import compas_libigl as igl
33
from compas.colors import Color
4-
from compas.geometry import Plane
4+
from compas.geometry import Plane, Rotation, Scale
55
from compas.datastructures import Mesh
6-
from compas.geometry import Rotation, Scale
76
from compas_viewer import Viewer
87

9-
10-
def split_mesh_by_plane(mesh, plane):
11-
"""Split a mesh into two parts using a plane.
12-
13-
Parameters
14-
----------
15-
mesh : compas.datastructures.Mesh
16-
The input mesh to split
17-
plane : compas.geometry.Plane
18-
The plane to split with
19-
20-
Returns
21-
-------
22-
tuple
23-
Two meshes (below_mesh, above_mesh), representing parts on each side of the plane
24-
"""
25-
# Calculate signed distance to the plane for all vertices
26-
distances = []
27-
for vertex in mesh.vertices():
28-
point = mesh.vertex_attributes(vertex, "xyz")
29-
vector = plane.point - point
30-
distance = plane.normal.dot(vector)
31-
distances.append(distance)
32-
mesh.vertex_attribute(vertex, "distance", distance)
33-
34-
# Remesh along the zero isoline (plane intersection)
35-
V2, F2, L = igl.trimesh_remesh_along_isoline(
36-
mesh.to_vertices_and_faces(),
37-
distances,
38-
0
39-
)
40-
41-
# Split faces based on labels (0 = below, 1 = above)
42-
below_faces = [f for i, f in enumerate(F2) if L[i] == 0]
43-
above_faces = [f for i, f in enumerate(F2) if L[i] == 1]
44-
45-
# Get unique vertices for each part
46-
below_vertices = set()
47-
above_vertices = set()
48-
for face in below_faces:
49-
below_vertices.update(face)
50-
for face in above_faces:
51-
above_vertices.update(face)
52-
53-
# Create vertex maps for new indices
54-
below_vmap = {old: new for new, old in enumerate(sorted(below_vertices))}
55-
above_vmap = {old: new for new, old in enumerate(sorted(above_vertices))}
56-
57-
# Create new vertex lists
58-
below_verts = [V2[i] for i in sorted(below_vertices)]
59-
above_verts = [V2[i] for i in sorted(above_vertices)]
60-
61-
# Remap face indices
62-
below_faces = [[below_vmap[v] for v in face] for face in below_faces]
63-
above_faces = [[above_vmap[v] for v in face] for face in above_faces]
64-
65-
# Create new meshes for each part
66-
below_mesh = Mesh.from_vertices_and_faces(below_verts, below_faces) if below_faces else None
67-
above_mesh = Mesh.from_vertices_and_faces(above_verts, above_faces) if above_faces else None
68-
69-
return below_mesh, above_mesh
70-
71-
728
# Load and transform mesh
739
mesh = Mesh.from_off(igl.get_beetle())
7410
R = Rotation.from_axis_and_angle([1, 0, 0], math.radians(90))
7511
S = Scale.from_factors([10, 10, 10])
7612
mesh.transform(S * R)
7713

78-
# Define a single cutting plane (horizontal at z=0)
79-
cutting_plane = Plane([0, 0, 0], [0, 1, 1])
14+
# Calculate signed distances to plane
15+
plane = Plane([0, 0, 0], [0, 1, 1])
16+
distances = [plane.normal.dot(plane.point - mesh.vertex_coordinates(v)) for v in mesh.vertices()]
8017

81-
# Split the mesh
82-
below_mesh, above_mesh = split_mesh_by_plane(mesh, cutting_plane)
83-
print(f"Original mesh: {mesh.number_of_vertices()} vertices, {mesh.number_of_faces()} faces")
84-
print(f"Below mesh: {below_mesh.number_of_vertices()} vertices, {below_mesh.number_of_faces()} faces")
85-
print(f"Above mesh: {above_mesh.number_of_vertices()} vertices, {above_mesh.number_of_faces()} faces")
18+
# Split mesh along plane
19+
V, F, L = igl.trimesh_remesh_along_isoline(mesh.to_vertices_and_faces(), distances, 0)
8620

87-
# Setup visualization
88-
viewer = Viewer()
89-
90-
# Add both mesh parts with different colors
91-
viewer.scene.add(below_mesh, facecolor=Color.red(), name="Below Plane")
92-
viewer.scene.add(above_mesh, facecolor=Color.blue(), name="Above Plane")
21+
# Create meshes for parts below and above plane
22+
below = Mesh.from_vertices_and_faces(V, [F[i] for i, l in enumerate(L) if l == 0])
23+
above = Mesh.from_vertices_and_faces(V, [F[i] for i, l in enumerate(L) if l == 1])
9324

25+
# Visualize
26+
viewer = Viewer()
27+
viewer.scene.add(below, facecolor=Color.red(), show_lines=False)
28+
viewer.scene.add(above, facecolor=Color.blue(), show_lines=False)
9429
viewer.show()

docs/examples/meshing_planes.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import compas_libigl as igl
2+
from compas.colors import ColorMap
3+
from compas.geometry import Rotation
4+
from compas.geometry import Scale
5+
import math
6+
from compas.datastructures import Mesh
7+
from compas_viewer import Viewer
8+
9+
# Load mesh
10+
mesh = Mesh.from_off(igl.get_beetle())
11+
R = Rotation.from_axis_and_angle([1, 0, 0], math.radians(90))
12+
S = Scale.from_factors([10, 10, 10])
13+
mesh.transform(S * R)
14+
15+
# Get z-coordinates as scalar field
16+
scalar_values = mesh.vertices_attribute("z")
17+
min_val, max_val = min(scalar_values), max(scalar_values)
18+
19+
# Create 4 isolines
20+
num_isolines = 4
21+
isovalues = [min_val + i * (max_val - min_val) / num_isolines for i in range(1, num_isolines + 1)]
22+
23+
# Split mesh along isolines
24+
V, F, S, G = igl.trimesh_remesh_along_isolines(
25+
mesh.to_vertices_and_faces(),
26+
scalar_values,
27+
isovalues
28+
)
29+
30+
# Visualize each piece in a different color
31+
color_map = ColorMap.from_mpl("viridis")
32+
viewer = Viewer()
33+
34+
# Create separate mesh for each group
35+
for i, group_id in enumerate(set(G)):
36+
faces = [F[j] for j in range(len(F)) if G[j] == group_id]
37+
if faces:
38+
piece = Mesh.from_vertices_and_faces(V, faces)
39+
viewer.scene.add(piece, facecolor=color_map(i / (num_isolines + 1)), show_lines=False)
40+
41+
viewer.show()

docs/examples/meshing_waves.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import compas_libigl as igl
2+
from compas.colors import ColorMap
3+
from compas.geometry import Rotation, Scale, Point, distance_point_point
4+
import math
5+
import numpy as np
6+
from compas.datastructures import Mesh
7+
from compas_viewer import Viewer
8+
9+
# Load mesh
10+
mesh = Mesh.from_off(igl.get_beetle())
11+
R = Rotation.from_axis_and_angle([1, 0, 0], math.radians(90))
12+
S = Scale.from_factors([10, 10, 10])
13+
mesh.transform(S * R)
14+
15+
scalar_values = []
16+
frequency = 2
17+
for v in mesh.vertices():
18+
x, y, z = mesh.vertex_coordinates(v)
19+
val = math.sin(frequency * x) * math.cos(frequency * y) + math.sin(frequency * z)
20+
scalar_values.append(val)
21+
22+
23+
# Get range and create isolines
24+
min_val, max_val = min(scalar_values), max(scalar_values)
25+
num_isolines = 7
26+
isovalues = [min_val + i * (max_val - min_val) / num_isolines for i in range(1, num_isolines + 1)]
27+
28+
# Split mesh along isolines
29+
V, F, S, G = igl.trimesh_remesh_along_isolines(
30+
mesh.to_vertices_and_faces(),
31+
scalar_values,
32+
isovalues
33+
)
34+
35+
# Visualize each piece in a different color
36+
color_map = ColorMap.from_mpl("plasma")
37+
viewer = Viewer()
38+
39+
# Create separate mesh for each group
40+
for i, group_id in enumerate(set(G)):
41+
faces = [F[j] for j in range(len(F)) if G[j] == group_id]
42+
if faces:
43+
piece = Mesh.from_vertices_and_faces(V, faces)
44+
viewer.scene.add(piece, facecolor=color_map(i / (num_isolines + 1)), show_lines=False)
45+
46+
viewer.show()

0 commit comments

Comments
 (0)