Split mesh using a splitting plane
See original GitHub issueI want to split a mesh using a plane, similar to cross_section
but returning both halves of the mesh as closed meshes instead of the polyline boundary of the intersection surface. I wrote the following code to achieve this:
def split_mesh(mesh, plane_origin, plane_normal):
"""
Splits mesh by intersection with a plane,
returns closed mesh for positive and negative side of plane
"""
plane_normal = unit_vector(plane_normal)
polyline, triangles_edge = trimesh.intersections.mesh_plane(bbox_mesh,
plane_origin= plane_origin,
plane_normal= plane_normal,
return_faces=True)
vertices_negative = []
vertices_positive = []
for vertex_id, vertex in enumerate(bbox_mesh.vertices):
# TODO: add threshold
signed_distance = np.dot(plane_normal, np.subtract(vertex, plane_origin))
if signed_distance < 0:
vertices_negative.append(vertex_id)
else:
vertices_positive.append(vertex_id)
triangles_negative = []
triangles_positive = []
# For each triangle check how many points on either side of the plane
for triangle in bbox_mesh.faces:
triangle_negative_check = [vertex_id in vertices_negative for vertex_id in triangle]
# If all points on the negative side this triangle is not affected
if all(triangle_negative_check):
triangles_negative.append(np.array(bbox_mesh.vertices[triangle]))
elif any(triangle_negative_check):
# Get section line for this triangle on edge
section = polyline[np.all(np.isin(bbox_mesh.faces[triangles_edge], np.array(triangle)), axis=1)][0]
assert section.shape == (2,3)
# If two points on negative side
if sum(triangle_negative_check) == 2:
vertex_1, vertex_2 = bbox_mesh.vertices[triangle[triangle_negative_check]]
triangles_negative.extend(unordered_to_triangles([section[0], section[1], vertex_1, vertex_2]))
vertex_3 = bbox_mesh.vertices[triangle[np.logical_not(triangle_negative_check)]]
triangles_positive.append(np.vstack([section[0], section[1], vertex_3]))
elif sum(triangle_negative_check) == 1:
vertex_3 = bbox_mesh.vertices[triangle[triangle_negative_check]]
triangles_negative.append(np.vstack([section[0], section[1], vertex_3]))
vertex_1, vertex_2 = bbox_mesh.vertices[triangle[np.logical_not(triangle_negative_check)]]
triangles_positive.extend(unordered_to_triangles([section[0], section[1], vertex_1, vertex_2]))
# If all points on the positive side this triangle is not affected
else:
triangles_positive.append(np.array(bbox_mesh.vertices[triangle]))
# Get triangulation of the split surface
vertices_splitsurface = []
for a, b in polyline:
for vertex in [a,b]:
if tuple(vertex) not in vertices_splitsurface:
vertices_splitsurface.append(tuple(vertex))
triangles_splitsurface = unordered_to_triangles(vertices_splitsurface)
# Add triangles of split surface to both the positive and negative side
triangles_negative.extend(triangles_splitsurface)
triangles_positive.extend(triangles_splitsurface)
# Create Trimesh from triangles for positive and negative
mesh_negative = trimesh.Trimesh(*to_face_indices(triangles_negative))
mesh_positive = trimesh.Trimesh(*to_face_indices(triangles_positive))
return mesh_positive, mesh_negative
Would it be useful to improve and create a pull request, or is there a much more simple way to achieve this with trimesh?
Looking forward to your reply!
Issue Analytics
- State:
- Created 5 years ago
- Reactions:1
- Comments:17 (9 by maintainers)
Top Results From Across the Web
Split a mesh with a plane - Blender Stack Exchange
Add a plane · Grab and move the plane to where I want the cut an existing mesh · Select the plane, then...
Read more >Split Mesh with Plane
The Split Mesh with Plane command enables you to cut triangular meshes with a plane that can be defined in an interactive way....
Read more >Mesh Splitting and Booleans (Add, Intersect, Subtract)
The Split Mesh tool will divide a mesh into two portions based on a cutting plane. Split Mesh is an ideal tool for...
Read more >Mesh Split Plane - Parametric House
In this grasshopper example file you can create a stellated mesh and split it with a parametric plane.
Read more >MeshSplit | Rhino 3-D modeling
If a curve is selected as splitter, it is "extruded" in the z-direction of the current CPlane to intersect and split the mesh....
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
BTW the test script to generate those images:
Oh, you probably don’t have to implement
linestrings_to_polygon
yourself, if you just dotrimesh.load_path(sections)
it will give you aPath3D
object (or if you want to call the specific function, it’strimesh.path.io.misc.lines_to_path
). If you transform the sections onto the plane either manually or throughpath.to_planar
, It will then havepath.polygons_full
constructed for you.As for the result of
triangulate_polygon
, that looks correct- the vertices are 2D because it’s coming from a planar polygon, you just need tonp.column_stack
it with zeros to use it in a 3D mesh.