13

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?

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
Rainer
  • 2,891
  • 19
  • 34

3 Answers3

12

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]

New convex hull

Taiki
  • 5,259
  • 26
  • 34
  • It doesn't quite work well for "Cube" instead of "Dodecahedron". The face vertices are not well ordered. – Szabolcs Oct 14 '15 at 13:08
  • 1
    In principle, two distinct faces of a polyhedron can have the same normal. But that will never happen if the polyhedron is a convex hull. So the idea should work well. – Szabolcs Oct 14 '15 at 13:11
  • Yes, I do rely on that assumption. – Taiki Oct 14 '15 at 13:12
  • I'm coding proper sort now... – Taiki Oct 14 '15 at 13:13
  • DONE! The code should work with anything now. Thank you @Szabolcs. – Taiki Oct 14 '15 at 13:19
  • 1
    @Taiki. NICE work thanks for putting this online.... – Rainer Oct 14 '15 at 16:03
  • @Taiki Your solution seems to only work for named polyhedron. If it is a random polyhedron, it does not seem to work. For example if you set v = 20;randomPoints = RandomReal[{-1, 1}, {v, 3}];convexhull = ConvexHullMesh[randomPoints];. – Teg Louis Sep 04 '23 at 02:03
  • @TegLouis Hmm weird. The code with your convexhull still works on my machine running Mathematica 13.1. – Taiki Sep 22 '23 at 04:09
  • Yeah, I am noticing that the wolframcloud version is not ideal for many reasons. – Teg Louis Sep 22 '23 at 17:23
5

Here is a solution that uses undocumented functionality to generate an appropriate MeshRegion[] object:

Graphics`Mesh`MeshInit[];
FirstCase[ConvexHull3D[N[PolyhedronData["Dodecahedron", "VertexCoordinates"]],
                       FlatFaces -> False], 
          GraphicsComplex[pts_, stuff_] :>
          MeshRegion[pts, Cases[stuff, _Polygon, ∞]], ∞]

dodecahedron as a MeshRegion[]

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
4

Somewhere around version 12+ ConvexHullMesh now returns the desired output out of the box:

ConvexHullMesh[N[PolyhedronData["Dodecahedron", "VertexCoordinates"]]]

If you're not on a recent enough version you can use Region`Mesh`MergeCells:

tris = RegionBoundary[DelaunayMesh[N[PolyhedronData["Dodecahedron", "VertexCoordinates"]]]]

Region`Mesh`MergeCells[tris]

Greg Hurst
  • 35,921
  • 1
  • 90
  • 136
  • Will that work for an unnamed polyhedron? Like for when using RandomPolyhedron? I will check when I get home. – Teg Louis Sep 05 '23 at 16:04
  • 1
    I would think so. – Greg Hurst Sep 05 '23 at 17:42
  • 1
    For wolfram cloud, it didn't work for an unnamed polygon. And the documentation for "PolyhedronData" says under possible issues that "Using nonstandard polyhedron names will not work". (I think this was a weird choice on Mathematica's part.) But I found out that PolyhedronCoordinates[RandomPolyhedron[{"ConvexHull", v}]] works where v is the number of vertices. While it doesn't use the term "ConvexHullMesh". I think it is worth noting this for this question since it is very related. – Teg Louis Sep 06 '23 at 00:24