The answer proposed by halmir is very efficient and will give a list featuring all the internal faces along with one face that represents the outer perimeter, but the outer face is not always at the same point in the list, and plotting the polygons sometimes results in obscuring some internal faces.
Consider the following graph,
g1 = AdjacencyGraph[{{0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 1,
0, 0, 0, 0, 1, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
0}, {1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0}, {1, 0, 0, 0, 0, 1, 0, 1,
0, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0}, {0, 0, 0, 1,
0, 1, 0, 0, 0, 0, 0, 1}, {0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, {0,
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
0, 0}, {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 1, 0}},
GraphLayout -> "PlanarEmbedding",
VertexCoordinates -> {{0.68, 0.88}, {0.84, 0.85}, {1.12,
0.89}, {0.33, 1.13}, {0.81, 0.33}, {0.43, 0.33}, {0.15,
1.13}, {0.96, 0.33}, {1.12, 0.33}, {1.12, 1.13}, {-0.12,
0.33}, {-0.12, 1.13}}]
The above algorithm will give
faces = FindFace[g1,GraphEmbedding[g1]];
coord = GraphEmbedding[g1];
Graphics[{EdgeForm[Directive[Black, Thick]],
Thread[{ColorData[3, "ColorList"][[;; Length[faces]]],
Polygon[coord[[#]]] & /@ faces}]}]
which has the polygons in such an order that you can't see all internal faces. The obvious solution (obvious after halmir pointed it out to me) is to remove the element with the largest area. But, as often happens to me, I had spent some time writing a code that does the same thing but much slower (because I didn't think halmir's code worked on the above graph).
The algorithm I propose should output the list of non-overlapping polygons from the input graph. The idea is to use FindCycles
to get a full list of cycles from the graph, then sort this list in terms of the resulting polygon area. We know that the smallest polygon is one we want to keep. Then we look at the rest of the polygons, keeping only those with zero overlap with the current list of faces. This is the slow step, because it uses RegionIntersection
to determine whether two polygons overlap.
I use a While
loop to make sure that we stop looking at the cycles once we have enough for a complete basis.
graphToFaces[graph_?PlanarGraphQ] := Module[{graphpoints, cycles, polygons, n},
graphpoints = GraphEmbedding[graph];
cycles =
Polygon[graphpoints[[#]]] & /@
FindCycle[graph, Max[Length /@ FindFundamentalCycles[graph]], All][[All, All, 2]];
cycles = SortBy[cycles, Area];
polygons = {cycles[[1]]};
n = 2;
While[Length@polygons < Length@FindFundamentalCycles@graph &&
n <= Length@cycles,
If[
And @@ (Area[Rationalize@cycles[[n]], Rationalize@ #]] === 0 & /@
polygons),
AppendTo[polygons, cycles[[n]]]
];
n++
];
First /@ (polygons /.
Thread[graphpoints -> Range@Length@graphpoints])
]
Applied to the problem above,
faces = graphToFaces[g1]
coord = GraphEmbedding[g1];
Graphics[{EdgeForm[Directive[Black, Thick]],
Thread[{ColorData[3, "ColorList"][[;; Length[faces]]],
Polygon[coord[[#]]] & /@ faces}]}]
(* {{5, 8, 2, 1}, {9, 8, 2, 3}, {2, 3, 10, 4, 1}, {5, 6, 7, 4,
1}, {11, 12, 7, 6}} *)