computational geometry - How do I get ConvexHullMesh to return polygons instead of triangle as surface mesh?
I would need to identify the types of regular polygons forming the surface of a convex hull of 3D points. If I e.g. take the following example of a regular polyhedron
ConvexHullMesh[N[PolyhedronData["Dodecahedron", "VertexCoordinates"]]]
The convex hull routine returns a triangulated mesh surface. Is there any simple way to convince Mathematica to return the surface as polyhedrons (in this case pentagons) instead of a triangulation.
To illustrate the issue further, e.g if one applies
MeshCells[ConvexHullMesh[N[PolyhedronData["Dodecahedron", "VertexCoordinates"]]], 2]
Mathematica only returns triangles.
If one applies
ConvexHullMesh[N[PolyhedronData["Dodecahedron", "VertexCoordinates"]]] // FullForm
There is the option "CoplanarityTolerance"
. But I do not know how to use it.
Any ideas?
Answer
The procedure groups triangles based on the same unit normal vector, then uses the vertices in each group to form a new polygon. The vertices are sorted in such a way that their polygon is not self-intersecting.
This method doesn't allow for coplanar tolerance. Triangles in the same group have the same unit normal vector determined to within the second argument of Round
(10^-5
here).
The sorting function sort
is modified from #48091, which is a 2D method. sort
uses the XY-projection of the points, unless they're colinear in X or Y.
sort[pts_] := Module[
{p, subspaceselector},
p = coord[[#]] & /@ pts;
subspaceselector = Which[
p[[1, 1]] == p[[2, 1]] == p[[3, 1]], Rest,
p[[1, 2]] == p[[2, 2]] == p[[3, 2]], Drop[#, {2}] &,
True, Most
];
SortBy[pts, N[ArcTan @@ subspaceselector[coord[[#]] - Mean[p]]] &]
];
unitnormal[verts_] := Round[
Normalize[Cross[verts[[2]] - verts[[1]], verts[[3]] - verts[[1]]]],
10^-5
];
convexhull = ConvexHullMesh[N[PolyhedronData["Dodecahedron", "VertexCoordinates"]]];
coord = MeshCoordinates[convexhull];
trivertices = Level[MeshCells[convexhull, 2], {-2}];
polysets = GatherBy[
trivertices,
unitnormal[Function[i, coord[[i]]] /@ #] &
];
polyvertices = Map[sort][Union @@ # & /@ polysets];
MeshRegion[coord, Polygon /@ polyvertices]
Comments
Post a Comment