Skip to content

Commit 6e1bc67

Browse files
CopilotLicini
andcommitted
Replace volume_polyhedron with signed volume approach for non-convex support
- volume_polyhedron only works for convex meshes (as per its documentation) - Implemented signed volume of tetrahedra approach which works for both convex and non-convex meshes - Removed volume_polyhedron import, added dot_vectors import - Updated CHANGELOG.md to document the new volume() method - All tests pass with same accuracy Co-authored-by: Licini <17893605+Licini@users.noreply.github.com>
1 parent c88b6e8 commit 6e1bc67

File tree

2 files changed

+28
-6
lines changed

2 files changed

+28
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
* Added `compas_rhino.install_with_pip` with corresponding command line utility `install_in_rhino`.
1313
* Added support for `.stp` file extension in addition to `.step` for `RhinoBrep.from_step()` and `RhinoBrep.to_step()` methods.
14+
* Added `volume()` method to `compas.datastructures.Mesh` for computing the volume of closed meshes using signed volume of triangles.
1415

1516
### Changed
1617

src/compas/datastructures/mesh/mesh.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from compas.geometry import distance_line_line
4343
from compas.geometry import distance_point_plane
4444
from compas.geometry import distance_point_point
45+
from compas.geometry import dot_vectors
4546
from compas.geometry import length_vector
4647
from compas.geometry import midpoint_line
4748
from compas.geometry import normal_polygon
@@ -52,7 +53,6 @@
5253
from compas.geometry import sum_vectors
5354
from compas.geometry import transform_points
5455
from compas.geometry import vector_average
55-
from compas.geometry import volume_polyhedron
5656
from compas.itertools import linspace
5757
from compas.itertools import pairwise
5858
from compas.itertools import window
@@ -3920,12 +3920,33 @@ def volume(self):
39203920
# Unify cycles to ensure consistent face orientation
39213921
mesh_copy.unify_cycles()
39223922

3923-
# Get vertices and faces from the unified copy
3924-
# Make a copy of vertices list since volume_polyhedron modifies it in place
3925-
vertices, faces = mesh_copy.to_vertices_and_faces()
3926-
vertices = [v[:] for v in vertices] # Deep copy of vertex coordinates
3923+
volume = 0.0
3924+
for fkey in mesh_copy.faces():
3925+
vertices = mesh_copy.face_vertices(fkey)
3926+
# Get coordinates for all vertices of the face
3927+
coords = [mesh_copy.vertex_coordinates(v) for v in vertices]
39273928

3928-
return abs(volume_polyhedron((vertices, faces)))
3929+
# Triangulate the face if it has more than 3 vertices
3930+
if len(coords) == 3:
3931+
triangles = [coords]
3932+
else:
3933+
# Use simple fan triangulation from first vertex
3934+
triangles = []
3935+
for i in range(1, len(coords) - 1):
3936+
triangles.append([coords[0], coords[i], coords[i + 1]])
3937+
3938+
# Calculate signed volume contribution from each triangle
3939+
for triangle in triangles:
3940+
# Signed volume of tetrahedron formed by triangle and origin
3941+
# V = (1/6) * (a · (b × c)) where a, b, c are the vertices
3942+
a, b, c = triangle
3943+
# Calculate cross product of b and c
3944+
bc = cross_vectors(b, c)
3945+
# Calculate dot product with a
3946+
vol = dot_vectors(a, bc) / 6.0
3947+
volume += vol
3948+
3949+
return abs(volume)
39293950

39303951
def centroid(self):
39313952
"""Calculate the mesh centroid.

0 commit comments

Comments
 (0)