I have a triangulated mesh that I generated with the Delaunay 3D function in PyVista. I would like to calculate the surface area of the mesh adding up the areas of all the triangles. Is there a way to obtain the indices of the simplices triangles from the delaunay result?
import pyvista as pv
cloud = pv.PolyData(points)
volume = cloud.delaunay_3d(alpha = 2.5)
shell = volume.extract_geometry()
shell.plot()
I know I can do it with Scipy but for whatever reason Scipy generates an incorrect mesh (and does not have attributes I can adjust in the Delaunay method):
from scipy.spatial import Delaunay
tri = Delaunay(points)
print(tri.simplices)
[[386 466 377 613]
[159 386 377 613]
[159 386 466 613]
...
[696 709 695 691]
[696 710 711 691]
[696 697 711 691]]
My goal is to loop through the triangles and calculate the surface area of the mesh.
PyVista PolyData
objects already have an area
property that adds up the cell areas.
For example, consider random points on the unit sphere:
import numpy as np
import pyvista as pv
# random point cloud on a unit sphere
rng = np.random.default_rng()
N = 1000 # points
thetas = rng.random(N)*np.pi
phis = rng.random(N)*2*np.pi
points = np.array([
np.sin(thetas)*np.cos(phis),
np.sin(thetas)*np.sin(phis),
np.cos(thetas),
]).T
# triangulate and compute total area
mesh = pv.PolyData(points)
triangulated = mesh.delaunay_3d().extract_surface()
print(triangulated.area, 4*np.pi)
For me this printed
12.47386243049973 12.566370614359172
The first value is the total area of our triangulated point cloud on a sphere, and the second value is the exact surface of a perfect unit sphere. Looks good.
Additionally, there are other similar attributes, for instance volume
for watertight surfaces (which you have):
>>> print(triangulated.volume, 4/3*np.pi)
4.127984347614561 4.1887902047863905
In other words, you don't need the vertex indices if you're only looking for the total area.
(If you do still want the vertices, the information is accessible via triangulated.faces
. My recommendation would be to look at triangulated.faces.reshape(-1, 4)[:, 1:]
which is a 2d array of shape (n_cells, 3)
, where each row corresponds to a given triangle and the three integers in the row are the indices of the three points forming the corresponding triangle.)