[Math] How would you make a (physical) dodecahedron with edges instead of faces

polyhedrasolid-geometry

Call this a "math problem disguised as a woodworking problem" or vice versa.

Background: You can construct a dodecahedron by cutting 12 identical, regular pentagon faces, beveling all the edges of these to half the dihedral angle and gluing them all together. The joints become the edges. Where 3 faces meet, you have the vertex. Simple enough.

Now let's say you want to build a dodecahedron, but instead of boards for the faces, you want the boards to be the edges. Three edges come together at each vertex, etc.

Relative to some dimension of the board itself, how would you determine/describe the two planes you'd cut/mill at the end of each board in order to allow the three boards to meet and be correctly oriented in three dimensions? Let's say you want one surface of the board to split the dihedral. (i.e. boards are halfway between being coplanar with the 2 faces on either side.)

I've been over at Wolfram banging my head on this for way too long. It's time to ask smarter folks.

Best Answer

This is a very interesting question, and I think I understand what ipmcc has in mind. There's a lot of Mathematica code involved in generating these images, so I'll put that at the end.

The first thing to understand is "boards are halfway between being coplanar with the 2 faces on either side". If I understand things correctly, the placement of a board with respect to the dodecahedron should look something like this: dodecahedron and board

With all of the boards, we should have one new face for every old edge. "What polyhedron has a face for every edge of an original one?" has been asked and answered in Is there such a thing as the "edge-face dual" of a polyhedron, and is the "edge-face dual" of a cube a rhombic dodecahedron?: It's the dual of the rectified polyhedron. A rectified dodecahedron is an icosidodecahedron, and the dual of that is a rhombic triacontahedron (with 30 golden rhombus faces). If we draw a triacontahedron on the outside of our dodecahedron, we get something like the following: tricontahedron and board

The problem is that that doesn't really look anything like "conceptually close" to the link @TonyK posted in a comment. We don't want the maximum possible piece of each board (a golden rhombus), we just want a sliver of each rhombus around the edges of the original dodecahedron. I think the intent was for something that looks like this (possibly with less wide slivers): slivers

However, the hexagons in that image are infinitely thin, whereas the question referred to "woodworking" and "beveling"; we need to thicken them up. We can't just thicken them naively because of the dihedral angles. They need to be frusta: beveled so they're part of a hexagonal pyramid with "top vertex" at the center of the figure. It should look something like this: frusta

By symmetry, you only need to build 30 copies of the same frustum. Fixing a length for the long diagonal, a frustum depends on two parameters. Let t be a parameter ranging from 0 to 1 where 0 means you have a whole golden rhombus face and 1 means you have just a line segment that is an edge of the dodecahedron (interpolating linearly). Let s be a parameter ranging from 0 to 1 where 0 means you have the whole pyramid and 1 means you have just the hexagon (interpolating linearly). Then the image with the flat hexagons had t=0.85 and s=1, and the image with the solid frusta had t=s=0.9. To see the effects of changing t and s qualitatively, here is a Youtube animation of the whole dodecahedron as t and s are changed, and here is a Youtube animation of just one frustum.

In sloppy Mathematica notation, where phi is the golden ratio $\varphi=\frac{1+\sqrt{5}}{2}$, and s and t are the parameters just described, the following is a list of faces of a single frustum (of long face diagonal length $\frac{2}{\varphi}$), where each face is a list of vertices (in a right-hand-rule order around the face), and each vertex is is a triple of x, y, z coordinates:

{
{{t - phi t, phi, 1 - t}, 
 {(-1 + phi) t, phi, 1 - t}, 
 {-1 + phi, phi, 0},
 {(-1 + phi) t, phi, -1 + t},
 {t - phi t, phi, -1 + t},
 {1 - phi, phi, 0}}, 
{{s - phi s, phi s, 0},
 {-(-1 + phi) s t, phi s, s (-1 + t)},
 {(-1 + phi) s t, phi s, s (-1 + t)},
 {(-1 + phi) s, phi s, 0},
 {(-1 + phi) s t, phi s, s - s t},
 {-(-1 + phi) s t, phi s, s - s t}}, 
{{s - phi s, phi s, 0},
 {1 - phi, phi, 0},
 {t - phi t, phi, -1 + t},
 {-(-1 + phi) s t, phi s, s (-1 + t)}}, 
{{-(-1 + phi) s t, phi s, s (-1 + t)},
 {t - phi t, phi, -1 + t},
 {(-1 + phi) t, phi, -1 + t},
 {(-1 + phi) s t, phi s, s (-1 + t)}},
{{(-1 + phi) s t, phi s, s (-1 + t)},
 {(-1 + phi) t, phi, -1 + t},
 {-1 + phi, phi, 0},
 {(-1 + phi) s, phi s, 0}},
{{(-1 + phi) s, phi s, 0},
 {-1 + phi, phi, 0},
 {(-1 + phi) t, phi, 1 - t},
 {(-1 + phi) s t, phi s, s - s t}},
{{(-1 + phi) s t, phi s, s - s t},
 {(-1 + phi) t, phi, 1 - t},
 {t - phi t, phi, 1 - t},
 {-(-1 + phi) s t, phi s, s - s t}},
{{-(-1 + phi) s t, phi s, s - s t},
 {t - phi t, phi, 1 - t},
 {1 - phi, phi, 0},
 {s - phi s, phi s, 0}}
}

The angles of the outer hexagon are $\tan^{-1}2\approx 63.43^{\circ}$ and $720^{\circ}-2\tan^{-1}2\approx 148.28^{\circ}$. The dihedral angle between the larger hexagon and one of the four smaller (assuming t near 1) trapezoidal faces is exactly $72^{\circ}$. However, the dihedral angle between the larger hexagon and one of the two bigger (assuming t near 1) trapezoidal faces depends on t. It's $\approx86.07^{\circ}$ for t=0.9, and in general is given by $$\cos^{-1}\left(\frac{\left(3-\sqrt{5}\right)\left(1+\sqrt{5}\right)\left(1-t\right)}{4*\sqrt{t^2+\frac{1}{2}\left(3-\sqrt{5}\right)\left(1-t\right)^{2}}}\right)$$

If you happen to have Mathematica 7 or above (the code might also work in 6), here is most of the code (with some scaffolding removed and some comments added) for generating the images and formulae referenced above. I make no promises about elegance or efficiency.

(*The Golden Ratio Phi is important*)
p = (1 + Sqrt[5])/2;
(*Coordinates and grouping from the Wikipedia article for \
dodecahedron.*)
groupedvs = {{{1, 1, -1}, {1, 1, 1}, {1, -1, 1}, {1, -1, -1}, {-1, 
     1, -1}, {-1, 1, 1}, {-1, -1, 1}, {-1, -1, -1}}, {{0, 1/p, 
     p}, {0, -1/p, p}, {0, 1/p, -p}, {0, -1/p, -p}}, {{1/p, p, 
     0}, {1/p, -p, 0}, {-1/p, p, 0}, {-1/p, -p, 0}}, {{p, 0, 1/p}, {p,
      0, -1/p}, {-p, 0, 1/p}, {-p, 0, -1/p}}};
(*Normal vectors to two adjacent faces.*)
n2 = -Cross[{1/p, p, 0} - {1, 1, 1}, {0, 1/p, p} - {1, 1, 1}]; 
n3 = Cross[{-1/p, p, 0} - {1/p, p, 0}, {1, 1, -1} - {1/p, p, 0}]; 
(*A flat list of vertices of the dodecahedron which should be easier to work with.*)
vs = Flatten[groupedvs, 1];
(*A list of lists of vertex indices to represent the 12 faces of the \
dodecahedron.*)
faces = {{12, 4, 14, 16, 8}, {18, 4, 12, 11, 1}, {12, 8, 20, 5, 
    11}, {8, 16, 7, 19, 20}, {20, 19, 6, 15, 5}, {19, 7, 10, 9, 
    6}, {15, 6, 9, 2, 13}, {5, 15, 13, 1, 11}, {13, 2, 17, 18, 1}, {2,
     9, 10, 3, 17}, {17, 3, 14, 4, 18}, {3, 10, 7, 16, 14}}; 
(*Show the "board" and the vertices of the dodecahedron and the faces \
of the dodecahedron.*)Show[(*Plot the vertices.*)
 ListPointPlot3D[groupedvs,(*Color the vertices like on Wikipedia.*)
  PlotStyle -> {Directive[Orange, PointSize[0.05]], 
    Directive[Green, PointSize[0.05]], 
    Directive[Blue, PointSize[0.05]], 
    Directive[Red, PointSize[0.05]]}, 
  AxesLabel -> {x, y, 
    z}],(*Plot the board using the fact that the sum of the two \
normals for the adjacent faces should give a normal right in between.*)
 ContourPlot3D[
  Dot[n3 + n2, {x - 1/p, y - p, z}] == 0, {x, -1, 1}, {y, 0, 
   2 p}, {z, -p, p}, ContourStyle -> Opacity[0.5], Mesh -> False], 
 Graphics3D[(*A sequence of polygons*)
  Polygon[(*where for every element of "faces"*)
   MapThread[(*we make a list of all five corresponding vertices.*)
    Table[vs[[(#1[[j]])]], {j, 1, 
       5}] &, {faces}]]](*Finally, make sure Mathematica doesn't \
squish the image.*), BoxRatios -> Automatic]
(*For later images, we'll need indices for the vertices that make up \
each edge of the dodecahedron.*)
edges = {{5, 11}, {11, 1}, {1, 13}, {13, 15}, {15, 5}, {1, 18}, {18, 
    4}, {4, 12}, {12, 11}, {13, 2}, {2, 17}, {17, 18}, {15, 6}, {6, 
    9}, {9, 2}, {9, 10}, {10, 3}, {3, 17}, {6, 19}, {19, 7}, {7, 
    10}, {19, 20}, {20, 8}, {8, 16}, {16, 7}, {20, 5}, {8, 12}, {14, 
    16}, {14, 4}, {14, 3}};
(*We also could use a raw list of faces for the rhombic \
tricontahedron where each face is a list of vertices in some cyclic \
order.*)purerhombic = {{{0, 1/2 (1 + Sqrt[5]), -1}, {0, 
     1/2 (-1 + Sqrt[5]), 1/2 (-1 - Sqrt[5])}, {-1, 0, 
     1/2 (-1 - Sqrt[5])}, {-1, 1, -1}}, {{1, 1, -1}, {0, 
     1/2 (1 + Sqrt[5]), -1}, {0, 1/2 (-1 + Sqrt[5]), 
     1/2 (-1 - Sqrt[5])}, {1, 0, 1/2 (-1 - Sqrt[5])}}, {{1, 
     1, -1}, {0, 1/2 (1 + Sqrt[5]), -1}, {1/2 (-1 + Sqrt[5]), 
     1/2 (1 + Sqrt[5]), 0}, {1/2 (1 + Sqrt[5]), 1, 
     0}}, {{1/2 (1 - Sqrt[5]), 1/2 (1 + Sqrt[5]), 0}, {0, 
     1/2 (1 + Sqrt[5]), -1}, {1/2 (-1 + Sqrt[5]), 1/2 (1 + Sqrt[5]), 
     0}, {0, 1/2 (1 + Sqrt[5]), 1}}, {{1/2 (1 - Sqrt[5]), 
     1/2 (1 + Sqrt[5]), 0}, {0, 1/2 (1 + Sqrt[5]), -1}, {-1, 
     1, -1}, {1/2 (-1 - Sqrt[5]), 1, 0}}, {{1, 
     1, -1}, {1/2 (1 + Sqrt[5]), 1, 0}, {1/2 (1 + Sqrt[5]), 0, 
     1/2 (1 - Sqrt[5])}, {1, 0, 
     1/2 (-1 - Sqrt[5])}}, {{1/2 (1 + Sqrt[5]), 0, 
     1/2 (1 - Sqrt[5])}, {1/2 (1 + Sqrt[5]), -1, 0}, {1, -1, -1}, {1, 
     0, 1/2 (-1 - Sqrt[5])}}, {{1, -1, -1}, {0, 
     1/2 (-1 - Sqrt[5]), -1}, {0, 1/2 (1 - Sqrt[5]), 
     1/2 (-1 - Sqrt[5])}, {1, 0, 1/2 (-1 - Sqrt[5])}}, {{1, 0, 
     1/2 (-1 - Sqrt[5])}, {0, 1/2 (-1 + Sqrt[5]), 
     1/2 (-1 - Sqrt[5])}, {-1, 0, 1/2 (-1 - Sqrt[5])}, {0, 
     1/2 (1 - Sqrt[5]), 1/2 (-1 - Sqrt[5])}}, {{1/2 (-1 + Sqrt[5]), 
     1/2 (1 + Sqrt[5]), 0}, {1/2 (1 + Sqrt[5]), 1, 0}, {1, 1, 1}, {0, 
     1/2 (1 + Sqrt[5]), 1}}, {{1/2 (1 + Sqrt[5]), 1, 0}, {1, 1, 
     1}, {1, 0, 1/2 (1 + Sqrt[5])}, {1/2 (1 + Sqrt[5]), 0, 
     1/2 (-1 + Sqrt[5])}}, {{1/2 (1 + Sqrt[5]), 0, 
     1/2 (1 - Sqrt[5])}, {1/2 (1 + Sqrt[5]), 1, 
     0}, {1/2 (1 + Sqrt[5]), 0, 
     1/2 (-1 + Sqrt[5])}, {1/2 (1 + Sqrt[5]), -1, 
     0}}, {{1/2 (1 - Sqrt[5]), 1/2 (1 + Sqrt[5]), 0}, {0, 
     1/2 (1 + Sqrt[5]), 1}, {-1, 1, 1}, {1/2 (-1 - Sqrt[5]), 1, 
     0}}, {{0, 1/2 (1 + Sqrt[5]), 1}, {0, 1/2 (-1 + Sqrt[5]), 
     1/2 (1 + Sqrt[5])}, {-1, 0, 1/2 (1 + Sqrt[5])}, {-1, 1, 1}}, {{1,
      1, 1}, {0, 1/2 (1 + Sqrt[5]), 1}, {0, 1/2 (-1 + Sqrt[5]), 
     1/2 (1 + Sqrt[5])}, {1, 0, 1/2 (1 + Sqrt[5])}}, {{0, 
     1/2 (1 - Sqrt[5]), 1/2 (1 + Sqrt[5])}, {-1, 0, 
     1/2 (1 + Sqrt[5])}, {0, 1/2 (-1 + Sqrt[5]), 
     1/2 (1 + Sqrt[5])}, {1, 0, 1/2 (1 + Sqrt[5])}}, {{0, 
     1/2 (1 - Sqrt[5]), 1/2 (1 + Sqrt[5])}, {1, 0, 
     1/2 (1 + Sqrt[5])}, {1, -1, 1}, {0, 1/2 (-1 - Sqrt[5]), 
     1}}, {{1/2 (1 + Sqrt[5]), 0, 
     1/2 (-1 + Sqrt[5])}, {1/2 (1 + Sqrt[5]), -1, 0}, {1, -1, 1}, {1, 
     0, 1/2 (1 + Sqrt[5])}}, {{-1, 0, 1/2 (1 + Sqrt[5])}, {-1, 1, 
     1}, {1/2 (-1 - Sqrt[5]), 1, 0}, {1/2 (-1 - Sqrt[5]), 0, 
     1/2 (-1 + Sqrt[5])}}, {{-1, -1, 1}, {-1, 0, 
     1/2 (1 + Sqrt[5])}, {1/2 (-1 - Sqrt[5]), 0, 
     1/2 (-1 + Sqrt[5])}, {1/2 (-1 - Sqrt[5]), -1, 0}}, {{0, 
     1/2 (1 - Sqrt[5]), 1/2 (1 + Sqrt[5])}, {-1, 0, 
     1/2 (1 + Sqrt[5])}, {-1, -1, 1}, {0, 1/2 (-1 - Sqrt[5]), 
     1}}, {{1/2 (-1 - Sqrt[5]), -1, 0}, {1/2 (-1 - Sqrt[5]), 0, 
     1/2 (1 - Sqrt[5])}, {1/2 (-1 - Sqrt[5]), 1, 
     0}, {1/2 (-1 - Sqrt[5]), 0, 
     1/2 (-1 + Sqrt[5])}}, {{1/2 (-1 - Sqrt[5]), -1, 
     0}, {1/2 (-1 - Sqrt[5]), 0, 1/2 (1 - Sqrt[5])}, {-1, 0, 
     1/2 (-1 - Sqrt[5])}, {-1, -1, -1}}, {{0, 
     1/2 (-1 - Sqrt[5]), -1}, {1/2 (1 - Sqrt[5]), 1/2 (-1 - Sqrt[5]), 
     0}, {1/2 (-1 - Sqrt[5]), -1, 
     0}, {-1, -1, -1}}, {{1/2 (1 - Sqrt[5]), 1/2 (-1 - Sqrt[5]), 
     0}, {1/2 (-1 - Sqrt[5]), -1, 0}, {-1, -1, 1}, {0, 
     1/2 (-1 - Sqrt[5]), 1}}, {{-1, 1, -1}, {-1, 0, 
     1/2 (-1 - Sqrt[5])}, {1/2 (-1 - Sqrt[5]), 0, 
     1/2 (1 - Sqrt[5])}, {1/2 (-1 - Sqrt[5]), 1, 0}}, {{0, 
     1/2 (-1 - Sqrt[5]), -1}, {0, 1/2 (1 - Sqrt[5]), 
     1/2 (-1 - Sqrt[5])}, {-1, 0, 
     1/2 (-1 - Sqrt[5])}, {-1, -1, -1}}, {{0, 
     1/2 (-1 - Sqrt[5]), -1}, {1/2 (1 - Sqrt[5]), 1/2 (-1 - Sqrt[5]), 
     0}, {0, 1/2 (-1 - Sqrt[5]), 1}, {1/2 (-1 + Sqrt[5]), 
     1/2 (-1 - Sqrt[5]), 0}}, {{1, -1, -1}, {1/2 (1 + Sqrt[5]), -1, 
     0}, {1/2 (-1 + Sqrt[5]), 1/2 (-1 - Sqrt[5]), 0}, {0, 
     1/2 (-1 - Sqrt[5]), -1}}, {{1/2 (1 + Sqrt[5]), -1, 0}, {1, -1, 
     1}, {0, 1/2 (-1 - Sqrt[5]), 1}, {1/2 (-1 + Sqrt[5]), 
     1/2 (-1 - Sqrt[5]), 0}}};
(*If we want to plot this, we need to tell Mathematica these faces \
are polygons command throughout.*)
rhombic = MapThread[Polygon[#1] &, {purerhombic}];
Show[ListPointPlot3D[groupedvs, 
  PlotStyle -> {Directive[Orange, PointSize[0.05]], 
    Directive[Green, PointSize[0.05]], 
    Directive[Cyan, PointSize[0.05]], 
    Directive[Pink, PointSize[0.05]]}, AxesLabel -> {x, y, z}], 
 ContourPlot3D[
  Dot[n3 + n2, {x - 1/p, y - p, z}] == 0, {x, -1, 1}, {y, 0, 
   2 p}, {z, -p, p}, ContourStyle -> Opacity[0.5], Mesh -> False], 
 Graphics3D[{Purple, 
   Thickness[
    0.015],(*This time we have lines consisting of pairs of vertex \
indices, not polygons consisting of quintuples of indices.*)
   Line[MapThread[Table[vs[[(#1[[j]])]], {j, 1, 2}] &, {edges}]]}], 
 Graphics3D[rhombic], BoxRatios -> Automatic]
(*To make parametrized hexagons, we need to make sure the lists of \
four vertices for each rhombus begin consistently with a large angle \
vertex. The length of a short diagonal is 2/phi which is about 1.2, \
and the length of a long diagonal is 2. Therefore, the following will \
reorder things appropriately.*)
rhombicorderedfaces = 
  MapThread[
   If[Norm[N[#1[[1]] - #1[[3]]]] > 
      1.5, {#1[[2]], #1[[3]], #1[[4]], #1[[1]]}, #1] &, \
{purerhombic}];
(*With a bit of geometry, we can see how to build parametrized \
hexagons now.*)
parametrizedrhombic[t_] := 
 MapThread[{#1[[1]], t*#1[[1]] + (1 - t)*#1[[2]], 
    t*#1[[3]] + (1 - t)*#1[[2]], #1[[3]], t*#1[[3]] + (1 - t)*#1[[4]],
     t*#1[[1]] + (1 - t)*#1[[4]]} &, {rhombicorderedfaces}]
(*To have something to plot, we can use the polygon command again.*)
pararhombic[t_] := MapThread[Polygon[#1] &, {parametrizedrhombic[t]}];
(*t = .85 seems like a fine start.*) 
Show[
  Graphics3D[pararhombic[85/100], Axes -> True], 
  BoxRatios -> Automatic]
(*Next we make solid frusta.*)
listofsolidhexes[t_, s_] := 
 MapThread[(*We need to flatten because I don't want to type out all \
six faces around.*)
  Flatten[{(*The extra braces on the top and bottom faces ensure that \
flatten yields the right result.*){#1}, {s*#1}, 
     Table[{s*#1[[i]], #1[[i]], #1[[6 - Mod[-(i + 1), 6]]], 
       s*#1[[6 - Mod[-(i + 1), 6]]]}, {i, 1, 6}]}, 
    1] &, {parametrizedrhombic[t]}]
(*For the purposes of plotting, it doesn't matter which polygonal \
face belongs to which frustum.*)
listofpolysforsolidhexes[t_, s_] := Flatten[listofsolidhexes[t, s], 1]
(*For the purposes of plotting, we need polygon commands.*)
polylistofpolys[t_, s_] := 
  MapThread[Polygon[#1] &, {listofpolysforsolidhexes[t, s]}];
(*To really see what's going on, we use Manipulate to let us modify t \
and s easily. For t=0.5 and s=1, we essentially have a pentatruncated \
rhombic triacontahedron, which is similar to, but distinct from, a \
European football shape.*)
Manipulate[
 Graphics3D[polylistofpolys[t, s], Boxed -> False], {{t, .9}, 0, 
  1}, {{s, .9}, 0, 1}]
(*If we only need to look at one piece:*)
Manipulate[
 Show[Graphics3D[
   MapThread[
    Polygon[#1] &, {listofsolidhexes[t, 
       s][[(*4 is the index that gives the frustum attached to the \
board in the early images.*)4]]}]], BoxRatios -> Automatic], {{t, .9},
   0, 1}, {{s, .95}, 0, 1}]
(*The raw data for that single frustum:*)
listofsolidhexes[t, s][[4]]