Edit: Recently Szabolcs released the new version of IGraphM (v0.2.0). Now the code below works pretty fine.
Let us imagine that we move polyhedron faces a bit:
name = "Icosahedron";
{poly, net} = PolyhedronData[name, {"Faces", "NetFaces"}];
Graphics3D[Normal@poly /.
Polygon@pts_ :> Polygon@Transpose[.9 Transpose@pts + .1 Mean@pts]]
Now we can construct a graph in the following way: each face corresponds to a triangle fan (gray lines below). The center vertex in the fan marks the face (black points). Initial faces have common vertices. They are marked by complete subgraphs (orange lines). We can construct this graph for the polyhedron and the net as well.
ids[p_] := FirstCase[p, _Polygon][[1]];
graph[p_] := Graph[#, VertexStyle -> _Integer -> Black] &@Flatten[{
Style[UndirectedEdge@##, Orange] & @@@ Subsets[#, {2}] & /@
GatherBy[Catenate@#, First],
Style[UndirectedEdge@##, Darker@Gray] & @@@ Partition[#, 2, 1, 1] & /@ #,
Style[UndirectedEdge[{##}, #2], Darker@Gray] & @@@ # & /@ #
}] &@MapIndexed[Thread@{#1, #2[[1]]} &, ids@p];
{netG, polyG} = graph /@ {net, poly};
{netCol, polyCol} = VertexList /@ {netG, polyG} /. {_Integer -> 1, {__Integer} -> 2};
netG
Graph3D[polyG, ViewAngle -> 0.3]
One can see that the first graph is the subgraph of the second one. We can find the subgraph isomorphism with IGraphM
package (thanks to Szabolcs and Kuba). If you don't have this package you can use this comprehensive list of definitions.
<< IGraphM`;
subisomorphism = First@Normal@
IGLADGetSubisomorphism[{netG, VertexColors -> netCol}, {polyG,
VertexColors -> polyCol}];
The following list is the face-to-face correspondence (bijection, similar to Kuba's fromNet
):
netToPoly[name, "Faces"] = Cases[#, _@__Integer] &@subisomorphism
(* {1 -> 1, 2 -> 12, 3 -> 5, 4 -> 3, 5 -> 15, 6 -> 14, 7 -> 18, 8 -> 7,
9 -> 11, 10 -> 9, 11 -> 2, 12 -> 20, 13 -> 4, 14 -> 13, 15 -> 17, 16 -> 16,
17 -> 8, 18 -> 6, 19 -> 19, 20 -> 10} *)
The following list is the vertex-to-vertex correspondence. Note, that several vertices of the net can correspond to one vertex of the polyhedron (it is surjection):
netToPoly[name, "Vertices"] =
Union@DeleteCases[#, _@__Integer][[;; , ;; , 1]] &@subisomorphism
(* {1 -> 12, 2 -> 12, 3 -> 12, 4 -> 12, 5 -> 12, 6 -> 8, 7 -> 2, 8 -> 4,
9 -> 6, 10 -> 10, 11 -> 8, 12 -> 3, 13 -> 7, 14 -> 11, 15 -> 5, 16 -> 1, 17 -> 3,
18 -> 9, 19 -> 9, 20 -> 9, 21 -> 9, 22 -> 9} *)
There are nice color visualizations of such a map in other answers. Let me do something new (see code below):
Firstly, I produce graphs of connected faces
faceGraph[g_Graph] :=
Graph@Cases[Tally@Cases[EdgeList@g, _[{_, i_}, {_, j_}] :> {i, j}],
{e_, 2} :> e];
netFG = faceGraph@netG;
polyFG = Graph[EdgeList@faceGraph@polyG /. Reverse /@ netToPoly[name, "Faces"]];
root = Last@GraphCenter@netFG;
{Graph[netFG, VertexLabels -> "Name"],
Graph[polyFG, VertexLabels -> "Name"]} // GraphicsRow
Then, I do some geometry which is similar to skeletal animation in computer graphics
net3D = MapAt[N@# /. {p__Real} :> {p, 0.} &, net, 1];
netFaces = Flatten@N@Normal@net3D;
polyFaces = Flatten[N@Normal@poly][[Sort[netToPoly[name, "Faces"]][[;; , 2]]]];
children = GroupBy[
DeleteCases[Thread[DepthFirstScan[netFG, root] -> VertexList@netFG],
root -> root], First -> Last];
ClearAll[fold, rotate, anchor]
polyVertexIDs[fID_] := ids[poly][[fID /. netToPoly[name, "Faces"]]];
commonNetVertexIDs[fID1_, fID2_] :=
ids[net][[fID1]] ⋂ ids[net][[fID2]];
commonPolyVertexIDs[fID1_, fID2_] :=
commonNetVertexIDs[fID1, fID2] /. netToPoly[name, "Vertices"];
anchor[fID1_, fID2_] :=
Sequence @@ {#2 - #, #} & @@ net3D[[1, commonNetVertexIDs[fID1, fID2]]];
maxAngle[fID1_, fID2_] :=
ArcTan[Cross[#2, #].Cross[#, #3], #.Cross@##2] &[
Normalize[#2 - #], #3 - #, #4 - #] & @@
N@poly[[1, {#[[1]], #[[2]], Complement[polyVertexIDs@fID1, #][[1]],
Complement[polyVertexIDs@fID2, #][[1]]}]] &@
commonPolyVertexIDs[fID1, fID2];
rotate[parentID_, childID_, t_] :=
GeometricTransformation[fold[t, childID],
RotationTransform[t maxAngle[parentID, childID], anchor[parentID, childID]]];
fold[t_, id_: root] := {netFaces[[id]],
If[Head@# === Missing, {}, rotate[id, #, t] & /@ #]} &@children@id;
Manipulate[
Graphics3D[fold[t],
PlotRange -> {MinMax@net[[1, ;; , 1]], MinMax@net[[1, ;; , 2]], {-0.5, 2.5}},
Boxed -> False, ImageSize -> 700, ViewVector -> {0, -100, 30}], {t, -1, 1}]
The same for "RhombicHexecontahedron"
: