6 * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $
7 ***************************************************************/
10 * \brief Computes an embedding of a graph with maximum external face.
11 * See paper "Graph Embedding with Minimum Depth and Maximum External
12 * Face" by C. Gutwenger and P. Mutzel (2004) for details.
14 * \author Thorsten Kerkhof
17 * This file is part of the Open Graph Drawing Framework (OGDF).
21 * See README.txt in the root directory of the OGDF installation for details.
24 * This program is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU General Public License
26 * Version 2 or 3 as published by the Free Software Foundation;
27 * see the file LICENSE.txt included in the packaging of this file
31 * This program is distributed in the hope that it will be useful,
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 * GNU General Public License for more details.
37 * You should have received a copy of the GNU General Public
38 * License along with this program; if not, write to the Free
39 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
40 * Boston, MA 02110-1301, USA.
42 * \see http://www.gnu.org/copyleft/gpl.html
43 ***************************************************************/
45 #include <ogdf/planarity/EmbedderMaxFace.h>
46 #include <ogdf/internal/planarity/ConnectedSubgraph.h>
47 #include <ogdf/internal/planarity/EmbedderMaxFaceBiconnectedGraphs.h>
51 void EmbedderMaxFace::call(Graph
& G
, adjEntry
& adjExternal
)
54 pAdjExternal
= &adjExternal
;
57 if (G
.numberOfNodes() <= 1)
59 if (G
.numberOfEdges() == 1)
61 edge e
= G
.firstEdge();
62 adjExternal
= e
->adjSource();
66 //HINT: Edges are directed from child to parent in BC-trees
67 pBCTree
= new BCTree(G
);
69 //base case of biconnected graph:
70 if (pBCTree
->bcTree().numberOfNodes() == 1)
72 NodeArray
<int> m_nodeLength(G
, 0);
73 EdgeArray
<int> m_edgeLength(G
, 1);
74 adjEntry m_adjExternal
;
75 EmbedderMaxFaceBiconnectedGraphs
<int>::embed(G
, m_adjExternal
, m_nodeLength
, m_edgeLength
);
76 adjExternal
= m_adjExternal
->twin();
82 //***************************************************************************/
83 //First step: calculate maximum face and node lengths
84 //***************************************************************************/
86 //Find root Block (root node is only node with out-degree of 0):
89 forall_nodes(n
, pBCTree
->bcTree())
98 //compute block graphs and SPQR trees:
99 blockG
.init(pBCTree
->bcTree());
100 nBlockEmbedding_to_nH
.init(pBCTree
->bcTree());
101 eBlockEmbedding_to_eH
.init(pBCTree
->bcTree());
102 nH_to_nBlockEmbedding
.init(pBCTree
->bcTree());
103 eH_to_eBlockEmbedding
.init(pBCTree
->bcTree());
104 nodeLength
.init(pBCTree
->bcTree());
105 cstrLength
.init(pBCTree
->bcTree());
106 spqrTrees
.init(pBCTree
->bcTree(),0);
107 computeBlockGraphs(rootBlockNode
, 0);
109 //Bottom-Up-Traversal:
111 forall_adj_edges(e
, rootBlockNode
)
113 node cT
= e
->source();
114 node cH
= pBCTree
->cutVertex(cT
, rootBlockNode
);
115 node cB
= nH_to_nBlockEmbedding
[rootBlockNode
][cH
];
117 //set length of v in block graph of root block node:
118 int length_v_in_rootBlock
= 0;
120 forall_adj_edges(e2
, cT
)
122 //check if edge is an incoming edge:
123 if (e2
->target() != cT
)
126 node blockNode
= e2
->source();
127 node cutVertex
= pBCTree
->cutVertex(cT
, blockNode
);
128 length_v_in_rootBlock
+= constraintMaxFace(blockNode
, cutVertex
);
130 nodeLength
[rootBlockNode
][cB
] = length_v_in_rootBlock
;
133 node bT_opt
= G
.chooseNode(); //= G.chooseNode() only to get rid of warning
135 maximumFaceRec(rootBlockNode
, bT_opt
, ell_opt
);
138 //****************************************************************************
139 //Second step: Embed G by expanding a maximum face in bT_opt
140 //****************************************************************************
142 treeNodeTreated
.init(pBCTree
->bcTree(), false);
147 G
.sort(v
, newOrder
[v
]);
149 forall_nodes(v
, pBCTree
->bcTree())
156 void EmbedderMaxFace::computeBlockGraphs(const node
& bT
, const node
& cH
)
160 forall_adj_edges(e
, bT
)
162 if (e
->source() == bT
)
165 node cT
= e
->source();
167 forall_adj_edges(e2
, cT
)
169 if (e2
->source() == cT
)
171 node cH2
= pBCTree
->cutVertex(cT
, e2
->source());
172 computeBlockGraphs(e2
->source(), cH2
);
179 m_cH
= pBCTree
->cutVertex(bT
->firstAdj()->twinNode(), bT
);
180 ConnectedSubgraph
<int>::call(pBCTree
->auxiliaryGraph(), blockG
[bT
], m_cH
,
181 nBlockEmbedding_to_nH
[bT
], eBlockEmbedding_to_eH
[bT
],
182 nH_to_nBlockEmbedding
[bT
], eH_to_eBlockEmbedding
[bT
]);
183 nodeLength
[bT
].init(blockG
[bT
], 0);
184 cstrLength
[bT
].init(blockG
[bT
], 0);
185 if ( !blockG
[bT
].empty()
186 && blockG
[bT
].numberOfNodes() != 1
187 && blockG
[bT
].numberOfEdges() > 2)
189 spqrTrees
[bT
] = new StaticSPQRTree(blockG
[bT
]);
194 int EmbedderMaxFace::constraintMaxFace(const node
& bT
, const node
& cH
)
196 //forall (v \in B, v \neq c) do:
197 // length_B(v) := \sum_{(v, B') \in B} ConstraintMaxFace(B', v);
199 forall_adj_edges(e
, bT
)
201 if (e
->target() != bT
)
203 node vT
= e
->source();
204 node vH
= pBCTree
->cutVertex(vT
, bT
);
206 //set length of vertex v in block graph of bT:
207 int length_v_in_block
= 0;
209 forall_adj_edges(e2
, vT
)
211 //check if edge is an incoming edge:
212 if (e2
->target() != vT
)
215 node bT2
= e2
->source();
216 node cutVertex
= pBCTree
->cutVertex(vT
, bT2
);
217 length_v_in_block
+= constraintMaxFace(bT2
, cutVertex
);
219 nodeLength
[bT
][nH_to_nBlockEmbedding
[bT
][vH
]] = length_v_in_block
;
222 EdgeArray
<int> edgeLength(blockG
[bT
], 1);
223 int cstrLengthBc
= EmbedderMaxFaceBiconnectedGraphs
<int>::computeSize(
225 nH_to_nBlockEmbedding
[bT
][cH
],
229 cstrLength
[bT
][nH_to_nBlockEmbedding
[bT
][cH
]] = cstrLengthBc
;
234 void EmbedderMaxFace::maximumFaceRec(const node
& bT
, node
& bT_opt
, int& ell_opt
)
236 //(B*, \ell*) := (B, size of a maximum face in B):
238 EdgeArray
<int> edgeLength(blockG
[bT
], 1);
239 NodeArray
< EdgeArray
<int> > edgeLengthSkel
;
240 int m_ell_opt
= EmbedderMaxFaceBiconnectedGraphs
<int>::computeSize(
241 blockG
[bT
], nodeLength
[bT
], edgeLength
, *spqrTrees
[bT
], edgeLengthSkel
);
244 forall_adj_edges(e
, bT
)
246 if (e
->target() != bT
)
248 node cT
= e
->source();
249 node cH
= pBCTree
->cutVertex(cT
, bT
);
251 EdgeArray
<int> edgeLength(blockG
[bT
], 1);
252 cstrLength
[bT
][nH_to_nBlockEmbedding
[bT
][cH
]]
253 = EmbedderMaxFaceBiconnectedGraphs
<int>::computeSize(blockG
[bT
],
254 nH_to_nBlockEmbedding
[bT
][cH
],
260 //L := \sum_{(B', c) \in bcTree} cstrLength(B', c)
264 forall_adj_edges(e2
, cT
)
266 //check if edge is an incoming edge:
267 if (e2
->source() != cT
)
270 //get partner vertex of c in the block graph of B'=e->target() and add
271 //cstrLength(B', c) to L:
272 node bT2
= e2
->target();
273 L
+= cstrLength
[bT2
][nH_to_nBlockEmbedding
[bT2
][pBCTree
->cutVertex(cT
, bT2
)]];
277 forall_adj_edges(e2
, cT
)
279 //check if edge is an outgoing edge or the edge from bT to cT:
280 if (e2
->target() != cT
|| e2
->source() == bT
)
283 //get partner vertex of c in the block graph of B'=e->source():
284 node pT
= e2
->source();
285 node partnerV
= pBCTree
->cutVertex(cT
, pT
);
286 node pB
= nH_to_nBlockEmbedding
[pT
][partnerV
];
287 nodeLength
[pT
][pB
] = L
- cstrLength
[pT
][pB
];
289 //pBCTree->originalGraph().chooseNode() just to get rid of warning:
290 node thisbT_opt
= pBCTree
->originalGraph().chooseNode();
292 maximumFaceRec(pT
, thisbT_opt
, thisell_opt
);
293 if (thisell_opt
> m_ell_opt
)
295 m_bT_opt
= thisbT_opt
;
296 m_ell_opt
= thisell_opt
;
301 //return (B*, \ell*):
307 void EmbedderMaxFace::embedBlock(const node
& bT
)
309 ListIterator
<adjEntry
> after
;
311 embedBlock(bT
, cT
, after
);
315 void EmbedderMaxFace::embedBlock(
318 ListIterator
<adjEntry
>& after
)
320 treeNodeTreated
[bT
] = true;
323 cH
= pBCTree
->cutVertex(cT
, bT
);
325 //***************************************************************************
326 // 1. Compute embedding of block
327 //***************************************************************************
328 EdgeArray
<int> edgeLength(blockG
[bT
], 1);
329 adjEntry m_adjExternal
= 0;
331 EmbedderMaxFaceBiconnectedGraphs
<int>::embed(blockG
[bT
], m_adjExternal
,
332 nodeLength
[bT
], edgeLength
);
334 EmbedderMaxFaceBiconnectedGraphs
<int>::embed(blockG
[bT
], m_adjExternal
,
335 nodeLength
[bT
], edgeLength
, nH_to_nBlockEmbedding
[bT
][cH
]);
337 //***************************************************************************
338 // 2. Copy block embedding into graph embedding and call recursively
339 // embedBlock for all cut vertices in bT
340 //***************************************************************************
341 CombinatorialEmbedding
CE(blockG
[bT
]);
342 face f
= CE
.leftFace(m_adjExternal
);
344 if (*pAdjExternal
== 0)
346 node on
= pBCTree
->original(nBlockEmbedding_to_nH
[bT
][m_adjExternal
->theNode()]);
347 adjEntry ae1
= on
->firstAdj();
348 for (adjEntry ae
= ae1
; ae
; ae
= ae
->succ())
350 if (ae
->theEdge() == pBCTree
->original(eBlockEmbedding_to_eH
[bT
][m_adjExternal
->theEdge()]))
352 *pAdjExternal
= ae
->twin();
359 forall_nodes(nSG
, blockG
[bT
])
361 node nH
= nBlockEmbedding_to_nH
[bT
][nSG
];
362 node nG
= pBCTree
->original(nH
);
363 adjEntry ae
= nSG
->firstAdj();
364 ListIterator
<adjEntry
>* pAfter
;
365 if (pBCTree
->bcproper(nG
) == cT
)
368 pAfter
= OGDF_NEW ListIterator
<adjEntry
>();
370 if (pBCTree
->typeOfGNode(nG
) == BCTree::CutVertex
)
372 node cT2
= pBCTree
->bcproper(nG
);
373 bool no_recursion
= false;
376 node parent_bT_of_cT2
;
378 forall_adj_edges(e_cT2_to_bT2
, cT2
)
380 if (e_cT2_to_bT2
->source() == cT2
)
382 parent_bT_of_cT2
= e_cT2_to_bT2
->target();
386 if (treeNodeTreated
[parent_bT_of_cT2
])
392 //find adjacency entry of nSG which lies on external face f:
393 adjEntry aeFace
= f
->firstAdj();
396 if (aeFace
->theNode() == nSG
)
401 ae
= nSG
->firstAdj();
404 aeFace
= aeFace
->faceCycleSucc();
405 } while(aeFace
!= f
->firstAdj());
409 //(if exists) find adjacency entry of nSG which lies on external face f:
410 adjEntry aeFace
= f
->firstAdj();
413 if (aeFace
->theNode() == nSG
)
418 ae
= nSG
->firstAdj();
421 aeFace
= aeFace
->faceCycleSucc();
422 } while(aeFace
!= f
->firstAdj());
425 forall_adj_edges(e_cT2_to_bT2
, cT2
)
428 if (e_cT2_to_bT2
->source() == cT2
)
429 bT2
= e_cT2_to_bT2
->target();
431 bT2
= e_cT2_to_bT2
->source();
432 if (!treeNodeTreated
[bT2
])
433 embedBlock(bT2
, cT2
, *pAfter
);
438 //embed all edges of block bT:
439 bool after_ae
= true;
440 for (adjEntry aeNode
= ae
;
441 after_ae
|| aeNode
!= ae
;
442 after_ae
= (!after_ae
|| !aeNode
->succ()) ? false : true,
443 aeNode
= aeNode
->succ() ? aeNode
->succ() : nSG
->firstAdj())
445 edge eG
= pBCTree
->original(eBlockEmbedding_to_eH
[bT
][aeNode
->theEdge()]);
446 if (nG
== eG
->source())
448 if (!pAfter
->valid())
449 *pAfter
= newOrder
[nG
].pushBack(eG
->adjSource());
451 *pAfter
= newOrder
[nG
].insertAfter(eG
->adjSource(), *pAfter
);
453 else //!(nG == eG->source())
455 if (!pAfter
->valid())
456 *pAfter
= newOrder
[nG
].pushBack(eG
->adjTarget());
458 *pAfter
= newOrder
[nG
].insertAfter(eG
->adjTarget(), *pAfter
);
460 } //for (adjEntry aeNode = ae; aeNode; aeNode = aeNode->succ())
462 if (!(*pAfter
== after
))
464 } //forall_nodes(nSG, blockG[bT])
467 } // end namespace ogdf