6 * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $
7 ***************************************************************/
10 * \brief planar biconnected augmentation approximation algorithm
15 * This file is part of the Open Graph Drawing Framework (OGDF).
19 * See README.txt in the root directory of the OGDF installation for details.
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * Version 2 or 3 as published by the Free Software Foundation;
25 * see the file LICENSE.txt included in the packaging of this file
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
35 * You should have received a copy of the GNU General Public
36 * License along with this program; if not, write to the Free
37 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
38 * Boston, MA 02110-1301, USA.
40 * \see http://www.gnu.org/copyleft/gpl.html
41 ***************************************************************/
44 #include <ogdf/augmentation/PlanarAugmentation.h>
46 #include <ogdf/basic/simple_graph_alg.h>
47 #include <ogdf/basic/extended_graph_alg.h>
48 #include <ogdf/decomposition/DynamicBCTree.h>
52 //#define PLANAR_AUGMENTATION_DEBUG
54 // for checking planarity directly after inserting a new edge
55 // and additional planarity tests after each augmentation round
56 //#define PLANAR_AUGMENTATION_DEBUG_PLANARCHECK
62 /********************************************************
64 * implementation of class PALabel
66 *******************************************************/
68 void PALabel::removePendant(node pendant
)
70 if (m_pendants
.size() > 0){
71 ListIterator
<node
> it
= m_pendants
.begin();
72 for (; it
.valid(); ++it
)
73 if ((*it
) == pendant
){
81 /********************************************************
83 * implementation of class PlanarAugmentation
85 *******************************************************/
88 // ----------------------------------------------------
91 // ----------------------------------------------------
92 void PlanarAugmentation::doCall(Graph
& g
, List
<edge
>& L
)
94 m_nPlanarityTests
= 0;
101 #ifdef PLANAR_AUGMENTATION_DEBUG
102 cout
<< "Graph G has no self loops = " << isLoopFree(*m_pGraph
) << endl
;
103 cout
<< "Graph G is planar = " << isPlanar(*m_pGraph
)<< endl
;
104 cout
<< "Graph G is connected = " << isConnected(*m_pGraph
) << endl
;
105 cout
<< "Graph G is biconnected = " << isBiconnected(*m_pGraph
) << endl
;
108 // create the bc-tree
109 if (m_pGraph
->numberOfNodes() > 1){
111 if (!isConnected(*m_pGraph
)){
112 if(m_pGraph
->numberOfEdges() == 0){
113 // one edge is required
114 m_pResult
->pushBack(m_pGraph
->newEdge(m_pGraph
->firstNode(), m_pGraph
->firstNode()->succ()));
117 makeConnectedByPendants();
120 m_pBCTree
= new DynamicBCTree(*m_pGraph
);
122 // init the m_adjNonChildren-NodeArray with all adjEntries of the bc-tree
123 m_adjNonChildren
.init(m_pBCTree
->m_B
);
127 forall_nodes(v
, m_pBCTree
->bcTree()){
128 if (v
->firstAdj() != 0){
129 m_adjNonChildren
[v
].pushFront(v
->firstAdj());
130 adj
= v
->firstAdj()->cyclicSucc();
131 while (adj
!= v
->firstAdj()){
132 m_adjNonChildren
[v
].pushBack(adj
);
133 adj
= adj
->cyclicSucc();
137 m_isLabel
.init(m_pBCTree
->bcTree(), 0);
138 m_belongsTo
.init(m_pBCTree
->bcTree(), 0);
140 // call main function
147 // ----------------------------------------------------
148 // makeConnectedByPendants()
150 // makes graph connected by inserting edges between
151 // nodes of pendants of the connected components
153 // ----------------------------------------------------
154 void PlanarAugmentation::makeConnectedByPendants()
156 DynamicBCTree
bcTreeTemp(*m_pGraph
, true);
158 NodeArray
<int> components
;
159 components
.init(*m_pGraph
, 0);
161 int compCnt
= connectedComponents(*m_pGraph
, components
);
163 List
<node
> getConnected
;
165 Array
<bool> compConnected(compCnt
);
166 for (int i
=0; i
<compCnt
; i
++){
167 compConnected
[i
] = false;
171 forall_nodes(v
, *m_pGraph
){
172 if (v
->degree() == 0){
173 // found a seperated node that will be connected
174 getConnected
.pushBack(v
);
175 compConnected
[components
[v
]] = true;
179 forall_nodes(v
, *m_pGraph
){
180 if ((compConnected
[components
[v
]] == false) && (bcTreeTemp
.bcproper(v
)->degree() <= 1)){
181 // found a node that will be connected
182 getConnected
.pushBack(v
);
183 compConnected
[components
[v
]] = true;
187 ListIterator
<node
> it
= getConnected
.begin();
188 ListIterator
<node
> itBefore
= getConnected
.begin();
191 // insert edge between it and itBefore
192 m_pResult
->pushBack(m_pGraph
->newEdge(*it
, *itBefore
));
201 // ----------------------------------------------------
204 // the main augmentation function
206 // ----------------------------------------------------
207 void PlanarAugmentation::augment()
209 node v
, rootPendant
= 0;
211 // first initialize the list of pendants
212 forall_nodes(v
, m_pBCTree
->bcTree()){
213 if (v
->degree() == 1){
214 #ifdef PLANAR_AUGMENTATION_DEBUG
215 cout
<< "augment(): found pendant with index " << v
->index();
217 if (m_pBCTree
->parent(v
) == 0){
219 #ifdef PLANAR_AUGMENTATION_DEBUG
220 cout
<< " is root! (also inserted into pendants-list!)" << endl
<< flush
;
224 #ifdef PLANAR_AUGMENTATION_DEBUG
225 cout
<< endl
<< flush
;
228 m_pendants
.pushBack(v
);
232 if (rootPendant
!= 0){
233 // the root of the bc-tree is also a pendant
234 // this has to be changed
236 node bAdjNode
= rootPendant
->firstAdj()->twinNode();
238 #ifdef PLANAR_AUGMENTATION_DEBUG
239 cout
<< "augment(): changing root in bc-tree because root is a pendant!" << endl
<< flush
;
240 cout
<< "augment(): index of old root = " << rootPendant
->index() << ", new root = " << bAdjNode
->index() << endl
<< flush
;
243 // modify the bc-tree-structure
244 modifyBCRoot(rootPendant
, bAdjNode
);
247 // call reduceChain for all pendants
248 if (m_pendants
.size() > 1){
249 ListIterator
<node
> it
= m_pendants
.begin();
250 for (; it
.valid(); ++it
){
255 // it can appear that reduceChain() inserts some edges
256 // in case of non-planarity (paPlanarity)
257 // so there are new pendants and obsolete pendants
258 // the obsolete pendants are collected in m_pendantsToDel
259 if (m_pendantsToDel
.size() > 0){
260 ListIterator
<node
> delIt
= m_pendantsToDel
.begin();
261 for (; delIt
.valid(); delIt
= m_pendantsToDel
.begin()){
262 deletePendant(*delIt
);
263 m_pendantsToDel
.del(delIt
);
267 #ifdef PLANAR_AUGMENTATION_DEBUG
268 cout
<< "augment(): after reduceChain() for every pendant:" << endl
;
269 cout
<< " #labels = " << m_labels
.size() << endl
;
270 cout
<< " #pendants = " << m_pendants
.size() << endl
<< endl
;
271 cout
<< "STARTING MAIN LOOP:" << endl
;
272 cout
<< endl
<< flush
;
276 while(!m_labels
.empty()){
277 // foundMatching indicates if there are 2 labels that can be connected
279 // labels first and second are going to be computed by findMatching
280 // and foundMatching=true or foundMatching=false
281 // first is always != 0 after findMatching(...)
282 pa_label first
, second
= 0;
284 foundMatching
= findMatching(first
, second
);
286 // no matching labels were found
289 // we have only one label
290 if (m_labels
.size() == 1){
292 if (m_pendants
.size() > 1)
293 //m_labels.size() == 1 && m_pendants.size() > 1
294 // join the pendants of this label
297 //m_labels.size() == 1 && m_pendants.size() == 1
298 connectInsideLabel(first
);
302 // m_labels.size() > 1
304 if (first
->size() == 1){
305 // m_labels.size() > 1 && first->size() == 1
307 connectInsideLabel(first
);
310 // m_labels.size() > 1 && first->size() > 1
311 // so connect all pendants of label first
318 // foundMatching == true
319 connectLabels(first
, second
);
322 // output after each round:
323 #ifdef PLANAR_AUGMENTATION_DEBUG
324 cout
<< endl
<< "augment(): output after one round:" << endl
;
325 cout
<< " #labels = " << m_labels
.size() << endl
;
326 cout
<< " #pendants = " << m_pendants
.size() << endl
;
327 #ifdef PLANAR_AUGMENTATION_DEBUG_PLANARCHECK
328 cout
<< "graph is planar == " << isPlanar(*m_pGraph
) << endl
;
329 cout
<< "graph is biconnected == " << isBiconnected(*m_pGraph
) << endl
;
331 cout
<< endl
<< flush
;
333 ListIterator
<pa_label
> labelIt
= m_labels
.begin();
335 for (; labelIt
.valid(); labelIt
++){
336 cout
<< "pos " << pos
<< ": ";
337 if ((m_isLabel
[(*labelIt
)->parent()]).valid())
338 cout
<< " OK, parent-index = " << (*labelIt
)->parent()->index()
339 << ", size = " << (*labelIt
)->size() << endl
<< flush
;
341 cout
<< " ERROR, parent-index = " << (*labelIt
)->parent()->index()
342 << ", size = " << (*labelIt
)->size()<< endl
<< flush
;
346 cout
<< endl
<< flush
;
348 // : output after each round
352 #ifdef PLANAR_AUGMENTATION_DEBUG
353 cout
<< endl
<< "FINISHED MAIN LOOP" << endl
<< endl
;
354 cout
<< "# planarity tests = " << m_nPlanarityTests
<< endl
;
355 #ifdef PLANAR_AUGMENTATION_DEBUG_PLANARITY
356 cout
<< "resulting Graph is biconnected = " << isBiconnected(*m_pGraph
) << endl
;
357 cout
<< "resulting Graph is planar = " << isPlanar(*m_pGraph
) << endl
;
359 cout
<< endl
<< flush
;
367 // ----------------------------------------------------
368 // reduceChain(node p, label labelOld)
370 // finds the "parent" (->label) for a pendant p of the BC-Tree
371 // and creates a new label or inserts the pendant to another
373 // reduceChain can also insert edges in case of paPlanarity
375 // ----------------------------------------------------
376 void PlanarAugmentation::reduceChain(node p
, pa_label labelOld
)
378 #ifdef PLANAR_AUGMENTATION_DEBUG
379 cout
<< "reduceChain(" << p
->index() << ")";
382 // parent = parent of p in the BC-Tree
383 // if p is the root, then parent == 0
384 node parent
= m_pBCTree
->DynamicBCTree::parent(p
);
386 // last is going to be the last cutvertex in the computation of followPath()
388 paStopCause stopCause
;
390 // traverse from parent to the root of the bc-tree and check several
391 // conditions. last is going to be the last cutvertex on this path
392 stopCause
= followPath(parent
, last
);
394 #ifdef PLANAR_AUGMENTATION_DEBUG
395 cout
<< ", stopCause == ";
398 cout
<< "paPlanarity" << endl
<< flush
;
401 cout
<< "paCDegree" << endl
<< flush
;
404 cout
<< "paBDegree" << endl
<< flush
;
407 cout
<< "paRoot" << endl
<< flush
;
413 if (stopCause
== paPlanarity
){
414 node adjToCutP
= adjToCutvertex(p
);
415 node adjToCutLast
= adjToCutvertex(m_pBCTree
->DynamicBCTree::parent(last
), last
);
417 // computes path in bc-tree between bcproper(adjToCutP) and bcproper(adjToCutLast)
418 SList
<node
>& path
= m_pBCTree
->findPath(adjToCutP
, adjToCutLast
);
420 #ifdef PLANAR_AUGMENTATION_DEBUG
421 cout
<< "reduceChain(): inserting edge between " << adjToCutP
->index()
422 << " and " << adjToCutLast
->index() << endl
<< flush
;
426 edge e
= m_pGraph
->newEdge(adjToCutP
, adjToCutLast
);
428 // insert the edge into the result-list
429 m_pResult
->pushBack(e
);
431 // update the bc-Tree with new edge
432 m_pBCTree
->updateInsertedEdge(e
);
434 // find the new arised pendant
435 node newPendant
= m_pBCTree
->find(p
);
437 if (newPendant
!= p
){
438 // delete the old pendant
439 // cannot delete the pendant immediatly
440 // because that would affect the outer loop in augment()
441 m_pendantsToDel
.pushBack(p
);
442 // insert the new arised pendant
443 // at the front of m_pendants becuse that doesn't affect the outer loop in augment()
444 m_pendants
.pushFront(newPendant
);
447 // updating m_adjNonChildren
448 updateAdjNonChildren(newPendant
, path
);
450 // check if newPendant is the new root of the bc-tree
451 if (m_pBCTree
->DynamicBCTree::parent(newPendant
) == 0){
452 #ifdef PLANAR_AUGMENTATION_DEBUG
453 cout
<< "reduceChain(): new arised pendant is the new root of the bc-tree, it has degree "
454 << m_pBCTree
->m_bNode_degree
[newPendant
] << endl
<< flush
;
457 node newRoot
= (*(m_adjNonChildren
[newPendant
].begin()))->twinNode();
459 // modify bc-tree-structure
460 modifyBCRoot(newPendant
, newRoot
);
465 // delete label if necessary
467 deleteLabel(labelOld
);
470 #ifdef PLANAR_AUGMENTATION_DEBUG
471 cout
<< "reduceChain(): calling reduceChain() with newPendant = " << newPendant
->index() << endl
<< flush
;
474 // call reduceChain with the new arised pendant
475 reduceChain(newPendant
);
480 if (stopCause
== paCDegree
|| stopCause
== paRoot
){
483 if (labelOld
->head() == last
){
484 // set the stop-cause
485 labelOld
->stopCause(stopCause
);
488 deleteLabel(labelOld
);
491 if (m_isLabel
[last
].valid()){
492 // l is the label that last is the head of
493 l
= *(m_isLabel
[last
]);
494 // add the actual pendant p to l
496 // set the stop-cause
497 l
->stopCause(stopCause
);
500 newLabel(last
, p
, stopCause
);
504 if (stopCause
== paBDegree
){
506 if (labelOld
->head() != last
){
507 deleteLabel(labelOld
);
508 newLabel(last
, p
, paBDegree
);
511 labelOld
->stopCause(paBDegree
);
515 newLabel(last
, p
, paBDegree
);
522 // ----------------------------------------------------
523 // followPath(node v, node &last)
525 // traverses the BC-Tree upwards from v
526 // (v is always a parent of a pendant)
527 // last becomes the last cutvertex before we return
529 // ----------------------------------------------------
530 paStopCause
PlanarAugmentation::followPath(node v
, node
& last
)
533 node bcNode
= m_pBCTree
->find(v
);
535 if (m_pBCTree
->typeOfBNode(bcNode
) == BCTree::CComp
){
540 int deg
= m_pBCTree
->m_bNode_degree
[bcNode
];
543 if (m_pBCTree
->typeOfBNode(bcNode
) == BCTree::CComp
){
551 // deg == 2 (case deg < 2 cannot occur)
552 if (m_pBCTree
->typeOfBNode(bcNode
) == BCTree::CComp
){
556 // bcNode is a BComp and degree is 2
557 if (m_pBCTree
->numberOfNodes(bcNode
) > 4){
558 // check planarity if number of nodes > 4
559 // because only than a K5- or k33-Subdivision can be included
564 SListIterator
<adjEntry
> childIt
= m_adjNonChildren
[bcNode
].begin();
565 while (!found
&& childIt
.valid()){
566 if (m_pBCTree
->find((*childIt
)->twinNode()) != last
){
568 adjBCNode
= m_pBCTree
->find((*childIt
)->twinNode());
573 // get nodes in biconnected-components graph of m_pBCTree
574 node hNode
= m_pBCTree
->m_bNode_hRefNode
[last
];
575 node hNode2
= m_pBCTree
->m_bNode_hRefNode
[adjBCNode
];
577 // check planarity for corresponding graph-nodes of hNode and hNode2
578 if (!planarityCheck(m_pBCTree
->m_hNode_gNode
[hNode
],
579 m_pBCTree
->m_hNode_gNode
[hNode2
])){
584 // iterate to parent node
585 bcNode
= m_pBCTree
->DynamicBCTree::parent(bcNode
);
587 // reached the bc-tree-root
593 // ----------------------------------------------------
594 // planarityCheck(node v1, node v2)
596 // checks planarity for the new edge (v1, v2)
597 // v1 and v2 are nodes in the original graph
599 // ----------------------------------------------------
600 bool PlanarAugmentation::planarityCheck(node v1
, node v2
)
602 // first simple tests
607 // check if edge (v1, v2) already exists
608 if (v1
->firstAdj()->twinNode() == v2
){
611 adjEntry adjTest
= v1
->firstAdj()->cyclicSucc();
612 while (adjTest
!= v1
->firstAdj()){
613 if (v1
->firstAdj()->twinNode() == v2
){
616 adjTest
= adjTest
->cyclicSucc();
619 // test planarity for edge (v1, v2)
620 edge e
= m_pGraph
->newEdge(v1
, v2
);
624 bool planar
= planarEmbed(*m_pGraph
);
626 // finally delete the edge
627 m_pGraph
->delEdge(e
);
634 // ----------------------------------------------------
635 // adjToCutvertex(node v, node cutvertex)
637 // returns the vertex in the original graph that
638 // belongs to v (B-Component in the BC-Graph and pendant)
639 // and is adjacent to the cutvertex (also node of the BC-Graph)
640 // if cutvertex == 0 then the cutvertex of the parent of v
643 // ----------------------------------------------------
644 node
PlanarAugmentation::adjToCutvertex(node v
, node cutvertex
)
646 node nodeAdjToCutVertex
;
650 // set nodeAdjToCutVertex to the node in the original graph,
651 // that corresponds to the parent (c-component) of v in the bc-tree
652 nodeAdjToCutVertex
= m_pBCTree
->m_hNode_gNode
[m_pBCTree
->m_bNode_hParNode
[v
]];
654 // adj = adjEntry at the cutvertex
655 adjEntry adj
= nodeAdjToCutVertex
->firstAdj();
657 while (m_pBCTree
->DynamicBCTree::bcproper(adj
->twinNode()) != v
)
658 adj
= adj
->cyclicSucc();
660 nodeAdjToCutVertex
= adj
->twinNode();
664 // set nodeAdjToCutVertex to the node in the original graph,
665 // corresponding to the cutvertex in the bc-tree
666 nodeAdjToCutVertex
= m_pBCTree
->m_hNode_gNode
[m_pBCTree
->m_bNode_hRefNode
[cutvertex
]];
668 // adj = adjEntry at the cutvertex
669 adjEntry adj
= nodeAdjToCutVertex
->firstAdj();
673 if (m_pBCTree
->bComponent(nodeAdjToCutVertex
, adj
->twinNode()) == v
){
675 nodeAdjToCutVertex
= adj
->twinNode();
678 adj
= adj
->cyclicSucc();
679 while ((!found
) && (adj
!= nodeAdjToCutVertex
->firstAdj())){
680 if (m_pBCTree
->bComponent(nodeAdjToCutVertex
, adj
->twinNode()) == v
){
681 nodeAdjToCutVertex
= adj
->twinNode();
684 adj
= adj
->cyclicSucc();
688 return nodeAdjToCutVertex
;
693 // ----------------------------------------------------
694 // findLastBefore(node pendant, node ancestor)
696 // returns the last vertex before ancestor
697 // on the path from pendant to ancestor
699 // ----------------------------------------------------
700 node
PlanarAugmentation::findLastBefore(node pendant
, node ancestor
)
702 node bcNode
= pendant
;
703 while ((bcNode
) && (m_pBCTree
->DynamicBCTree::parent(bcNode
) != ancestor
))
704 bcNode
= m_pBCTree
->DynamicBCTree::parent(bcNode
);
707 // should never occur
716 // ----------------------------------------------------
717 // deletePendant(node p)
719 // deletes pendant p from the list of all pendants
720 // deletes p also from the label it belongs to
722 // ----------------------------------------------------
723 void PlanarAugmentation::deletePendant(node p
, bool removeFromLabel
)
725 ListIterator
<node
> mPendantsIt
= m_pendants
.begin();
727 bool deleted
= false;
728 while (!deleted
&& mPendantsIt
.valid()){
729 ListIterator
<node
> itSucc
= mPendantsIt
.succ();
730 if ((*mPendantsIt
) == p
){
731 m_pendants
.del(mPendantsIt
);
734 mPendantsIt
= itSucc
;
737 if ((removeFromLabel
) && (m_belongsTo
[p
] != 0)){
738 (m_belongsTo
[p
])->removePendant(p
);
745 // ----------------------------------------------------
746 // removeAllPendants(label& l)
749 // and - if desired - removes the pendants belonging to l
751 // ----------------------------------------------------
752 void PlanarAugmentation::removeAllPendants(pa_label
& l
)
754 while (l
->size() > 0){
755 m_belongsTo
[l
->getFirstPendant()] = 0;
756 l
->removeFirstPendant();
762 // ----------------------------------------------------
763 // addPendant(pa_label& l, node pendant)
765 // adds a pendant p to a label l
766 // re-inserts also l to m_labels
768 // ----------------------------------------------------
769 void PlanarAugmentation::addPendant(node p
, pa_label
& l
)
774 node newParent
= m_pBCTree
->find(l
->parent());
776 m_labels
.del(m_isLabel
[l
->parent()]);
777 m_isLabel
[newParent
] = insertLabel(l
);
782 // ----------------------------------------------------
783 // joinPendants(pa_label& l)
785 // connects all pendants of the label
787 // ----------------------------------------------------
788 void PlanarAugmentation::joinPendants(pa_label
& l
)
790 #ifdef PLANAR_AUGMENTATION_DEBUG
791 cout
<< "joinPendants(): l->size()==" << l
->size() << endl
<< flush
;
794 node pendant1
= l
->getFirstPendant();
795 // delete pendant from m_pendants but not from the label it belongs to
796 deletePendant(pendant1
, false);
798 SList
<edge
> newEdges
;
800 // traverse through pendant-list and connect them
801 ListIterator
<node
> pendantIt
= (l
->m_pendants
).begin();
802 while (pendantIt
.valid()){
804 if (*pendantIt
!= pendant1
){
806 // delete pendant from m_pendants but not from the label it belongs to
807 deletePendant(*pendantIt
, false);
809 #ifdef PLANAR_AUGMENTATION_DEBUG
810 cout
<< "joinPendants(): connectPendants: " << pendant1
->index()
811 << " and " << (*pendantIt
)->index() << endl
<< flush
;
814 // connect pendants and insert edge in newEdges
815 newEdges
.pushBack(connectPendants(pendant1
, *pendantIt
));
818 pendant1
= *pendantIt
;
824 updateNewEdges(newEdges
);
826 removeAllPendants(l
);
828 SListIterator
<edge
> edgeIt
= newEdges
.begin();
829 node newBlock
= (m_pBCTree
->DynamicBCTree::bcproper(*edgeIt
));
830 if (m_pBCTree
->m_bNode_degree
[newBlock
] == 1){
831 #ifdef PLANAR_AUGMENTATION_DEBUG
832 cout
<< "joinPendants(): new block " << newBlock
->index() << " has degree 1 " << endl
<< flush
;
835 m_belongsTo
[newBlock
] = l
;
836 addPendant(newBlock
, l
);
837 m_pendants
.pushBack(newBlock
);
841 #ifdef PLANAR_AUGMENTATION_DEBUG
842 cout
<< "joinPendants(): new block has degree " << m_pBCTree
->m_bNode_degree
[newBlock
] << endl
<< flush
;
850 // ----------------------------------------------------
851 // connectInsideLabel(label& l)
853 // connects the only pendant of l with
854 // a computed "ancestor"
856 // ----------------------------------------------------
857 void PlanarAugmentation::connectInsideLabel(pa_label
& l
)
859 #ifdef PLANAR_AUGMENTATION_DEBUG
860 cout
<< "connectInsideLabel(): l->size() == " << l
->size() << ", parent = " << l
->parent()->index()
861 << ", head = " << l
->head()->index() << endl
<< flush
;
864 node head
= l
->head();
865 node pendant
= l
->getFirstPendant();
867 node ancestor
= m_pBCTree
->DynamicBCTree::parent(head
);
869 node v1
= adjToCutvertex(pendant
);
871 // check if head is the root of the BC-Tree
873 node wrongAncestor
= findLastBefore(pendant
, head
);
875 SListIterator
<adjEntry
> adjIt
= m_adjNonChildren
[head
].begin();
877 while ((!found
) && (adjIt
.valid())){
879 if (m_pBCTree
->find((*adjIt
)->twinNode()) != wrongAncestor
){
880 ancestor
= m_pBCTree
->find((*adjIt
)->twinNode());
887 node v2
= adjToCutvertex(ancestor
, head
);
889 #ifdef PLANAR_AUGMENTATION_DEBUG
890 cout
<< "connectInsideLabel(): inserting edge between " << v1
->index() << " and " << v2
->index() << endl
<< flush
;
893 SList
<edge
> newEdges
;
894 edge e
= m_pGraph
->newEdge(v1
, v2
);
895 newEdges
.pushFront(e
);
897 #ifdef PLANAR_AUGMENTATION_DEBUG_PLANARCHECK
898 if (!isPlanar(*m_pGraph
))
899 cout
<< "connectInsideLabel(): CRITICAL ERROR!!! inserted non-planar edge!!! (in connectInsideLabel())" << endl
<< flush
;
902 updateNewEdges(newEdges
);
904 node newBlock
= m_pBCTree
->DynamicBCTree::bcproper(e
);
906 // delete label l, and also the pendant
909 if (m_pBCTree
->m_bNode_degree
[newBlock
] == 1){
910 #ifdef PLANAR_AUGMENTATION_DEBUG
911 cout
<< "connectInsideLabel(): new block " << newBlock
->index() << " has degree 1... calling reduceChain() ";
913 m_pendants
.pushBack(newBlock
);
914 if ((m_belongsTo
[newBlock
] != 0) && (m_belongsTo
[newBlock
]->size() == 1)){
915 reduceChain(newBlock
, m_belongsTo
[newBlock
]);
918 reduceChain(newBlock
);
919 // it can appear that reduceChain() inserts some edges
920 // so there are new pendants and obsolete pendants
921 // the obsolete pendants are collected in m_pendantsToDel
922 if (m_pendantsToDel
.size() > 0){
923 ListIterator
<node
> delIt
= m_pendantsToDel
.begin();
924 for (; delIt
.valid(); delIt
= m_pendantsToDel
.begin()){
925 deletePendant(*delIt
);
926 m_pendantsToDel
.del(delIt
);
935 // ----------------------------------------------------
936 // connectPendants(node pendant1, node pendant2)
938 // connects the two pendants with a new edge
940 // ----------------------------------------------------
941 edge
PlanarAugmentation::connectPendants(node pendant1
, node pendant2
)
943 node v1
= adjToCutvertex(pendant1
);
944 node v2
= adjToCutvertex(pendant2
);
946 #ifdef PLANAR_AUGMENTATION_DEBUG
947 cout
<< "connectPendants(): inserting edge between " << v1
->index() << " and " << v2
->index() << endl
<< flush
;
950 edge e
= m_pGraph
->newEdge(v1
, v2
);
952 #ifdef PLANAR_AUGMENTATION_DEBUG_PLANARCHECK
953 if (!(isPlanar(*m_pGraph
)))
954 cout
<< "connectLabels(): CRITICAL ERROR in connectPendants: inserted edge is not planar!!!" << endl
<< flush
;
962 // ----------------------------------------------------
963 // insertLabel(pa_label l)
965 // inserts a label l at the correct position in the list
967 // ----------------------------------------------------
968 ListIterator
<pa_label
> PlanarAugmentation::insertLabel(pa_label l
)
970 if (m_labels
.size() == 0){
971 return m_labels
.pushFront(l
);
974 ListIterator
<pa_label
> it
= m_labels
.begin();
975 while (it
.valid() && ((*it
)->size() > l
->size())){
979 return m_labels
.pushBack(l
);
981 return m_labels
.insert(l
, it
, before
);
987 // ----------------------------------------------------
988 // deleteLabel(pa_label& l, bool removePendants)
991 // and - if desired - removes the pendants belonging to l
993 // ----------------------------------------------------
994 void PlanarAugmentation::deleteLabel(pa_label
& l
, bool removePendants
)
996 ListIterator
<pa_label
> labelIt
= m_isLabel
[l
->parent()];
998 m_labels
.del(labelIt
);
999 m_isLabel
[l
->parent()] = 0;
1001 ListIterator
<node
> pendantIt
= (l
->m_pendants
).begin();
1002 while (pendantIt
.valid()){
1003 m_belongsTo
[*pendantIt
] = 0;
1007 if (removePendants
){
1008 pendantIt
= (l
->m_pendants
).begin();
1009 while (pendantIt
.valid()){
1011 ListIterator
<node
> mPendantsIt
= m_pendants
.begin();
1013 bool deleted
= false;
1014 while (!deleted
&& mPendantsIt
.valid()){
1015 ListIterator
<node
> itSucc
= mPendantsIt
.succ();
1016 if ((*mPendantsIt
) == *pendantIt
){
1017 m_pendants
.del(mPendantsIt
);
1020 mPendantsIt
= itSucc
;
1032 // ----------------------------------------------------
1033 // connectLabels(pa_label first, pa_label second);
1035 // connects the pendants of first with the pendants
1037 // first.size() >= second.size()
1039 // ----------------------------------------------------
1040 void PlanarAugmentation::connectLabels(pa_label first
, pa_label second
)
1042 ListIterator
<node
> pendantIt
;
1044 #ifdef PLANAR_AUGMENTATION_DEBUG
1045 cout
<< "connectLabels(), first->size()=="<< first
->size() << " , second->size()=="
1046 << second
->size() << endl
<< flush
;
1048 pendantIt
= (first
->m_pendants
).begin();
1049 cout
<< "connectLabels(): label first = ";
1050 for (; pendantIt
.valid(); pendantIt
++){
1051 cout
<< (*pendantIt
)->index() << ", ";
1053 pendantIt
= (second
->m_pendants
).begin();
1054 cout
<< " || " << endl
<< "label second = ";
1055 for (; pendantIt
.valid(); pendantIt
++){
1056 cout
<< (*pendantIt
)->index() << ", ";
1058 cout
<< endl
<< flush
;
1061 SList
<edge
> newEdges
;
1062 pendantIt
= (second
->m_pendants
).begin();
1064 // stores the pendants of label first that were connected
1065 // because first.size() => second.size()
1066 SList
<node
> getConnected
;
1070 while (pendantIt
.valid()){
1071 v2
= first
->getPendant(n
);
1072 getConnected
.pushBack(v2
);
1073 newEdges
.pushBack(connectPendants(v2
, *pendantIt
));
1075 #ifdef PLANAR_AUGMENTATION_DEBUG_PLANARCHECK
1076 if (!(isPlanar(*m_pGraph
)))
1077 cout
<< "connectLabels(): CRITICAL ERROR: inserted edge is not planar!!!" << endl
<< flush
;
1084 updateNewEdges(newEdges
);
1085 deleteLabel(second
);
1087 node newBlock
= m_pBCTree
->DynamicBCTree::bcproper(newEdges
.front());
1088 #ifdef PLANAR_AUGMENTATION_DEBUG
1089 cout
<< "connectLabels(): newBlock->index() == " << newBlock
->index() << ", degree == "
1090 << m_pBCTree
->m_bNode_degree
[newBlock
] << endl
<< flush
;
1093 SListIterator
<node
> pendantIt2
= getConnected
.begin();
1094 while (pendantIt2
.valid()){
1096 //first->removePendant(*pendantIt2);
1097 deletePendant(*pendantIt2
);
1102 if (first
->size() != 0){
1103 m_labels
.del(m_isLabel
[first
->parent()]);
1104 m_isLabel
[m_pBCTree
->find(first
->parent())] = insertLabel(first
);
1106 pendantIt
= (first
->m_pendants
).begin();
1107 for (; pendantIt
.valid(); pendantIt
++){
1108 m_belongsTo
[m_pBCTree
->find(*pendantIt
)] = first
;
1111 else{ // first->size() == 0
1115 if (m_pBCTree
->m_bNode_degree
[newBlock
] == 1){
1117 #ifdef PLANAR_AUGMENTATION_DEBUG
1118 cout
<< "connectLabels(): m_bNode_degree[" << newBlock
->index() << "] == 1... calling reduceChain()" << endl
<< flush
;
1121 m_pendants
.pushBack(newBlock
);
1123 if ((m_belongsTo
[newBlock
] != 0) && (m_belongsTo
[newBlock
]->size() == 1)){
1124 reduceChain(newBlock
, m_belongsTo
[newBlock
]);
1127 reduceChain(newBlock
);
1129 // it can appear that reduceChain() inserts some edges
1130 // so there are new pendants and obsolete pendants
1131 // the obsolete pendants are collected in m_pendantsToDel
1132 if (m_pendantsToDel
.size() > 0){
1133 ListIterator
<node
> delIt
= m_pendantsToDel
.begin();
1134 for (; delIt
.valid(); delIt
= m_pendantsToDel
.begin()){
1135 deletePendant(*delIt
);
1136 m_pendantsToDel
.del(delIt
);
1142 #ifdef PLANAR_AUGMENTATION_DEBUG
1143 cout
<< "connectLabels(): newBlock is no new pendant ! degree == " << m_pBCTree
->m_bNode_degree
[newBlock
] << endl
<< flush
;
1150 // ----------------------------------------------------
1151 // newLabel(node cutvertex, node block, paStopCause whyStop)
1153 // creates a new label and inserts it into m_labels
1155 // ----------------------------------------------------
1156 pa_label
PlanarAugmentation::newLabel(node cutvertex
, node p
, paStopCause whyStop
)
1158 pa_label l
= OGDF_NEW
PALabel(0, cutvertex
, whyStop
);
1161 m_isLabel
[cutvertex
] = m_labels
.pushBack(l
);
1167 // ----------------------------------------------------
1168 // findMatching(pa_label& first, pa_label& second)
1170 // trys to find two matching labels
1171 // first will be the label with max. size that has
1174 // ----------------------------------------------------
1175 bool PlanarAugmentation::findMatching(pa_label
& first
, pa_label
& second
)
1177 first
= m_labels
.front();
1181 ListIterator
<pa_label
> it
= m_labels
.begin();
1185 if (second
!= first
){
1186 if ( (l
!= 0) && (second
->size() < l
->size()) ){
1193 if ( connectCondition(second
, first
)
1194 && planarityCheck(m_pBCTree
->m_hNode_gNode
[m_pBCTree
->m_bNode_hRefNode
[second
->head()]],
1195 m_pBCTree
->m_hNode_gNode
[m_pBCTree
->m_bNode_hRefNode
[first
->head()]]) )
1202 if ( planarityCheck(m_pBCTree
->m_hNode_gNode
[m_pBCTree
->m_bNode_hRefNode
[second
->head()]],
1203 m_pBCTree
->m_hNode_gNode
[m_pBCTree
->m_bNode_hRefNode
[first
->head()]]) ){
1204 if (connectCondition(second
, first
)){
1223 // ----------------------------------------------------
1224 // connectCondition(pa_label a, pa_label b)
1226 // checks the connect-condition for label a and b
1228 // ----------------------------------------------------
1229 bool PlanarAugmentation::connectCondition(pa_label a
, pa_label b
)
1233 if ( (a
->isBLabel()) && (b
->size() == 1) ){
1237 int deg1
= m_pBCTree
->m_bNode_degree
[m_pBCTree
->find(a
->head())] - b
->size() +1;
1238 int deg2
= m_pBCTree
->m_bNode_degree
[m_pBCTree
->find(b
->head())] - b
->size() +1;
1240 if ((deg1
> 2) && (deg2
> 2)){
1243 if ((deg1
> 2) || (deg2
> 2)){
1250 SList
<node
> *path
= m_pBCTree
->findPathBCTree(a
->head(), b
->head());
1251 SListIterator
<node
> it
= path
->begin();
1254 for (; it
.valid(); it
++){
1255 bcNode
= m_pBCTree
->find(*it
);
1257 if ((bcNode
!= a
->parent()) && (bcNode
!= b
->parent())){
1258 if (m_pBCTree
->m_bNode_degree
[bcNode
] > 2){
1265 if ((m_pBCTree
->typeOfBNode(bcNode
) == BCTree::BComp
)
1266 && (m_pBCTree
->m_bNode_degree
[bcNode
] > 3))
1280 // ----------------------------------------------------
1281 // updateAdjNonChildren()
1283 // update of m_adjNonChildren
1284 // newBlock is the node all nodes on path now belong to
1286 // ----------------------------------------------------
1287 void PlanarAugmentation::updateAdjNonChildren(node newBlock
, SList
<node
>& path
)
1289 SListIterator
<node
> pathIt
= path
.begin();
1291 SListIterator
<adjEntry
> childIt
= m_adjNonChildren
[newBlock
].begin();
1292 SListIterator
<adjEntry
> prevIt
= m_adjNonChildren
[newBlock
].begin();
1293 // first update m_adjNonChildren[newBlock] by deleting wrong adjEntries
1294 while (childIt
.valid()){
1295 if (m_pBCTree
->find((*childIt
)->twinNode()) == newBlock
){
1296 if (childIt
== m_adjNonChildren
[newBlock
].begin()){
1297 m_adjNonChildren
[newBlock
].popFront();
1298 childIt
= m_adjNonChildren
[newBlock
].begin();
1299 prevIt
= m_adjNonChildren
[newBlock
].begin();
1303 m_adjNonChildren
[newBlock
].delSucc(prevIt
);
1313 // now run through list of all path-nodes
1314 // and update m_adjNonChildren[pathIt] if they do not belong to another bc-node
1315 // or insert adjEntries to m_adjNonChildren[newBlock]
1316 while (pathIt
.valid()){
1318 if (*pathIt
!= newBlock
){
1319 if (*pathIt
== m_pBCTree
->find(*pathIt
)){
1321 childIt
= m_adjNonChildren
[*pathIt
].begin();
1322 prevIt
= m_adjNonChildren
[*pathIt
].begin();
1324 while (childIt
.valid()){
1325 if (m_pBCTree
->find((*childIt
)->twinNode()) == (*pathIt
)){
1326 if (childIt
== m_adjNonChildren
[*pathIt
].begin()){
1327 m_adjNonChildren
[*pathIt
].popFront();
1328 childIt
= m_adjNonChildren
[*pathIt
].begin();
1329 prevIt
= m_adjNonChildren
[*pathIt
].begin();
1333 m_adjNonChildren
[*pathIt
].delSucc(prevIt
);
1343 else{ // (*pathIt != m_pBCTree->find(*pathIt))
1344 childIt
= m_adjNonChildren
[*pathIt
].begin();
1346 while (childIt
.valid()){
1347 if (m_pBCTree
->find((*childIt
)->twinNode()) != newBlock
){
1348 // found a child of *pathIt, that has an adjacent bc-node
1349 // that doesn't belong to newBlock
1350 m_adjNonChildren
[newBlock
].pushBack(*childIt
);
1354 m_adjNonChildren
[*pathIt
].clear();
1363 // ----------------------------------------------------
1366 // modifys the root of the bc-tree
1368 // ----------------------------------------------------
1369 void PlanarAugmentation::modifyBCRoot(node oldRoot
, node newRoot
)
1371 // status before updates:
1372 // m_pBCTree->m_bNode_hRefNode[oldRoot] = 0
1373 // m_pBCTree->m_bNode_hParNode[oldRoot] = 0
1375 // m_pBCTree->m_bNode_hRefNode[newRoot] = single isolated vertex in b-comp-graph of this c-comp
1376 // m_pBCTree->m_bNode_hParNode[newRoot] = cutvertex in b-comp-graph corresponding to rootPendant
1379 // for the old root:
1380 m_pBCTree
->m_bNode_hRefNode
[oldRoot
] = m_pBCTree
->m_bNode_hParNode
[newRoot
];
1381 m_pBCTree
->m_bNode_hParNode
[oldRoot
] = m_pBCTree
->m_bNode_hRefNode
[newRoot
];
1383 // for the new root:
1384 // m_pBCTree->m_bNode_hRefNode[newRoot] = no update required;
1385 m_pBCTree
->m_bNode_hParNode
[newRoot
] = 0;
1390 // ----------------------------------------------------
1391 // updateNewEdges(const SList<edge> &newEdges)
1393 // updates the bc-tree-structure and m_adjNonChildren,
1394 // also adds all edges of newEdges to m_pResult
1396 // ----------------------------------------------------
1397 void PlanarAugmentation::updateNewEdges(const SList
<edge
> &newEdges
)
1399 SListConstIterator
<edge
> edgeIt
= newEdges
.begin();
1400 while (edgeIt
.valid()){
1401 m_pResult
->pushBack(*edgeIt
);
1403 SList
<node
>& path
= m_pBCTree
->findPath((*edgeIt
)->source(), (*edgeIt
)->target());
1405 m_pBCTree
->updateInsertedEdge(*edgeIt
);
1406 node newBlock
= m_pBCTree
->DynamicBCTree::bcproper(*edgeIt
);
1408 updateAdjNonChildren(newBlock
, path
);
1410 if ((m_pBCTree
->parent(newBlock
) == 0)
1411 && (m_pBCTree
->m_bNode_degree
[newBlock
] == 1)) {
1412 // the new block is a pendant and also the new root of the bc-tree
1414 newRoot
= (*(m_adjNonChildren
[newBlock
].begin()))->twinNode();
1415 modifyBCRoot(newBlock
, newRoot
);
1416 } //if ((m_pBCTree->parent(newBlock) == 0) && (m_pBCTree->m_bNode_degree[newBlock] == 1))
1420 } // while (edgeIt.valid)
1425 // ----------------------------------------------------
1428 // cleanup before finish
1430 // ----------------------------------------------------
1431 void PlanarAugmentation::terminate()
1433 while (m_labels
.size() > 0){
1434 pa_label l
= m_labels
.popFrontRet();
1440 forall_nodes(v
, m_pBCTree
->m_B
)
1441 m_adjNonChildren
[v
].clear();
1446 } // end namespace ogdf