How would you make a (physical) dodecahedron with edges instead of faces?
Solution 1:
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:
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:
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):
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:
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]]