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.
12 * See the paper "Graph Embedding with Minimum Depth and Maximum External
13 * Face" by C. Gutwenger and P. Mutzel (2004) for details.
14 * The algorithm for maximum external face is combined with the
15 * algorithm for maximum external layers which defines how to embed
16 * blocks into inner faces. See diploma thesis "Algorithmen zur
17 * Bestimmung von guten Graph-Einbettungen für orthogonale
18 * Zeichnungen" (in german) by Thorsten Kerkhof (2007) for details.
20 * \author Thorsten Kerkhof
23 * This file is part of the Open Graph Drawing Framework (OGDF).
27 * See README.txt in the root directory of the OGDF installation for details.
30 * This program is free software; you can redistribute it and/or
31 * modify it under the terms of the GNU General Public License
32 * Version 2 or 3 as published by the Free Software Foundation;
33 * see the file LICENSE.txt included in the packaging of this file
37 * This program is distributed in the hope that it will be useful,
38 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 * GNU General Public License for more details.
43 * You should have received a copy of the GNU General Public
44 * License along with this program; if not, write to the Free
45 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
46 * Boston, MA 02110-1301, USA.
48 * \see http://www.gnu.org/copyleft/gpl.html
49 ***************************************************************/
51 #include <ogdf/planarity/EmbedderMaxFaceLayers.h>
52 #include <ogdf/internal/planarity/EmbedderMaxFaceBiconnectedGraphsLayers.h>
53 #include <ogdf/internal/planarity/ConnectedSubgraph.h>
57 void EmbedderMaxFaceLayers::call(Graph
& G
, adjEntry
& adjExternal
)
60 pAdjExternal
= &adjExternal
;
63 if (G
.numberOfNodes() <= 1)
65 if (G
.numberOfEdges() == 1)
67 edge e
= G
.firstEdge();
68 adjExternal
= e
->adjSource();
72 //HINT: Edges are directed from child to parent in BC-trees
73 pBCTree
= new BCTree(G
);
75 //base case of biconnected graph:
76 if (pBCTree
->bcTree().numberOfNodes() == 1)
78 NodeArray
<int> m_nodeLength(G
, 0);
79 EdgeArray
<int> m_edgeLength(G
, 1);
80 adjEntry m_adjExternal
;
81 EmbedderMaxFaceBiconnectedGraphsLayers
<int>::embed(G
, m_adjExternal
, m_nodeLength
, m_edgeLength
);
82 adjExternal
= m_adjExternal
;
88 //***************************************************************************/
89 //First step: calculate maximum face and node lengths
90 //***************************************************************************/
92 //Find root Block (root node is only node with out-degree of 0):
95 forall_nodes(n
, pBCTree
->bcTree())
104 //compute block graphs and SPQR trees:
105 blockG
.init(pBCTree
->bcTree());
106 nBlockEmbedding_to_nH
.init(pBCTree
->bcTree());
107 eBlockEmbedding_to_eH
.init(pBCTree
->bcTree());
108 nH_to_nBlockEmbedding
.init(pBCTree
->bcTree());
109 eH_to_eBlockEmbedding
.init(pBCTree
->bcTree());
110 nodeLength
.init(pBCTree
->bcTree());
111 cstrLength
.init(pBCTree
->bcTree());
112 spqrTrees
.init(pBCTree
->bcTree(),0);
113 computeBlockGraphs(rootBlockNode
, 0);
115 //Bottom-Up-Traversal:
117 forall_adj_edges(e
, rootBlockNode
)
119 node cT
= e
->source();
120 node cH
= pBCTree
->cutVertex(cT
, rootBlockNode
);
121 node cB
= nH_to_nBlockEmbedding
[rootBlockNode
][cH
];
123 //set length of v in block graph of root block node:
124 int length_v_in_rootBlock
= 0;
126 forall_adj_edges(e2
, cT
)
128 //check if edge is an incoming edge:
129 if (e2
->target() != cT
)
132 node blockNode
= e2
->source();
133 node cutVertex
= pBCTree
->cutVertex(cT
, blockNode
);
134 length_v_in_rootBlock
+= constraintMaxFace(blockNode
, cutVertex
);
136 nodeLength
[rootBlockNode
][cB
] = length_v_in_rootBlock
;
139 node bT_opt
= G
.chooseNode(); //= G.chooseNode() only to get rid of warning
141 maximumFaceRec(rootBlockNode
, bT_opt
, ell_opt
);
144 //****************************************************************************
145 //Second step: Embed G by expanding a maximum face in bT_opt
146 //****************************************************************************
148 treeNodeTreated
.init(pBCTree
->bcTree(), false);
153 G
.sort(v
, newOrder
[v
]);
155 forall_nodes(v
, pBCTree
->bcTree())
162 void EmbedderMaxFaceLayers::computeBlockGraphs(const node
& bT
, const node
& cH
)
166 forall_adj_edges(e
, bT
)
168 if (e
->source() == bT
)
171 node cT
= e
->source();
173 forall_adj_edges(e2
, cT
)
175 if (e2
->source() == cT
)
177 node cH2
= pBCTree
->cutVertex(cT
, e2
->source());
178 computeBlockGraphs(e2
->source(), cH2
);
185 m_cH
= pBCTree
->cutVertex(bT
->firstAdj()->twinNode(), bT
);
186 ConnectedSubgraph
<int>::call(pBCTree
->auxiliaryGraph(), blockG
[bT
], m_cH
,
187 nBlockEmbedding_to_nH
[bT
], eBlockEmbedding_to_eH
[bT
],
188 nH_to_nBlockEmbedding
[bT
], eH_to_eBlockEmbedding
[bT
]);
189 nodeLength
[bT
].init(blockG
[bT
], 0);
190 cstrLength
[bT
].init(blockG
[bT
], 0);
191 if ( !blockG
[bT
].empty()
192 && blockG
[bT
].numberOfNodes() != 1
193 && blockG
[bT
].numberOfEdges() > 2)
195 spqrTrees
[bT
] = new StaticSPQRTree(blockG
[bT
]);
200 int EmbedderMaxFaceLayers::constraintMaxFace(const node
& bT
, const node
& cH
)
202 //forall (v \in B, v \neq c) do:
203 // length_B(v) := \sum_{(v, B') \in B} ConstraintMaxFace(B', v);
205 forall_adj_edges(e
, bT
)
207 if (e
->target() != bT
)
209 node vT
= e
->source();
210 node vH
= pBCTree
->cutVertex(vT
, bT
);
212 //set length of vertex v in block graph of bT:
213 int length_v_in_block
= 0;
215 forall_adj_edges(e2
, vT
)
217 //check if edge is an incoming edge:
218 if (e2
->target() != vT
)
221 node bT2
= e2
->source();
222 node cutVertex
= pBCTree
->cutVertex(vT
, bT2
);
223 length_v_in_block
+= constraintMaxFace(bT2
, cutVertex
);
225 nodeLength
[bT
][nH_to_nBlockEmbedding
[bT
][vH
]] = length_v_in_block
;
228 EdgeArray
<int> edgeLength(blockG
[bT
], 1);
230 = EmbedderMaxFaceBiconnectedGraphsLayers
<int>::computeSize(blockG
[bT
],
231 nH_to_nBlockEmbedding
[bT
][cH
],
235 cstrLength
[bT
][nH_to_nBlockEmbedding
[bT
][cH
]] = cstrLengthBc
;
240 void EmbedderMaxFaceLayers::maximumFaceRec(const node
& bT
, node
& bT_opt
, int& ell_opt
)
242 //(B*, \ell*) := (B, size of a maximum face in B):
244 EdgeArray
<int> edgeLength(blockG
[bT
], 1);
245 NodeArray
< EdgeArray
<int> > edgeLengthSkel
;
246 int m_ell_opt
= EmbedderMaxFaceBiconnectedGraphsLayers
<int>::computeSize(
254 forall_adj_edges(e
, bT
)
256 if (e
->target() != bT
)
258 node cT
= e
->source();
259 node cH
= pBCTree
->cutVertex(cT
, bT
);
261 EdgeArray
<int> edgeLength(blockG
[bT
], 1);
262 cstrLength
[bT
][nH_to_nBlockEmbedding
[bT
][cH
]] = EmbedderMaxFaceBiconnectedGraphsLayers
<int>::computeSize(
264 nH_to_nBlockEmbedding
[bT
][cH
],
270 //L := \sum_{(B', c) \in bcTree} cstrLength(B', c)
274 forall_adj_edges(e2
, cT
)
276 //check if edge is an incoming edge:
277 if (e2
->source() != cT
)
280 //get partner vertex of c in the block graph of B'=e->target() and add
281 //cstrLength(B', c) to L:
282 node bT2
= e2
->target();
283 L
+= cstrLength
[bT2
][nH_to_nBlockEmbedding
[bT2
][pBCTree
->cutVertex(cT
, bT2
)]];
287 forall_adj_edges(e2
, cT
)
289 //check if edge is an outgoing edge or the edge from bT to cT:
290 if (e2
->target() != cT
|| e2
->source() == bT
)
293 //get partner vertex of c in the block graph of B'=e->source():
294 node pT
= e2
->source();
295 node partnerV
= pBCTree
->cutVertex(cT
, pT
);
296 node pB
= nH_to_nBlockEmbedding
[pT
][partnerV
];
297 nodeLength
[pT
][pB
] = L
- cstrLength
[pT
][pB
];
299 //pBCTree->originalGraph().chooseNode() just to get rid of warning:
300 node thisbT_opt
= pBCTree
->originalGraph().chooseNode();
302 maximumFaceRec(pT
, thisbT_opt
, thisell_opt
);
303 if (thisell_opt
> m_ell_opt
)
305 m_bT_opt
= thisbT_opt
;
306 m_ell_opt
= thisell_opt
;
311 //return (B*, \ell*):
317 void EmbedderMaxFaceLayers::embedBlock(const node
& bT
)
319 ListIterator
<adjEntry
> after
;
321 embedBlock(bT
, cT
, after
);
325 void EmbedderMaxFaceLayers::embedBlock(
328 ListIterator
<adjEntry
>& after
)
330 treeNodeTreated
[bT
] = true;
333 cH
= pBCTree
->cutVertex(cT
, bT
);
335 //***************************************************************************
336 // 1. Compute embedding of block
337 //***************************************************************************
338 EdgeArray
<int> edgeLength(blockG
[bT
], 1);
339 adjEntry m_adjExternal
= 0;
341 EmbedderMaxFaceBiconnectedGraphsLayers
<int>::embed(blockG
[bT
], m_adjExternal
,
342 nodeLength
[bT
], edgeLength
);
344 EmbedderMaxFaceBiconnectedGraphsLayers
<int>::embed(blockG
[bT
], m_adjExternal
,
345 nodeLength
[bT
], edgeLength
, nH_to_nBlockEmbedding
[bT
][cH
]);
347 //***************************************************************************
348 // 2. Copy block embedding into graph embedding and call recursively
349 // embedBlock for all cut vertices in bT
350 //***************************************************************************
351 CombinatorialEmbedding
CE(blockG
[bT
]);
352 face f
= CE
.leftFace(m_adjExternal
);
354 if (*pAdjExternal
== 0)
356 node on
= pBCTree
->original(nBlockEmbedding_to_nH
[bT
][m_adjExternal
->theNode()]);
357 adjEntry ae1
= on
->firstAdj();
358 for (adjEntry ae
= ae1
; ae
; ae
= ae
->succ())
360 if (ae
->theEdge() == pBCTree
->original(eBlockEmbedding_to_eH
[bT
][m_adjExternal
->theEdge()]))
362 *pAdjExternal
= ae
->twin();
368 bool DGcomputed
= false;
371 List
<node
>* p_fPG_to_nDG
;
372 NodeArray
<int>* p_nDG_to_fPG
;
373 NodeArray
< List
<adjEntry
> >* p_adjacencyList
;
374 List
< List
<adjEntry
> >* p_faces
;
375 NodeArray
<int>* p_distances
;
378 forall_nodes(nSG
, blockG
[bT
])
380 node nH
= nBlockEmbedding_to_nH
[bT
][nSG
];
381 node nG
= pBCTree
->original(nH
);
382 adjEntry ae
= nSG
->firstAdj();
383 ListIterator
<adjEntry
>* pAfter
;
384 if (pBCTree
->bcproper(nG
) == cT
)
387 pAfter
= OGDF_NEW ListIterator
<adjEntry
>();
389 if (pBCTree
->typeOfGNode(nG
) == BCTree::CutVertex
)
391 node cT2
= pBCTree
->bcproper(nG
);
392 bool no_recursion
= false;
395 node parent_bT_of_cT2
;
397 forall_adj_edges(e_cT2_to_bT2
, cT2
)
399 if (e_cT2_to_bT2
->source() == cT2
)
401 parent_bT_of_cT2
= e_cT2_to_bT2
->target();
405 if (treeNodeTreated
[parent_bT_of_cT2
])
411 //find adjacency entry of nSG which lies on external face f:
412 adjEntry aeFace
= f
->firstAdj();
415 if (aeFace
->theNode() == nSG
)
420 ae
= nSG
->firstAdj();
423 aeFace
= aeFace
->faceCycleSucc();
424 } while(aeFace
!= f
->firstAdj());
428 //(if exists) find adjacency entry of nSG which lies on external face f:
429 bool aeExtExists
= false;
430 adjEntry aeFace
= f
->firstAdj();
433 if (aeFace
->theNode() == nSG
)
438 ae
= nSG
->firstAdj();
442 aeFace
= aeFace
->faceCycleSucc();
443 } while(aeFace
!= f
->firstAdj());
450 p_fPG_to_nDG
= OGDF_NEW List
<node
>();
451 p_nDG_to_fPG
= OGDF_NEW NodeArray
<int>();
452 p_adjacencyList
= OGDF_NEW NodeArray
< List
<adjEntry
> >();
453 p_faces
= OGDF_NEW List
< List
<adjEntry
> >;
454 p_distances
= OGDF_NEW NodeArray
<int>;
457 //compute dual graph of skeleton graph:
458 p_adjacencyList
->init(blockG
[bT
]);
460 forall_nodes(nBG
, blockG
[bT
])
463 forall_adj(ae_nBG
, nBG
)
464 (*p_adjacencyList
)[nBG
].pushBack(ae_nBG
);
467 NodeArray
< List
<adjEntry
> > adjEntryTreated(blockG
[bT
]);
468 forall_nodes(nBG
, blockG
[bT
])
473 if (adjEntryTreated
[nBG
].search(adj
) != -1)
476 List
<adjEntry
> newFace
;
480 newFace
.pushBack(adj2
);
481 adjEntryTreated
[adj2
->theNode()].pushBack(adj2
);
482 node tn
= adj2
->twinNode();
483 int idx
= (*p_adjacencyList
)[tn
].search(adj2
->twin());
485 idx
= (*p_adjacencyList
)[tn
].size() - 1;
488 adj2
= *((*p_adjacencyList
)[tn
].get(idx
));
489 } while (adj2
!= adj
);
490 p_faces
->pushBack(newFace
);
492 } //forall_nodes(nBG, blockG[bT])
494 p_nDG_to_fPG
->init(*p_DG
);
496 for (ListIterator
< List
<adjEntry
> > it
= p_faces
->begin(); it
.valid(); it
++)
498 node nn
= p_DG
->newNode();
499 (*p_nDG_to_fPG
)[nn
] = p_fPG_to_nDG
->search(*(p_fPG_to_nDG
->pushBack(nn
)));
502 NodeArray
< List
<node
> > adjFaces(*p_DG
);
504 for (ListIterator
< List
<adjEntry
> > it
= p_faces
->begin(); it
.valid(); it
++)
507 for (ListIterator
<adjEntry
> it2
= (*it
).begin(); it2
.valid(); it2
++)
511 for (ListIterator
< List
<adjEntry
> > it3
= p_faces
->begin(); it3
.valid(); it3
++)
513 bool do_break
= false;
514 for (ListIterator
<adjEntry
> it4
= (*it3
).begin(); it4
.valid(); it4
++)
516 if ((*it4
) == (*it2
)->twin())
529 && adjFaces
[*(p_fPG_to_nDG
->get(f1_id
))].search(*(p_fPG_to_nDG
->get(f2_id
))) == -1
530 && adjFaces
[*(p_fPG_to_nDG
->get(f2_id
))].search(*(p_fPG_to_nDG
->get(f1_id
))) == -1)
532 adjFaces
[*(p_fPG_to_nDG
->get(f1_id
))].pushBack(*(p_fPG_to_nDG
->get(f2_id
)));
533 p_DG
->newEdge(*(p_fPG_to_nDG
->get(f1_id
)), *(p_fPG_to_nDG
->get(f2_id
)));
536 if (*it2
== f
->firstAdj())
538 } //for (ListIterator<adjEntry> it2 = (*it).begin(); it2.valid(); it2++)
540 } //for (ListIterator< List<adjEntry> > it = faces.begin(); it.valid(); it++)
542 //compute shortest path from every face to the external face:
544 p_DG
->allEdges(DG_edges
);
545 for (ListIterator
<edge
> it_e
= DG_edges
.begin(); it_e
.valid(); it_e
++)
547 node s
= (*it_e
)->source();
548 node t
= (*it_e
)->target();
551 ShortestPathWithBFM shortestPath
;
552 node efDG
= *(p_fPG_to_nDG
->get(extFaceID
));
553 EdgeArray
<int> el(*p_DG
, 1);
554 p_distances
->init(*p_DG
);
555 NodeArray
<edge
> pi(*p_DG
);
556 shortestPath
.call(*p_DG
, efDG
, el
, *p_distances
, pi
);
559 //choose face with minimal shortest path:
560 List
<adjEntry
> optFace
;
561 int optFaceDist
= -1;
562 for (int fID
= 0; fID
< p_faces
->size(); fID
++)
564 List
<adjEntry
> theFace
= *(p_faces
->get(fID
));
566 bool contains_nSG
= false;
567 for (ListIterator
<adjEntry
> it_ae
= theFace
.begin(); it_ae
.valid(); it_ae
++)
569 if ((*it_ae
)->theNode() == nSG
)
579 int thisDist
= (*p_distances
)[*p_fPG_to_nDG
->get(fID
)];
580 if (optFaceDist
== -1 || optFaceDist
> thisDist
)
583 optFaceDist
= thisDist
;
587 ae
= nSG
->firstAdj();
590 } //for (int fID = 0; fID < faces.size(); fID++)
591 } //if (!aeExtExists)
594 forall_adj_edges(e_cT2_to_bT2
, cT2
)
597 if (e_cT2_to_bT2
->source() == cT2
)
598 bT2
= e_cT2_to_bT2
->target();
600 bT2
= e_cT2_to_bT2
->source();
601 if (!treeNodeTreated
[bT2
])
602 embedBlock(bT2
, cT2
, *pAfter
);
607 //embed all edges of block bT:
608 bool after_ae
= true;
609 for (adjEntry aeNode
= ae
;
610 after_ae
|| aeNode
!= ae
;
611 after_ae
= (!after_ae
|| !aeNode
->succ()) ? false : true,
612 aeNode
= aeNode
->succ() ? aeNode
->succ() : nSG
->firstAdj())
614 edge eG
= pBCTree
->original(eBlockEmbedding_to_eH
[bT
][aeNode
->theEdge()]);
615 if (nG
== eG
->source())
617 if (!pAfter
->valid())
618 *pAfter
= newOrder
[nG
].pushBack(eG
->adjSource());
620 *pAfter
= newOrder
[nG
].insertAfter(eG
->adjSource(), *pAfter
);
622 else //!(nG == eG->source())
624 if (!pAfter
->valid())
625 *pAfter
= newOrder
[nG
].pushBack(eG
->adjTarget());
627 *pAfter
= newOrder
[nG
].insertAfter(eG
->adjTarget(), *pAfter
);
629 } //for (adjEntry aeNode = ae; aeNode; aeNode = aeNode->succ())
631 if (!(*pAfter
== after
))
633 } //forall_nodes(nSG, blockG[bT])
640 delete p_adjacencyList
;
646 } // end namespace ogdf