from scipy.spatial import ConvexHull, QhullError
from ddg.datastructures.halfedge.get import get_edge_loop
from ddg.optimize.he.functional import HalfEdgeFunctional
[docs]class PlanarFacesEnergy(HalfEdgeFunctional):
"""
Measures the non-planarity of the faces of a discrete surface using their volume.
"""
def __init__(self, surface, attr_name, attr_dimension=None, boundary_cells=set()):
super().__init__(
surface,
attr_name,
"verts",
attr_dimension=attr_dimension,
boundary_cells=boundary_cells,
)
[docs] def evaluate(self, x):
"""
The evaluate function creates a convex hull for each face using
scipy.spatial.ConvexHull which uses the Qhull algorithm (qhull.org) and
then evaluates the volume of each face. The errors in the Qhull
algorithm each start with the ID "QH6...". "QH6154" refers to the error
where the inputs for the convex hull are already planar. In this
method, this specific error is bypassed for obvious reasons.
"""
E = 0
for face in self.surface.faces:
vertices = []
for edge in get_edge_loop(face.edge):
i = edge.tail
coordinate = (
x[i.interior_cell_index]
if i.interior_cell_index is not None
else getattr(i, self.attr_name)
)
vertices.append(coordinate)
try:
hull = ConvexHull(vertices)
E += hull.volume**2
except QhullError as e:
if str(e)[0:6] != "QH6154":
raise
else:
continue
return E