6 * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $
7 ***************************************************************/
10 * \brief Implementation of Cluster Planarity tests and Cluster
11 * Planar embedding for C-connected Cluster Graphs
13 * \author Sebastian Leipert
16 * This file is part of the Open Graph Drawing Framework (OGDF).
20 * See README.txt in the root directory of the OGDF installation for details.
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * Version 2 or 3 as published by the Free Software Foundation;
26 * see the file LICENSE.txt included in the packaging of this file
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
36 * You should have received a copy of the GNU General Public
37 * License along with this program; if not, write to the Free
38 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
39 * Boston, MA 02110-1301, USA.
41 * \see http://www.gnu.org/copyleft/gpl.html
42 ***************************************************************/
45 //#include <qapplication.h>
46 #include <ogdf/basic/Graph.h>
48 #include <ogdf/cluster/CconnectClusterPlanarEmbed.h>
50 #include <ogdf/basic/simple_graph_alg.h>
51 #include <ogdf/basic/extended_graph_alg.h>
52 #include <ogdf/basic/AdjEntryArray.h>
54 #include <ogdf/internal/planarity/EmbedPQTree.h>
60 CconnectClusterPlanarEmbed::CconnectClusterPlanarEmbed()
62 ogdf::strcpy(errorCode
,124,"\0");
67 CconnectClusterPlanarEmbed::~CconnectClusterPlanarEmbed()
72 // Tests if a ClusterGraph is c-planar and embedds it.
73 bool CconnectClusterPlanarEmbed::embed(ClusterGraph
&C
,Graph
&G
)
76 OGDF_ASSERT(C
.consistencyCheck())
78 if (G
.numberOfNodes() <= 1) return true;
80 // Initialize Node and cluster arrays associated with original graph.
82 m_nodeTableOrig2Copy
.init(G
,0);
83 m_clusterTableOrig2Copy
.init(C
,0);
84 m_clusterEmbedding
.init(C
,0);
85 m_clusterSubgraph
.init(C
,0);
86 m_clusterSubgraphHubs
.init(C
,0);
87 m_clusterSubgraphWheelGraph
.init(C
,0);
88 m_clusterClusterGraph
.init(C
,0);
89 m_clusterNodeTableNew2Orig
.init(C
,0);
90 m_clusterOutgoingEdgesAnker
.init(C
,0);
91 m_clusterSuperSink
.init(C
,0);
92 m_clusterPQContainer
.init(C
);
93 m_unsatisfiedCluster
.init(C
,false);
95 // Copy the graph (necessary, since we modify it throughout the planarity test)
97 ClusterGraph
Ccopy(C
,Gcopy
,m_clusterTableOrig2Copy
,m_nodeTableOrig2Copy
);
99 // Initialize translation tables for nodes and clusters
100 m_clusterTableCopy2Orig
.init(Ccopy
,0);
104 cluster c1
= m_clusterTableOrig2Copy
[c
];
105 m_clusterTableCopy2Orig
[c1
] = c
;
107 m_nodeTableCopy2Orig
.init(Gcopy
,0);
111 node w
= m_nodeTableOrig2Copy
[v
];
112 m_nodeTableCopy2Orig
[w
] = v
;
114 // Remove empty clusters
115 SList
<cluster
> removeCluster
;
116 forall_clusters(c
,Ccopy
)
118 if (c
->cCount() == 0 && c
->nCount() == 0)
119 removeCluster
.pushBack(c
);
121 while (!removeCluster
.empty())
123 c
= removeCluster
.popFrontRet();
124 m_unsatisfiedCluster
[m_clusterTableCopy2Orig
[c
]] = true;
125 cluster parent
= c
->parent();
127 if (parent
->cCount() == 0 && parent
->nCount() == 0)
128 removeCluster
.pushBack(parent
);
130 while (Ccopy
.rootCluster()->cCount() == 1 && Ccopy
.rootCluster()->nCount() == 0)
132 c
= (*(Ccopy
.rootCluster()->cBegin()));
133 m_unsatisfiedCluster
[m_clusterTableCopy2Orig
[c
]] = true;
137 OGDF_ASSERT(Ccopy
.consistencyCheck());
139 // Initialize node and cluster arrays associated with copied graph.
140 m_clusterPQTree
.init(Ccopy
,0);
141 m_currentHubs
.init(Gcopy
,false);
142 m_wheelGraphNodes
.init(Gcopy
,0);
143 m_outgoingEdgesAnker
.init(Gcopy
,0);
146 bool cPlanar
= preProcess(Ccopy
,Gcopy
);
150 OGDF_ASSERT(Gcopy
.representsCombEmbedding())
151 //OGDF_ASSERT(Ccopy.consistencyCheck());
153 recursiveEmbed(Ccopy
,Gcopy
);
154 OGDF_ASSERT(Ccopy
.consistencyCheck());
156 copyEmbedding(Ccopy
,Gcopy
,C
,G
);
158 C
.adjAvailable(true);
162 nonPlanarCleanup(Ccopy
,Gcopy
);
168 if (m_clusterSubgraph
[c
] != 0 && c
!= C
.rootCluster())
169 delete m_clusterSubgraph
[c
];
173 // Deinitialize all node and cluster arrays
174 m_parallelEdges
.init();
176 m_clusterPQTree
.init();
177 m_clusterEmbedding
.init();
178 m_clusterSubgraph
.init();
179 m_clusterSubgraphHubs
.init();
180 m_clusterSubgraphWheelGraph
.init();
181 m_clusterClusterGraph
.init();
182 m_clusterNodeTableNew2Orig
.init();
183 m_clusterOutgoingEdgesAnker
.init();
184 m_clusterSuperSink
.init();
185 m_clusterPQContainer
.init();
187 m_clusterTableOrig2Copy
.init();
188 m_clusterTableCopy2Orig
.init();
189 m_nodeTableOrig2Copy
.init();
190 m_nodeTableCopy2Orig
.init();
191 m_currentHubs
.init();
192 m_wheelGraphNodes
.init();
193 m_outgoingEdgesAnker
.init();
200 // Tests if a ClusterGraph is c-planar and embedds it.
201 // Specifies reason for non planarity
202 bool CconnectClusterPlanarEmbed::embed(ClusterGraph
&C
,Graph
&G
, char (&code
)[124])
205 bool cPlanar
= embed(C
,G
);
206 ogdf::strcpy(code
,124,errorCode
);
217 // call(ClusterGraph &C)
219 // preProcess(ClusterGraph &C,Graph &G)
221 // planarityTest(ClusterGraph &C,cluster &act,Graph &G)
223 // foreach ChildCluster
224 // planarityTest(ClusterGraph &C,cluster &act,Graph &G)
226 // preparation(Graph &G,cluster &origCluster)
228 // foreach biconnected Component
229 // doTest(Graph &G,NodeArray<int> &numbering,cluster &origCluster)
234 /*******************************************************************************
236 ********************************************************************************/
238 // Copies the embedding of Ccopy to C
240 void CconnectClusterPlanarEmbed::copyEmbedding(
250 OGDF_ASSERT(Gcopy
.representsCombEmbedding())
252 OGDF_ASSERT(Ccopy
.representsCombEmbedding())
254 AdjEntryArray
<adjEntry
> adjTableCopy2Orig(Gcopy
);
255 AdjEntryArray
<adjEntry
> adjTableOrig2Copy(G
);
256 AdjEntryArray
<bool> visited(G
,false); // For parallel edges
257 EdgeArray
<edge
> edgeTableCopy2Orig(Gcopy
,0); // Translation table for parallel edges
258 EdgeArray
<bool> parallelEdge(Gcopy
,false); // Marks parallel edges in copy Graph
259 AdjEntryArray
<adjEntry
> parallelEntryPoint(G
,0); // For storing information on parallel
260 // edges for cluster adjlistst.
261 AdjEntryArray
<bool> parallelToBeIgnored(Gcopy
,false);// For storing information on parallel
262 // edges for cluster adjlistst.
264 // prepare parallel Edges
265 prepareParallelEdges(G
);
266 NodeArray
<SListPure
<adjEntry
> > entireEmbedding(G
);
268 //process over all copy nodes
269 forall_nodes(vCopy
,Gcopy
)
271 //get the original node
272 node wOrig
= m_nodeTableCopy2Orig
[vCopy
];
276 //process over all adjacent copy edges
277 SList
<adjEntry
> entries
;
278 Gcopy
.adjEntries(vCopy
,entries
);
279 SListIterator
<adjEntry
> itv
;
280 for (itv
= entries
.begin(); itv
.valid(); itv
++)
283 node vN
= vAdj
->twinNode();
284 node wN
= m_nodeTableCopy2Orig
[vN
];
285 m_nodeTableOrig2Copy
[wN
] = vN
;
288 forall_adj(wAdj
,wOrig
)
291 if (edgeTableCopy2Orig
[vAdj
->theEdge()] != 0 &&
292 m_isParallel
[edgeTableCopy2Orig
[vAdj
->theEdge()]])
293 // Break if parallel edge (not a reference edge) that has already been assigned.
295 if (wAdj
->twinNode() == wN
296 && !visited
[wAdj
] && !m_isParallel
[wAdj
->theEdge()])
297 // && !m_isParallel[wAdj->theEdge()])
298 // Either a non parallel edge or the reference edge of a set of
301 adjTableCopy2Orig
[vAdj
] = wAdj
;
302 adjTableOrig2Copy
[wAdj
] = vAdj
;
303 // adjTableCopy2Orig[vAdj->twin()] = wAdj->twin();
304 // adjTableOrig2Copy[wAdj->twin()] = vAdj->twin();
305 edgeTableCopy2Orig
[vAdj
->theEdge()] = wAdj
->theEdge();
307 if (int(ogdf::debugLevel
) >= int(dlHeavyChecks
)){
308 cout
<< "Orig " << wAdj
<< " " << wAdj
->index() << "\t twin " << wAdj
->twin()->index() << endl
;
309 cout
<< "Copy " << vAdj
<< " " << vAdj
->index() << "\t twin " << vAdj
->twin()->index() << endl
<< endl
;}
310 //qDebug ("Visited: %d->%d %d", wAdj->theNode()->index(),
311 // wAdj->twinNode()->index(),
314 entireEmbedding
[wOrig
].pushBack(wAdj
); // if no parallel edges exist,
315 // this will be our embedding.
316 // entireEmbedding[wN].pushFront(wAdj->twin());
317 visited
[wAdj
] = true; // for multi-edges
318 // visited[wAdj->twin()] = true; // for multi-edges
321 else if (wAdj
->twinNode() == wN
&& !visited
[wAdj
])
322 // A parallel edge that is not the reference edge.
323 // We need to set the translation table
325 adjTableCopy2Orig
[vAdj
] = wAdj
;
326 adjTableOrig2Copy
[wAdj
] = vAdj
;
327 adjTableCopy2Orig
[vAdj
->twin()] = wAdj
->twin();
328 adjTableOrig2Copy
[wAdj
->twin()] = vAdj
->twin();
329 edgeTableCopy2Orig
[vAdj
->theEdge()] = wAdj
->theEdge();
330 visited
[wAdj
] = true; // So we do not consider parallel edges twice.
331 visited
[wAdj
->twin()] = true; // So we do not consider parallel edges twice.
338 // Locate all parallel edges
339 // Sort them within the adjacency lists,
340 // such that they appear consecutively.
341 NodeArray
<SListPure
<adjEntry
> > newEntireEmbedding(G
);
342 NodeArray
<SListPure
<adjEntry
> > newEntireEmbeddingCopy(Gcopy
);
344 if (m_parallelCount
> 0)
348 SListIterator
<adjEntry
> it
;
349 for(it
= entireEmbedding
[v
].begin();it
.valid();it
++)
351 edge e
= (*it
)->theEdge();
353 if (!m_parallelEdges
[e
].empty())
355 // This edge is the reference edge
356 // of a bundle of parallel edges
358 ListIterator
<edge
> it
;
359 // If v is source of e, insert the parallel edges
360 // in the order stored in the list.
361 if (e
->adjSource()->theNode() == v
)
363 adjEntry adj
= e
->adjSource();
365 newEntireEmbedding
[v
].pushBack(adj
);
366 newEntireEmbeddingCopy
[m_nodeTableOrig2Copy
[v
]].pushBack(adjTableOrig2Copy
[adj
]);
368 parallelEntryPoint
[e
->adjSource()] = adj
;
369 parallelToBeIgnored
[adjTableOrig2Copy
[adj
]] = true;
371 for (it
= m_parallelEdges
[e
].begin(); it
.valid(); it
++)
373 edge parallel
= (*it
);
374 adjEntry adj
= parallel
->adjSource()->theNode() == v
?
375 parallel
->adjSource() : parallel
->adjTarget();
376 parallelToBeIgnored
[adjTableOrig2Copy
[adj
]] = true;
378 if (int(ogdf::debugLevel
) >= int(dlHeavyChecks
)){
379 cout
<< adj
<< " " << adj
->index() << "\t twin " << adj
->twin()->index() << endl
;}
381 newEntireEmbedding
[v
].pushBack(adj
);
382 newEntireEmbeddingCopy
[m_nodeTableOrig2Copy
[v
]].pushBack(adjTableOrig2Copy
[adj
]);
386 // v is target of e, insert the parallel edges
387 // in the opposite order stored in the list.
388 // This keeps the embedding.
391 for (it
= m_parallelEdges
[e
].rbegin(); it
.valid(); it
--)
393 edge parallel
= (*it
);
394 adjEntry adj
= parallel
->adjSource()->theNode() == v
?
395 parallel
->adjSource() : parallel
->adjTarget();
396 parallelToBeIgnored
[adjTableOrig2Copy
[adj
]] = true;
398 newEntireEmbedding
[v
].pushBack(adj
);
399 newEntireEmbeddingCopy
[m_nodeTableOrig2Copy
[v
]].pushBack(adjTableOrig2Copy
[adj
]);
402 // parallelEntryPoint[adjTableOrig2Copy[adj]] = adj;
403 parallelEntryPoint
[e
->adjTarget()] = adj
;
407 adjEntry adj
= e
->adjTarget();
409 newEntireEmbedding
[v
].pushBack(adj
);
410 newEntireEmbeddingCopy
[m_nodeTableOrig2Copy
[v
]];//.pushBack(adjTableOrig2Copy[adj]);
411 newEntireEmbeddingCopy
[m_nodeTableOrig2Copy
[v
]].pushBack(adjTableOrig2Copy
[adj
]);
412 parallelToBeIgnored
[adjTableOrig2Copy
[adj
]] = true;
415 else if (!m_isParallel
[e
])
416 // normal non-multi-edge
418 adjEntry adj
= e
->adjSource()->theNode() == v
?
419 e
->adjSource() : e
->adjTarget();
421 newEntireEmbedding
[v
].pushBack(adj
);
422 newEntireEmbeddingCopy
[m_nodeTableOrig2Copy
[v
]];//pushBack(adjTableOrig2Copy[adj]);
423 adjTableOrig2Copy
[adj
];
424 newEntireEmbeddingCopy
[m_nodeTableOrig2Copy
[v
]].pushBack(adjTableOrig2Copy
[adj
]);
426 // else e is a multi-edge but not the reference edge
431 G
.sort(v
,newEntireEmbedding
[v
]);
432 forall_nodes(v
,Gcopy
)
433 Gcopy
.sort(v
,newEntireEmbeddingCopy
[v
]);
439 G
.sort(v
,entireEmbedding
[v
]);
440 OGDF_ASSERT(G
.representsCombEmbedding())
445 OGDF_ASSERT(G
.representsCombEmbedding())
447 forall_clusters(c
,Ccopy
)
449 SListPure
<adjEntry
> embedding
;
452 ListIterator
<adjEntry
> it
;
454 for(it
= c
->firstAdj();it
.valid(); it
++)
457 edge e
= adj
->theEdge();
459 if (!m_parallelEdges
[edgeTableCopy2Orig
[e
]].empty())
461 adjEntry padj
= parallelEntryPoint
[adjTableCopy2Orig
[adj
]];
463 bool lastMultiEdgeFound
= false;
464 node target
= padj
->twinNode();
466 while (!lastMultiEdgeFound
) // Scan the parallel edges of e
467 // in the original graph along the embedded
468 // adjacency list of its target
470 if (padj
->twinNode() == target
) // is a multi edge
472 embedding
.pushBack(padj
);
474 if (!padj
) break; //only multi edges
476 else // Not a multi Edge
480 else if (!parallelToBeIgnored
[adj
])
482 embedding
.pushBack(adjTableCopy2Orig
[adj
]);
486 C
.makeAdjEntries(m_clusterTableCopy2Orig
[c
],embedding
.begin());
491 /*******************************************************************************
493 ********************************************************************************/
496 // Deallocates all memory, if the cluster graph is not cluster planar
498 void CconnectClusterPlanarEmbed::nonPlanarCleanup(ClusterGraph
&Ccopy
,Graph
&Gcopy
)
501 while (!m_callStack
.empty())
503 cluster act
= m_callStack
.pop();
505 Graph
*subGraph
= m_clusterSubgraph
[act
];
507 node superSink
= m_clusterPQContainer
[act
].m_superSink
;
511 forall_edges(e
,*subGraph
)
513 if (e
->source() != superSink
&& e
->target() != superSink
)
514 if ((*m_clusterOutgoingEdgesAnker
[act
])[e
])
515 delete (*m_clusterOutgoingEdgesAnker
[act
])[e
];
519 if (m_clusterEmbedding
[act
] != 0)
520 delete m_clusterEmbedding
[act
];
521 delete m_clusterSubgraphHubs
[act
];
522 delete m_clusterSubgraphWheelGraph
[act
];
523 delete m_clusterNodeTableNew2Orig
[act
];
524 delete m_clusterOutgoingEdgesAnker
[act
];
526 m_clusterPQContainer
[act
].Cleanup();
531 forall_edges(e
,Gcopy
)
533 if (m_outgoingEdgesAnker
[e
])
534 delete m_outgoingEdgesAnker
[e
];
540 /*******************************************************************************
542 ********************************************************************************/
545 // This function is called by recursiveEmbed only. It fixes
546 // the adjacency lists of the hubs in Gcopy after a cluster has been
549 void CconnectClusterPlanarEmbed::hubControl(Graph
&G
,NodeArray
<bool> &hubs
)
554 if (hubs
[hub
]) // hub is a hub
559 adjEntry startAdj
= hub
->firstAdj();
560 adjEntry firstAdj
= 0;
562 while (firstAdj
!= startAdj
)
566 secAdj
= firstAdj
->cyclicSucc();
567 firstNode
= firstAdj
->twinNode();
568 secNode
= secAdj
->twinNode();
570 adjEntry cyclicPredOfFirst
= firstAdj
->twin()->cyclicPred();
571 while(cyclicPredOfFirst
->twinNode()
574 cyclicPredOfFirst
= cyclicPredOfFirst
->cyclicPred();
576 G
.moveAdjBefore(cyclicPredOfFirst
,firstAdj
->twin());
579 adjEntry cyclicSuccOfSec
= secAdj
->twin()->cyclicSucc();
580 while(cyclicSuccOfSec
->twinNode()
583 cyclicSuccOfSec
= cyclicSuccOfSec
->cyclicSucc();
585 G
.moveAdjAfter(cyclicSuccOfSec
,secAdj
->twin());
600 /*******************************************************************************
602 ********************************************************************************/
605 // Function computes the cluster planar embedding of a cluster graph
606 // by recursively reinserting the clusters back into Gcopy and embedding
607 // their corresponding subgraphs within the planar embedding of Gcopy.
610 void CconnectClusterPlanarEmbed::recursiveEmbed(ClusterGraph
&Ccopy
,Graph
&Gcopy
)
614 // Remove root cluster from stack.
615 // Induced subgraph of root cluster corresponds to Gcopy
616 cluster root
= m_callStack
.pop();
618 OGDF_ASSERT(Gcopy
.representsCombEmbedding())
620 hubControl(Gcopy
,m_currentHubs
);
622 while (!m_callStack
.empty())
625 // Cluster act is reinserted into Gcopy.
626 cluster act
= m_callStack
.pop();
627 if (m_unsatisfiedCluster
[act
] == true)
630 // subgraph is the graph that replaces the wheelGraph of act in Gcopy
631 Graph
*subGraph
= m_clusterSubgraph
[act
];
632 // embedding contains the (partial) embedding of all biconnected components
633 // that do not have outgoing edges of the cluster act.
634 NodeArray
<SListPure
<adjEntry
> > *embedding
= m_clusterEmbedding
[act
];
635 // For every node of subGraph hubs is true if the node is a hub in subGraph
636 NodeArray
<bool> *hubs
= m_clusterSubgraphHubs
[act
];
637 // For every node in subGraph wheelGraphNodes stores the corresponding
638 // cluster, if the node is a node of a wheel graph
639 NodeArray
<cluster
> *wheelGraphNodes
= m_clusterSubgraphWheelGraph
[act
];
640 EmbedPQTree
*T
= m_clusterPQContainer
[act
].m_T
;
641 EdgeArray
<Stack
<edge
>*> *outgoingAnker
= m_clusterOutgoingEdgesAnker
[act
];
643 // What else do we have:
645 // 1. In m_wheelGraphNodes we have for every node of Gcopy that
646 // is a wheel graph node its corresponding cluster.
647 // Must UPDATE this information after we have replaced the current
648 // wheel graph by subGraph.
652 // 1. When inserting new Nodes to Gcopy, that correspond to nodes of subGraph
653 // copy the information on the wheel graphs (stored in wheelGraphNodes)
654 // 2. When inserting new Nodes to Gcopy, that correspond to nodes of subGraph
655 // copy the information if it is a hub (stored in hubs)
658 //----------------------------------------//
659 // Translation tables between the subgraph and
660 // its corresponding subgraph in Gcopy
661 AdjEntryArray
<adjEntry
> tableAdjEntrySubGraph2Gcopy(*subGraph
);
662 NodeArray
<node
> nodeTableGcopy2SubGraph(Gcopy
,0);
663 NodeArray
<node
> nodeTableSubGraph2Gcopy(*subGraph
,0);
666 //----------------------------------------//
667 // Identify all wheelgraph nodes in Gcopy that correspond to act.
668 // These nodes have to be removed and replaced by subGraph.
670 SList
<node
> replaceNodes
;
671 forall_nodes(v
,Gcopy
)
672 if (m_wheelGraphNodes
[v
] == act
)
673 replaceNodes
.pushBack(v
);
676 //----------------------------------------//
677 // Introduce a new cluster in Gcopy
678 cluster newCluster
= 0;
679 if (m_unsatisfiedCluster
[act
->parent()] == true)
680 newCluster
= Ccopy
.newCluster(Ccopy
.rootCluster());
682 newCluster
= Ccopy
.newCluster(m_clusterTableOrig2Copy
[act
->parent()]);
683 m_clusterTableOrig2Copy
[act
] = newCluster
;
684 m_clusterTableCopy2Orig
[newCluster
] = act
;
687 //----------------------------------------//
688 // Insert for every node of subGraph
689 // a new node in Gcopy.
690 forall_nodes(v
,*subGraph
)
692 if (v
!= m_clusterSuperSink
[act
])
694 node newNode
= Gcopy
.newNode();
695 Ccopy
.reassignNode(newNode
,newCluster
);
696 nodeTableGcopy2SubGraph
[newNode
] = v
;
697 nodeTableSubGraph2Gcopy
[v
] = newNode
;
699 // Copy information from subGraph nodes to new Gcopy nodes.
700 if ((*wheelGraphNodes
)[v
])
701 m_wheelGraphNodes
[newNode
] = (*wheelGraphNodes
)[v
];
703 m_currentHubs
[newNode
] = (*hubs
)[v
];
704 m_nodeTableCopy2Orig
[newNode
] = (*m_clusterNodeTableNew2Orig
[act
])[v
];
709 //----------------------------------------//
710 // Insert the edges between the new nodes
711 EdgeArray
<bool> visited((*subGraph
),false);
712 forall_nodes(v
,*subGraph
)
714 node newV
= nodeTableSubGraph2Gcopy
[v
];
717 if (v
!= m_clusterSuperSink
[act
])
719 forall_adj_edges (e
,v
)
721 node w
= e
->opposite(v
);
723 if (w
!= m_clusterSuperSink
[act
] && !visited
[e
])
725 node newW
= nodeTableSubGraph2Gcopy
[w
];
726 edge eNew
= Gcopy
.newEdge(newV
,newW
);
727 if ((e
->adjSource()->theNode() == v
&&
728 eNew
->adjSource()->theNode() == nodeTableSubGraph2Gcopy
[v
]) ||
729 (e
->adjTarget()->theNode() == v
&&
730 eNew
->adjTarget()->theNode() == nodeTableSubGraph2Gcopy
[v
]))
732 tableAdjEntrySubGraph2Gcopy
[e
->adjSource()] = eNew
->adjSource();
733 tableAdjEntrySubGraph2Gcopy
[e
->adjTarget()] = eNew
->adjTarget();
737 tableAdjEntrySubGraph2Gcopy
[e
->adjTarget()] = eNew
->adjSource();
738 tableAdjEntrySubGraph2Gcopy
[e
->adjSource()] = eNew
->adjTarget();
741 // Copy the information of outgoing edges
743 m_outgoingEdgesAnker
[eNew
] = (*outgoingAnker
)[e
];
749 //edge borderEdge = m_clusterPQContainer[act].m_stEdgeLeaf->userStructKey();
753 //----------------------------------------//
755 edge startEdge
= 0; // first outgoing edge of cluster
756 // start embedding here
757 SListIterator
<node
> its
;
758 for (its
= replaceNodes
.begin(); its
.valid(); its
++)
761 // Assert that v is a node of the wheelgraph belonging
763 OGDF_ASSERT(m_wheelGraphNodes
[v
] == act
)
765 // Traverse all edges adajcent to v to locate an outgoing edge.
767 forall_adj_edges(e
,v
)
769 node w
= e
->opposite(v
);
770 if (act
!= m_wheelGraphNodes
[w
])
772 // Outgoing Edge of wheelgraph detected.
774 its
= replaceNodes
.rbegin(); // break outer for loop
781 // Stack outgoing edges according to embedding
783 // Assert that there is an outgoing edge of the cluster
784 OGDF_ASSERT(startEdge
);
785 List
<edge
> outgoingEdges
;
786 outgoingEdges
.pushBack(startEdge
);
788 adjEntry adj
= startEdge
->adjSource()->theNode() == v
?
789 startEdge
->adjSource() : startEdge
->adjTarget();
790 edge currentEdge
= 0;
791 while (currentEdge
!= startEdge
)
793 adjEntry newAdj
= adj
->cyclicSucc();
794 newAdj
= newAdj
->twin();
795 currentEdge
= newAdj
->theEdge();
796 if (act
!= m_wheelGraphNodes
[newAdj
->theNode()])
798 // Outgoing Edge of wheelgraph detected.
799 if (currentEdge
!= startEdge
)
800 outgoingEdges
.pushBack(currentEdge
);
801 adj
= adj
->cyclicSucc();
808 //----------------------------------------//
809 // Insert the edges between the new nodes and
810 // the existing nodes of Gcopy.
812 PlanarLeafKey
<IndInfo
*>* leftKey
= 0;
813 PlanarLeafKey
<IndInfo
*>* rightKey
= 0;
815 node t
= m_clusterPQContainer
[act
].m_superSink
;
816 SListPure
<PlanarLeafKey
<IndInfo
*>*> allOutgoing
;
819 EdgeArray
<edge
> debugTableOutgoingSubGraph2Gcopy(*subGraph
,0);
822 ListIterator
<edge
> ite
;
823 for (ite
= outgoingEdges
.begin(); ite
.valid();)
826 ListIterator
<edge
> succ
= ite
.succ();
829 // Assert that stack for anker nodes is not empty
830 OGDF_ASSERT(!m_outgoingEdgesAnker
[e
]->empty())
832 node nonWheelNode
; // The node of Gcopy that does not
833 // correspond to cluster act
834 if (act
!= m_wheelGraphNodes
[e
->source()])
835 nonWheelNode
= e
->source();
837 OGDF_ASSERT(act
!= m_wheelGraphNodes
[e
->target()])
838 nonWheelNode
= e
->target();
841 edge subGraphEdge
= m_outgoingEdgesAnker
[e
]->pop();
842 node subGraphNode
= subGraphEdge
->opposite(t
);
845 if (int(ogdf::debugLevel
) >= int(dlHeavyChecks
)){
846 debugTableOutgoingSubGraph2Gcopy
[subGraphEdge
] = e
;}
849 rightKey
= (*m_clusterPQContainer
[act
].m_edge2Key
)[subGraphEdge
];
850 allOutgoing
.pushBack(rightKey
);
853 SListPure
<PlanarLeafKey
<IndInfo
*>*> pair
;
854 pair
.pushBack(leftKey
);
855 pair
.pushBack(rightKey
);
860 // Assert that the Reduction did not fail
862 T
->PQTree
<edge
,IndInfo
*,bool>::emptyAllPertinentNodes();
865 firstEdge
= subGraphEdge
;
869 // Assert that the anker node is a node
871 OGDF_ASSERT(subGraphNode
->graphOf() == subGraph
)
873 // Redirect the edge to the new node.
874 // This keeps the embedding of Gcopy.
875 if (nonWheelNode
== e
->source())
877 Gcopy
.moveTarget(e
, nodeTableSubGraph2Gcopy
[subGraphNode
]);
879 if (subGraphEdge
->source() == subGraphNode
)
881 tableAdjEntrySubGraph2Gcopy
[subGraphEdge
->adjSource()] = e
->adjTarget();
882 tableAdjEntrySubGraph2Gcopy
[subGraphEdge
->adjTarget()] = e
->adjSource();
886 tableAdjEntrySubGraph2Gcopy
[subGraphEdge
->adjSource()] = e
->adjSource();
887 tableAdjEntrySubGraph2Gcopy
[subGraphEdge
->adjTarget()] = e
->adjTarget();
892 Gcopy
.moveSource(e
,nodeTableSubGraph2Gcopy
[subGraphNode
]);
894 if (subGraphEdge
->target() == subGraphNode
)
896 tableAdjEntrySubGraph2Gcopy
[subGraphEdge
->adjSource()] = e
->adjTarget();
897 tableAdjEntrySubGraph2Gcopy
[subGraphEdge
->adjTarget()] = e
->adjSource();
901 tableAdjEntrySubGraph2Gcopy
[subGraphEdge
->adjSource()] = e
->adjSource();
902 tableAdjEntrySubGraph2Gcopy
[subGraphEdge
->adjTarget()] = e
->adjTarget();
910 //----------------------------------------//
911 // Compute an embedding of the subgraph
913 // Mark all leaves as relevant
917 T
->Reduction(allOutgoing
);
918 // Assert that the Reduction did not fail
921 // Stores for every node v the keys corresponding to the incoming edges of v
922 NodeArray
<SListPure
<PlanarLeafKey
<IndInfo
*>* > >* inLeaves
923 = m_clusterPQContainer
[act
].m_inLeaves
;
925 // Stores for every node v the keys corresponding to the outgoing edges of v
926 /*NodeArray<SListPure<PlanarLeafKey<IndInfo*>* > >* outLeaves
927 = m_clusterPQContainer[act].m_outLeaves;*/
929 // Stores for every node v the sequence of incoming edges of v according
931 NodeArray
<SListPure
<edge
> >* frontier
932 = m_clusterPQContainer
[act
].m_frontier
;
934 // Stores for every node v the nodes corresponding to the
935 // opposed sink indicators found in the frontier of v.
936 NodeArray
<SListPure
<node
> >* opposed
937 = m_clusterPQContainer
[act
].m_opposed
;
939 // Stores for every node v the nodes corresponding to the
940 // opposed sink indicators found in the frontier of v.
941 NodeArray
<SListPure
<node
> >* nonOpposed
942 = m_clusterPQContainer
[act
].m_nonOpposed
;
944 // Stores for every node the st-number
945 NodeArray
<int>* numbering
= m_clusterPQContainer
[act
].m_numbering
;
947 // Stores for every st-Number the corresponding node
948 Array
<node
>* tableNumber2Node
= m_clusterPQContainer
[act
].m_tableNumber2Node
;
950 Array
<bool> toReverse(1,(*numbering
)[t
],false);
952 // Get necessary embedding information
953 T
->ReplaceRoot((*inLeaves
)[t
], (*frontier
)[t
], (*opposed
)[t
], (*nonOpposed
)[t
],t
);
956 //---------------------------------------------------------//
957 // Compute a regular embedding of the biconnected component.
959 // Reverse adjacency lists if necessary
960 edge check
= (*frontier
)[t
].front();
962 // Check if the order of edges around t has to be reversed.
963 if (firstEdge
== check
)
964 toReverse
[(*numbering
)[t
]] = true;
967 for (i
= (*numbering
)[t
]; i
>= 2; i
--)
971 while (!(*nonOpposed
)[(*tableNumber2Node
)[i
]].empty())
973 v
= (*nonOpposed
)[(*tableNumber2Node
)[i
]].popFrontRet();
974 OGDF_ASSERT(!toReverse
[(*numbering
)[v
]])
975 toReverse
[(*numbering
)[v
]] = true;
977 (*frontier
)[(*tableNumber2Node
)[i
]].reverse();
981 while (!(*opposed
)[(*tableNumber2Node
)[i
]].empty())
983 v
= (*opposed
)[(*tableNumber2Node
)[i
]].popFrontRet();
984 OGDF_ASSERT(!toReverse
[(*numbering
)[v
]])
985 toReverse
[(*numbering
)[v
]] = true;
988 (*nonOpposed
)[(*tableNumber2Node
)[i
]].clear();
989 (*opposed
)[(*tableNumber2Node
)[i
]].clear();
993 if (int(ogdf::debugLevel
) >= int(dlHeavyChecks
)){
994 cout
<< endl
<< "New Lists after Reversing " << endl
;
995 for (i
= 1; i
<= (*numbering
)[t
]; i
++){v
= (*tableNumber2Node
)[i
];
996 cout
<<"v = "<<v
<<" : "<<" ";SListIterator
<edge
> it
;
997 for(it
=(*frontier
)[v
].begin();it
.valid();it
++)cout
<<*it
<<" ";
1001 // Compute the upward embedding
1003 NodeArray
<SListPure
<adjEntry
> > biCompEmbedding(*subGraph
);
1004 for (i
= 1; i
<= (*numbering
)[t
]; i
++)
1006 v
= (*tableNumber2Node
)[i
];
1007 while (!(*frontier
)[v
].empty())
1009 edge e
= (*frontier
)[v
].popFrontRet();
1010 biCompEmbedding
[v
].pushBack(
1011 (e
->adjSource()->theNode() == v
)? e
->adjSource() : e
->adjTarget());
1015 //---------------------------------------------//
1016 // Compute the entire embedding of the subGraph
1018 NodeArray
<bool> mark(*subGraph
,false);
1019 NodeArray
<SListIterator
<adjEntry
> > adjMarker(*subGraph
,0);
1020 for (i
= 1; i
<= (*numbering
)[t
]; i
++)
1022 v
= (*tableNumber2Node
)[i
];
1023 adjMarker
[v
] = biCompEmbedding
[v
].begin();
1025 v
= (*tableNumber2Node
)[(*numbering
)[t
]];
1026 entireEmbed(*subGraph
,biCompEmbedding
,adjMarker
,mark
,v
);
1029 //--------------------------------------------------//
1030 // Sort the adjacency list of the new nodes in Gcopy
1031 // using the entire embedding of subGraph
1033 NodeArray
<SListPure
<adjEntry
> > embeddingGcopy(Gcopy
);
1035 // Copy Embedding of biconnected Componts with no outging edges first
1037 forall_nodes(v
,(*subGraph
))
1039 SListIterator
<adjEntry
> it
;
1040 for (it
= (*embedding
)[v
].begin(); it
.valid(); it
++)
1041 embeddingGcopy
[nodeTableSubGraph2Gcopy
[v
]].pushBack(
1042 tableAdjEntrySubGraph2Gcopy
[*it
]);
1046 // Copy Embedding of the biconnected componts
1047 // with outging edges. Don't add the outgoing edges
1049 for (i
= 1; i
< (*numbering
)[t
]; i
++)
1051 v
= (*tableNumber2Node
)[i
];
1052 SListIterator
<adjEntry
> it
;
1053 while (!biCompEmbedding
[v
].empty())
1055 adjEntry adj
= biCompEmbedding
[v
].popFrontRet();
1056 (*embedding
)[v
].pushBack(adj
);
1057 embeddingGcopy
[nodeTableSubGraph2Gcopy
[v
]].pushBack(
1058 tableAdjEntrySubGraph2Gcopy
[adj
]);
1063 forall_nodes(v
,*subGraph
)
1065 Gcopy
.sort(nodeTableSubGraph2Gcopy
[v
], embeddingGcopy
[nodeTableSubGraph2Gcopy
[v
]]);
1068 //----------------------------------------//
1069 // Sort the adjacency list of the new cluster nodes in Gcopy
1070 // using the adjacency list of t
1072 SListPure
<adjEntry
> embeddingClusterList
;
1073 while (!biCompEmbedding
[t
].empty())
1075 adjEntry adj
= biCompEmbedding
[t
].popFrontRet();
1076 (*embedding
)[t
].pushBack(adj
);
1077 // Choose the twin of adj, since adj is associated with t
1078 // which is the outside of the cluster.
1079 embeddingClusterList
.pushFront(tableAdjEntrySubGraph2Gcopy
[adj
->twin()]);
1082 Ccopy
.makeAdjEntries(newCluster
,embeddingClusterList
.begin());
1087 //----------------------------------------//
1088 // Delete the wheelGraph nodes from Gcopy
1089 while (!replaceNodes
.empty())
1091 v
= replaceNodes
.popFrontRet();
1092 // Ccopy.unassignNode(v);
1096 OGDF_ASSERT(Gcopy
.representsCombEmbedding())
1099 if (m_clusterEmbedding
[act
] != 0)
1100 delete m_clusterEmbedding
[act
];
1101 delete m_clusterSubgraphHubs
[act
];
1102 delete m_clusterSubgraphWheelGraph
[act
];
1103 delete m_clusterNodeTableNew2Orig
[act
];
1104 delete m_clusterOutgoingEdgesAnker
[act
];
1106 m_clusterPQContainer
[act
].Cleanup();
1108 hubControl(Gcopy
,m_currentHubs
);
1113 forall_edges(e
,Gcopy
)
1115 if (m_outgoingEdgesAnker
[e
])
1116 delete m_outgoingEdgesAnker
[e
];
1119 delete m_clusterSubgraphHubs
[root
];
1120 delete m_clusterSubgraphWheelGraph
[root
];
1121 delete m_clusterOutgoingEdgesAnker
[root
];
1124 Ccopy
.adjAvailable(true);
1131 /*******************************************************************************
1133 ********************************************************************************/
1135 //Checks if the algorithm is applicable (input is c-connected and planar) and
1136 //then calls the planarity test method
1138 bool CconnectClusterPlanarEmbed::preProcess(ClusterGraph
&Ccopy
,Graph
&Gcopy
)
1141 if (!isCConnected(Ccopy
))
1143 ogdf::sprintf(errorCode
,124,"Graph is not Ccopy-connected \n");
1144 m_errorCode
= nonCConnected
;
1148 if (!isPlanar(Ccopy
))
1150 ogdf::sprintf(errorCode
,124,"Graph is not planar\n");
1151 m_errorCode
= nonPlanar
;
1157 SListPure
<node
> selfLoops
;
1158 makeLoopFree(Gcopy
,selfLoops
);
1160 c
= Ccopy
.rootCluster();
1162 bool cPlanar
= planarityTest(Ccopy
,c
,Gcopy
);
1170 /*******************************************************************************
1172 ********************************************************************************/
1175 // Recursive call for testing Planarity of a Cluster
1177 bool CconnectClusterPlanarEmbed::planarityTest(
1178 ClusterGraph
&Ccopy
,
1182 cluster origOfAct
= m_clusterTableCopy2Orig
[act
];
1185 // Test children first
1186 ListConstIterator
<cluster
> it
;
1187 for (it
= act
->cBegin(); it
.valid();)
1189 ListConstIterator
<cluster
> succ
= it
.succ();
1190 cluster next
= (*it
);
1191 if (!planarityTest(Ccopy
,next
,Gcopy
))
1197 m_callStack
.push(origOfAct
);
1199 // Get induced subgraph of cluster act and test it for planarity
1202 if (int(ogdf::debugLevel
) >= int(dlHeavyChecks
)){
1203 cout
<< endl
<< endl
<< "Testing cluster " << origOfAct
->index()<<endl
;}
1206 List
<node
> subGraphNodes
;
1207 ListIterator
<node
> its
;
1208 for (its
= act
->nBegin(); its
.valid(); its
++)
1209 subGraphNodes
.pushBack(*its
);
1211 Graph
*subGraph
= OGDF_NEW
Graph();
1212 NodeArray
<node
> nodeTableOrig2New
;
1213 EdgeArray
<edge
> edgeTableOrig2New
;
1214 inducedSubGraph(Gcopy
, subGraphNodes
.begin(), (*subGraph
), nodeTableOrig2New
, edgeTableOrig2New
);
1215 NodeArray
<node
> nodeTableNew2Orig((*subGraph
),0);
1217 // Necessary only for root cluster.
1218 EdgeArray
<edge
> edgeTableNew2Orig(*subGraph
,0);
1220 if (act
!= Ccopy
.rootCluster())
1222 m_clusterSubgraph
[origOfAct
] = subGraph
;
1223 m_clusterNodeTableNew2Orig
[origOfAct
] = new NodeArray
<node
>((*subGraph
),0);
1224 m_clusterSubgraphHubs
[origOfAct
] = OGDF_NEW NodeArray
<bool>((*subGraph
),0);
1225 m_clusterSubgraphWheelGraph
[origOfAct
] = OGDF_NEW NodeArray
<cluster
>((*subGraph
),0);
1226 m_clusterOutgoingEdgesAnker
[origOfAct
] = OGDF_NEW EdgeArray
<Stack
<edge
>*>((*subGraph
),0);
1227 for (its
= act
->nBegin(); its
.valid(); its
++)
1230 (*m_clusterNodeTableNew2Orig
[origOfAct
])[nodeTableOrig2New
[w
]]
1231 = m_nodeTableCopy2Orig
[w
];
1234 forall_edges(e
,Gcopy
)
1236 if (edgeTableOrig2New
[e
] && m_outgoingEdgesAnker
[e
])
1237 (*m_clusterOutgoingEdgesAnker
[origOfAct
])[edgeTableOrig2New
[e
]]
1238 = m_outgoingEdgesAnker
[e
];
1243 m_clusterSubgraph
[origOfAct
] = &Gcopy
;
1244 m_clusterSubgraphHubs
[origOfAct
] = OGDF_NEW NodeArray
<bool>(Gcopy
,0);
1245 m_clusterSubgraphWheelGraph
[origOfAct
] = OGDF_NEW NodeArray
<cluster
>(Gcopy
,0);
1246 m_clusterOutgoingEdgesAnker
[origOfAct
] = OGDF_NEW EdgeArray
<Stack
<edge
>*>(Gcopy
,0);
1247 for (its
= act
->nBegin(); its
.valid(); its
++)
1250 node ttt
= nodeTableOrig2New
[w
];
1251 nodeTableNew2Orig
[ttt
] = w
;
1254 forall_edges(e
,Gcopy
)
1256 edgeTableNew2Orig
[edgeTableOrig2New
[e
]] = e
;
1257 if (m_outgoingEdgesAnker
[e
])
1258 (*m_clusterOutgoingEdgesAnker
[origOfAct
])[e
]
1259 = m_outgoingEdgesAnker
[e
];
1265 // Introduce super sink and add edges corresponding
1266 // to outgoing edges of the cluster
1268 node superSink
= subGraph
->newNode();
1269 EdgeArray
<node
> outgoingTable((*subGraph
),0);
1271 for (its
= act
->nBegin(); its
.valid(); its
++)
1274 adjEntry adj
= w
->firstAdj();
1277 edge e
= adj
->theEdge();
1279 if (nodeTableOrig2New
[e
->source()] == 0)
1280 // edge is connected to a node outside the cluster
1282 cor
= subGraph
->newEdge(nodeTableOrig2New
[e
->target()],superSink
);
1283 outgoingTable
[cor
] = e
->source();
1284 if (m_outgoingEdgesAnker
[e
])
1285 (*m_clusterOutgoingEdgesAnker
[origOfAct
])[cor
]
1286 = m_outgoingEdgesAnker
[e
];
1288 else if (nodeTableOrig2New
[e
->target()] == 0) // dito
1290 cor
= subGraph
->newEdge(nodeTableOrig2New
[e
->source()],superSink
);
1291 outgoingTable
[cor
] = e
->target();
1292 if (m_outgoingEdgesAnker
[e
])
1293 (*m_clusterOutgoingEdgesAnker
[origOfAct
])[cor
]
1294 = m_outgoingEdgesAnker
[e
]; }
1296 // else edge connects two nodes of the cluster
1299 if (superSink
->degree() == 0) // root cluster is not connected to outside clusters
1301 subGraph
->delNode(superSink
);
1305 m_clusterSuperSink
[origOfAct
] = superSink
;
1308 if (int(ogdf::debugLevel
) >= int(dlHeavyChecks
)){
1310 ogdf::sprintf(filename
,124,"Ccopy%d.gml",origOfAct
->index());
1311 subGraph
->writeGML(filename
);
1316 bool cPlanar
= preparation((*subGraph
),origOfAct
,superSink
);
1319 if (cPlanar
&& act
!= Ccopy
.rootCluster())
1321 // Remove induced subgraph and the cluster act.
1322 // Replace it by a wheel graph
1323 while (!subGraphNodes
.empty())
1325 node w
= subGraphNodes
.popFrontRet();
1326 if (m_currentHubs
[w
])
1327 (*m_clusterSubgraphHubs
[origOfAct
])[nodeTableOrig2New
[w
]]
1329 if (m_wheelGraphNodes
[w
])
1330 (*m_clusterSubgraphWheelGraph
[origOfAct
])[nodeTableOrig2New
[w
]]
1331 = m_wheelGraphNodes
[w
];
1333 // Ccopy.unassignNode(w);
1337 cluster parent
= act
->parent();
1339 if (superSink
&& m_clusterPQContainer
[origOfAct
].m_T
)
1340 constructWheelGraph(Ccopy
,Gcopy
,parent
,origOfAct
,
1341 m_clusterPQContainer
[origOfAct
].m_T
,
1342 outgoingTable
,superSink
);
1345 m_clusterTableOrig2Copy
[origOfAct
] = 0;
1346 Ccopy
.delCluster(act
);
1349 else if (cPlanar
&& act
== Ccopy
.rootCluster())
1353 forall_nodes(w
,Gcopy
)
1355 if (m_currentHubs
[w
])
1356 (*m_clusterSubgraphHubs
[origOfAct
])[w
] = true;
1357 if (m_wheelGraphNodes
[w
])
1358 (*m_clusterSubgraphWheelGraph
[origOfAct
])[w
] = m_wheelGraphNodes
[w
];
1361 forall_nodes(w
,*subGraph
)
1362 subGraph
->sort(w
,(*m_clusterEmbedding
[origOfAct
])[w
]);
1364 forall_nodes(w
,(*subGraph
))
1366 node originalOfw
= nodeTableNew2Orig
[w
];
1368 SListPure
<adjEntry
> adjList
;
1373 edge e
= edgeTableNew2Orig
[a
->theEdge()];
1374 adjEntry adj
= (e
->adjSource()->theNode() == originalOfw
)?
1375 e
->adjSource() : e
->adjTarget();
1376 adjList
.pushBack(adj
);
1379 Gcopy
.sort(originalOfw
,adjList
);
1382 // Test if embedding was determined correctly.
1383 OGDF_ASSERT(subGraph
->representsCombEmbedding())
1385 edgeTableNew2Orig
.init();
1386 outgoingTable
.init();
1387 nodeTableNew2Orig
.init();
1388 delete m_clusterEmbedding
[origOfAct
];
1389 m_clusterEmbedding
[origOfAct
] = 0;
1394 else if (!cPlanar
&& act
== Ccopy
.rootCluster())
1396 edgeTableNew2Orig
.init();
1397 outgoingTable
.init();
1398 nodeTableNew2Orig
.init();
1399 delete m_clusterEmbedding
[origOfAct
];
1400 m_clusterEmbedding
[origOfAct
] = 0;
1406 ogdf::sprintf(errorCode
,124,"Graph is not planar at cluster %d.\n",act
->index());
1407 m_errorCode
= nonCPlanar
;
1418 /*******************************************************************************
1420 ********************************************************************************/
1424 // Prepare planarity test for one cluster
1426 bool CconnectClusterPlanarEmbed::preparation(Graph
&subGraph
,
1427 cluster
&origCluster
,
1433 int bcIdSuperSink
= -1; // ID of biconnected component that contains superSink
1434 // Initialization with -1 necessary for assertion
1435 bool cPlanar
= true;
1438 NodeArray
<node
> tableNodesSubGraph2BiComp(subGraph
,0);
1439 EdgeArray
<edge
> tableEdgesSubGraph2BiComp(subGraph
,0);
1440 NodeArray
<bool> mark(subGraph
,0);
1442 EdgeArray
<int> componentID(subGraph
);
1444 // Generate datastructure for embedding, even if it is left empty.
1445 // Embedding either contains
1446 // Embedding of the root cluster
1448 // Partial Embedding of the biconnected components not having
1451 NodeArray
<SListPure
<adjEntry
> >
1452 *entireEmbedding
= OGDF_NEW NodeArray
<SListPure
<adjEntry
> >(subGraph
);
1453 m_clusterEmbedding
[origCluster
] = entireEmbedding
;
1455 // Determine Biconnected Components
1456 int bcCount
= biconnectedComponents(subGraph
,componentID
);
1458 // Determine edges per biconnected component
1459 Array
<SList
<edge
> > blockEdges(0,bcCount
-1);
1460 forall_edges(e
,subGraph
)
1462 blockEdges
[componentID
[e
]].pushFront(e
);
1465 // Determine nodes per biconnected component.
1466 Array
<SList
<node
> > blockNodes(0,bcCount
-1);
1467 for (int i
= 0; i
< bcCount
; i
++)
1469 SListIterator
<edge
> it
;
1470 for (it
= blockEdges
[i
].begin(); it
.valid(); ++it
)
1473 if (!mark
[e
->source()])
1475 blockNodes
[i
].pushBack(e
->source());
1476 mark
[e
->source()] = true;
1478 if (!mark
[e
->target()])
1480 blockNodes
[i
].pushBack(e
->target());
1481 mark
[e
->target()] = true;
1484 if (superSink
&& mark
[superSink
])
1486 OGDF_ASSERT(bcIdSuperSink
== -1);
1489 SListIterator
<node
> itn
;
1490 for (itn
= blockNodes
[i
].begin(); itn
.valid(); ++itn
)
1497 OGDF_ASSERT(mark
[v
]); // v has been placed two times on the list.
1505 // Perform Planarity Test for every biconnected component
1509 // Compute st-numbering
1510 NodeArray
<int> numbering(subGraph
,0);
1513 n
= stNumber(subGraph
,numbering
,0,superSink
);
1515 n
= stNumber(subGraph
,numbering
);
1516 OGDF_ASSERT_IF(dlConsistencyChecks
,testSTnumber(subGraph
,numbering
,n
))
1518 EdgeArray
<edge
> tableEdgesBiComp2SubGraph(subGraph
,0);
1519 NodeArray
<node
> tableNodesBiComp2SubGraph(subGraph
,0);
1520 forall_edges(e
,subGraph
)
1521 tableEdgesBiComp2SubGraph
[e
] = e
;
1522 forall_nodes(v
,subGraph
)
1523 tableNodesBiComp2SubGraph
[v
] = v
;
1525 // Initialize the container class for storing all information
1526 // if it does not belong to the root cluster.
1527 if (bcIdSuperSink
== 0)
1528 m_clusterPQContainer
[origCluster
].init(&subGraph
);
1536 tableEdgesBiComp2SubGraph
,
1537 tableEdgesBiComp2SubGraph
,
1538 tableNodesBiComp2SubGraph
);
1540 // Do not save the embedding of the subgraph. It is not complete.
1541 if (bcIdSuperSink
== -1)
1543 // The root cluster is embedded.
1544 // Gather the embeddding of the biconnected graph, if it belongs to
1545 // the root cluster.
1546 // The embedding of the subgraph is saved, as it is the root cluster graph.
1547 forall_nodes(v
,subGraph
)
1551 (*entireEmbedding
)[v
].pushBack(a
);
1558 for (int i
= 0; i
< bcCount
; i
++)
1560 Graph
*biCompOfSubGraph
= OGDF_NEW
Graph();
1562 SListIterator
<node
> itn
;
1563 for (itn
= blockNodes
[i
].begin(); itn
.valid(); ++ itn
)
1566 node w
= biCompOfSubGraph
->newNode();
1567 tableNodesSubGraph2BiComp
[v
] = w
;
1570 NodeArray
<node
> tableNodesBiComp2SubGraph(*biCompOfSubGraph
,0);
1571 for (itn
= blockNodes
[i
].begin(); itn
.valid(); ++ itn
)
1572 tableNodesBiComp2SubGraph
[tableNodesSubGraph2BiComp
[*itn
]] = *itn
;
1574 SListIterator
<edge
> it
;
1575 for (it
= blockEdges
[i
].begin(); it
.valid(); ++it
)
1578 edge f
= biCompOfSubGraph
->newEdge(
1579 tableNodesSubGraph2BiComp
[e
->source()], tableNodesSubGraph2BiComp
[e
->target()]);
1580 tableEdgesSubGraph2BiComp
[e
] = f
;
1583 EdgeArray
<edge
> tableEdgesBiComp2SubGraph(*biCompOfSubGraph
,0);
1584 for (it
= blockEdges
[i
].begin(); it
.valid(); ++it
)
1585 tableEdgesBiComp2SubGraph
[tableEdgesSubGraph2BiComp
[*it
]] = *it
;
1587 NodeArray
<int> numbering(*biCompOfSubGraph
,0);
1589 if (bcIdSuperSink
== i
)
1591 n
= stNumber(*biCompOfSubGraph
,numbering
,0,tableNodesSubGraph2BiComp
[superSink
]);
1592 OGDF_ASSERT_IF(dlConsistencyChecks
,testSTnumber(*biCompOfSubGraph
,numbering
,n
))
1594 // Initialize the container class for storing all information
1595 m_clusterPQContainer
[origCluster
].init(&subGraph
);
1601 tableNodesSubGraph2BiComp
[superSink
],
1603 tableEdgesBiComp2SubGraph
,
1604 tableEdgesSubGraph2BiComp
,
1605 tableNodesBiComp2SubGraph
);
1609 n
= stNumber(*biCompOfSubGraph
,numbering
);
1610 OGDF_ASSERT_IF(dlConsistencyChecks
,testSTnumber(*biCompOfSubGraph
,numbering
,n
));
1617 tableEdgesBiComp2SubGraph
,
1618 tableEdgesSubGraph2BiComp
,
1619 tableNodesBiComp2SubGraph
);
1625 tableEdgesBiComp2SubGraph
.init();
1626 tableNodesBiComp2SubGraph
.init();
1627 delete biCompOfSubGraph
;
1631 if (bcIdSuperSink
== -1)
1633 // The root cluster is embedded.
1634 // Gather the embedding of the biconnected graph, if it belongs to
1635 // the root cluster.
1636 // The embedding of the subgraph is saved, as it is the root cluster graph.
1637 forall_nodes(v
,*biCompOfSubGraph
)
1639 node w
= tableNodesBiComp2SubGraph
[v
];
1643 edge e
= tableEdgesBiComp2SubGraph
[a
->theEdge()];
1644 adjEntry adj
= (e
->adjSource()->theNode() == w
)?
1645 e
->adjSource() : e
->adjTarget();
1646 (*entireEmbedding
)[w
].pushBack(adj
);
1650 else if (bcIdSuperSink
!= i
)
1652 // A non root cluster is embedded.
1653 // Gather the embeddings of the biconnected components
1654 // that do not have outgoing edges of the cluster.
1655 forall_nodes(v
,*biCompOfSubGraph
)
1657 node w
= tableNodesBiComp2SubGraph
[v
];
1661 edge e
= tableEdgesBiComp2SubGraph
[a
->theEdge()];
1662 adjEntry adj
= (e
->adjSource()->theNode() == w
)?
1663 e
->adjSource() : e
->adjTarget();
1664 (*entireEmbedding
)[w
].pushBack(adj
);
1670 tableEdgesBiComp2SubGraph
.init();
1671 tableNodesBiComp2SubGraph
.init();
1672 delete biCompOfSubGraph
;
1677 // m_clusterEmbedding[origCluster] now contains the (partial) embedding
1678 // of all biconnected components that do not have outgoing edges
1679 // of the cluster origCluster.
1689 /*******************************************************************************
1691 ********************************************************************************/
1694 // Performs a planarity test on a biconnected component
1695 // of subGraph and embedds it planar.
1696 // numbering contains an st-numbering of the component.
1697 bool CconnectClusterPlanarEmbed::doEmbed(Graph
*biconComp
,
1698 NodeArray
<int> &numbering
,
1699 cluster
&origCluster
,
1702 EdgeArray
<edge
> &tableEdgesBiComp2SubGraph
,
1703 EdgeArray
<edge
> &tableEdgesSubGraph2BiComp
,
1704 NodeArray
<node
> &tableNodesBiComp2SubGraph
)
1707 bool cPlanar
= true;
1710 // incoming edge of v: an edge e = (v,w) with number(v) < number(w)
1713 // Stores for every node v the keys corresponding to the incoming edges of v
1714 NodeArray
<SListPure
<PlanarLeafKey
<IndInfo
*>* > > inLeaves(*biconComp
);
1716 // Stores for every node v the keys corresponding to the outgoing edges of v
1717 NodeArray
<SListPure
<PlanarLeafKey
<IndInfo
*>* > > outLeaves(*biconComp
);
1719 // Stores for every node v the sequence of incoming edges of v according
1721 NodeArray
<SListPure
<edge
> > frontier(*biconComp
);
1723 // Stores for every node v the nodes corresponding to the
1724 // opposed sink indicators found in the frontier of v.
1725 NodeArray
<SListPure
<node
> > opposed(*biconComp
);
1727 // Stores for every node v the nodes corresponding to the
1728 // non opposed sink indicators found in the frontier of v.
1729 NodeArray
<SListPure
<node
> > nonOpposed(*biconComp
);
1731 // Stores for every st-Number the corresponding node
1732 Array
<node
> tableNumber2Node(biconComp
->numberOfNodes()+1);
1734 Array
<bool> toReverse(1,biconComp
->numberOfNodes()+1,false);
1736 PlanarLeafKey
<IndInfo
*>* stEdgeLeaf
;
1738 forall_nodes(v
,*biconComp
)
1742 forall_adj_edges(e
,v
)
1744 if (numbering
[e
->opposite(v
)] > numbering
[v
])
1746 PlanarLeafKey
<IndInfo
*>* L
= OGDF_NEW PlanarLeafKey
<IndInfo
*>(e
);
1747 inLeaves
[v
].pushFront(L
);
1748 if (numbering
[v
] == 1 && numbering
[e
->opposite(v
)])
1752 tableNumber2Node
[numbering
[v
]] = v
;
1755 forall_nodes(v
,*biconComp
)
1757 SListIterator
<PlanarLeafKey
<IndInfo
*>* > it
;
1758 for (it
= inLeaves
[v
].begin(); it
.valid(); ++it
)
1760 PlanarLeafKey
<IndInfo
*>* L
= *it
;
1761 outLeaves
[L
->userStructKey()->opposite(v
)].pushFront(L
);
1765 EmbedPQTree
* T
= new EmbedPQTree();
1767 T
->Initialize(inLeaves
[tableNumber2Node
[1]]);
1769 for (i
= 2; i
< biconComp
->numberOfNodes(); i
++)
1771 if (T
->Reduction(outLeaves
[tableNumber2Node
[i
]]))
1774 inLeaves
[tableNumber2Node
[i
]],
1775 frontier
[tableNumber2Node
[i
]],
1776 opposed
[tableNumber2Node
[i
]],
1777 nonOpposed
[tableNumber2Node
[i
]],
1778 tableNumber2Node
[i
]);
1779 T
->emptyAllPertinentNodes();
1788 if (cPlanar
&& superSink
)
1790 // The tested component contains the outgoing edges
1793 // Keep the PQTree to construct a Wheelgraph
1794 // Replace the edge stored in the keys of T
1795 // by the original edges.
1796 // Necessary, since the edges currently in T
1797 // correspond to a graph that mirrors a biconnected
1798 // component and thus is deallocated
1800 // For embedding the graph, we need to keep the
1803 SListIterator
<PlanarLeafKey
<IndInfo
*>* > it
;
1804 //int n = biconComp->numberOfNodes();
1806 // Replace the edge stored in the keys of T
1807 // by the original edges.
1810 //--------------------------------------//
1811 // All information that we keep is dependend on subGraph.
1812 // Translate the information back from biconComp to subGraph.
1815 m_clusterPQContainer
[origCluster
].m_superSink
1816 = tableNodesBiComp2SubGraph
[superSink
];
1818 forall_nodes(v
,*biconComp
)
1820 // Replace the edge stored in the every key used for constructing T
1821 // by the original edges.
1822 // This implicity replaces the keys at the leaves and at inLeaves.
1825 node orig
= tableNodesBiComp2SubGraph
[v
];
1827 // Assert that m_outLeaves is empty
1828 OGDF_ASSERT((*m_clusterPQContainer
[origCluster
].m_outLeaves
)[orig
].empty())
1829 for (it
= outLeaves
[v
].begin(); it
.valid(); ++it
)
1831 PlanarLeafKey
<IndInfo
*>* key
= *it
;
1832 key
->m_userStructKey
= tableEdgesBiComp2SubGraph
[key
->m_userStructKey
];
1833 (*m_clusterPQContainer
[origCluster
].m_edge2Key
)[key
->m_userStructKey
] = key
;
1834 (*m_clusterPQContainer
[origCluster
].m_outLeaves
)[orig
].pushBack(key
);
1837 // Assert that m_inLeaves is empty
1838 OGDF_ASSERT((*m_clusterPQContainer
[origCluster
].m_inLeaves
)[orig
].empty())
1839 for (it
= inLeaves
[v
].begin(); it
.valid(); ++it
)
1841 PlanarLeafKey
<IndInfo
*>* key
= *it
;
1842 (*m_clusterPQContainer
[origCluster
].m_inLeaves
)[orig
].pushBack(key
);
1845 // Replace the nodes stored in the lists opposed and nonOpposed
1846 // by the original nodes
1848 // Assert that m_opposed and m_nonOpposed are empty
1849 OGDF_ASSERT((*m_clusterPQContainer
[origCluster
].m_opposed
)[orig
].empty())
1850 OGDF_ASSERT((*m_clusterPQContainer
[origCluster
].m_nonOpposed
)[orig
].empty())
1851 SListIterator
<node
> itn
;
1852 for (itn
= nonOpposed
[v
].begin(); itn
.valid(); itn
++)
1854 node w
= tableNodesBiComp2SubGraph
[(*itn
)];
1855 (*m_clusterPQContainer
[origCluster
].m_nonOpposed
)[orig
].pushBack(w
);
1857 for (itn
= opposed
[v
].begin(); itn
.valid(); itn
++)
1859 node w
= tableNodesBiComp2SubGraph
[(*itn
)];
1860 (*m_clusterPQContainer
[origCluster
].m_opposed
)[orig
].pushBack(w
);
1863 (*m_clusterPQContainer
[origCluster
].m_numbering
)[orig
] = numbering
[v
];
1864 (*m_clusterPQContainer
[origCluster
].m_tableNumber2Node
)[numbering
[v
]] = orig
;
1867 // Replace the edges stored in frontier
1868 // by the original edges of subgraph.
1870 OGDF_ASSERT((*m_clusterPQContainer
[origCluster
].m_frontier
)[orig
].empty())
1871 SListIterator
<edge
> ite
;
1872 for (ite
= frontier
[v
].begin(); ite
.valid(); ite
++)
1874 edge e
= tableEdgesBiComp2SubGraph
[(*ite
)];
1875 (*m_clusterPQContainer
[origCluster
].m_frontier
)[orig
].pushBack(e
);
1880 m_clusterPQContainer
[origCluster
].m_T
= T
;
1881 m_clusterPQContainer
[origCluster
].m_stEdgeLeaf
= stEdgeLeaf
;
1882 SListPure
<PQBasicKey
<edge
,IndInfo
*,bool>*> leafKeys
;
1883 T
->getFront(T
->root(),leafKeys
);
1884 SListIterator
<PQBasicKey
<edge
,IndInfo
*,bool>* > itk
;
1885 for (itk
= leafKeys
.begin(); itk
.valid(); itk
++)
1887 if ((*itk
)->nodePointer()->status() == PQNodeRoot::INDICATOR
)
1889 node ofInd
= (*itk
)->nodePointer()->getNodeInfo()->userStructInfo()->getAssociatedNode();
1890 (*itk
)->nodePointer()->getNodeInfo()->userStructInfo()->resetAssociatedNode(tableNodesBiComp2SubGraph
[ofInd
]);
1896 // The tested component does not contain outgoing edges
1898 // Compute a regular embedding of the biconnected component.
1899 int i
= biconComp
->numberOfNodes();
1900 if (T
->Reduction(outLeaves
[tableNumber2Node
[i
]]))
1903 inLeaves
[tableNumber2Node
[i
]],
1904 frontier
[tableNumber2Node
[i
]],
1905 opposed
[tableNumber2Node
[i
]],
1906 nonOpposed
[tableNumber2Node
[i
]],
1907 tableNumber2Node
[i
]);
1913 if (!origCluster
|| !superSink
|| !cPlanar
)
1914 // Do not cleanup information of component
1915 // with outgoing edges.
1917 forall_nodes(v
,*biconComp
)
1919 if (v
!= superSink
|| !cPlanar
)
1921 while (!outLeaves
[v
].empty())
1923 PlanarLeafKey
<IndInfo
*>* L
= outLeaves
[v
].popFrontRet();
1933 if (cPlanar
&& (!origCluster
|| !superSink
))
1935 // The tested component does not contain outgoing edges
1937 // Compute a regular embedding of the biconnected component.
1939 // Reverse adjacency lists if necessary
1940 // This gives an upward embedding
1941 for (i
= biconComp
->numberOfNodes(); i
>= 2; i
--)
1945 while (!nonOpposed
[tableNumber2Node
[i
]].empty())
1947 v
= nonOpposed
[tableNumber2Node
[i
]].popFrontRet();
1948 OGDF_ASSERT(!toReverse
[numbering
[v
]])
1949 toReverse
[numbering
[v
]] = true;
1951 frontier
[tableNumber2Node
[i
]].reverse();
1955 while (!opposed
[tableNumber2Node
[i
]].empty())
1957 v
= opposed
[tableNumber2Node
[i
]].popFrontRet();
1958 OGDF_ASSERT(!toReverse
[numbering
[v
]])
1959 toReverse
[numbering
[v
]] = true;
1962 nonOpposed
[tableNumber2Node
[i
]].clear();
1963 opposed
[tableNumber2Node
[i
]].clear();
1966 // Compute the entire embedding
1967 NodeArray
<SListPure
<adjEntry
> > entireEmbedding(*biconComp
);
1968 forall_nodes(v
,*biconComp
)
1970 while (!frontier
[v
].empty())
1972 edge e
= frontier
[v
].popFrontRet();
1973 entireEmbedding
[v
].pushBack(
1974 (e
->adjSource()->theNode() == v
)? e
->adjSource() : e
->adjTarget());
1979 NodeArray
<bool> mark(*biconComp
,false);
1980 NodeArray
<SListIterator
<adjEntry
> > adjMarker(*biconComp
,0);
1981 forall_nodes(v
,*biconComp
)
1982 adjMarker
[v
] = entireEmbedding
[v
].begin();
1983 v
= tableNumber2Node
[biconComp
->numberOfNodes()];
1984 entireEmbed(*biconComp
,entireEmbedding
,adjMarker
,mark
,v
);
1987 forall_nodes(v
,*biconComp
)
1988 biconComp
->sort(v
,entireEmbedding
[v
]);
1990 // Test if embedding was determined correctly.
1991 OGDF_ASSERT(biconComp
->representsCombEmbedding())
2004 /*******************************************************************************
2006 ********************************************************************************/
2009 // Used by doEmbed. Computes an entire embedding from an
2010 // upward embedding.
2011 void CconnectClusterPlanarEmbed::entireEmbed(
2013 NodeArray
<SListPure
<adjEntry
> > &entireEmbedding
,
2014 NodeArray
<SListIterator
<adjEntry
> > &adjMarker
,
2015 NodeArray
<bool> &mark
,
2019 SListIterator
<adjEntry
> it
;
2020 for (it
= adjMarker
[v
]; it
.valid(); ++it
)
2023 edge e
= a
->theEdge();
2024 adjEntry adj
= (e
->adjSource()->theNode() == v
)?
2025 e
->adjTarget() : e
->adjSource();
2026 node w
= adj
->theNode();
2027 entireEmbedding
[w
].pushFront(adj
);
2029 entireEmbed(biconComp
,entireEmbedding
,adjMarker
,mark
,w
);
2038 /*******************************************************************************
2039 prepareParallelEdges
2040 ********************************************************************************/
2043 void CconnectClusterPlanarEmbed::prepareParallelEdges(Graph
&G
)
2048 // Stores for one reference edge all parallel edges.
2049 m_parallelEdges
.init(G
);
2050 // Is true for any multiedge, except for the reference edge.
2051 m_isParallel
.init(G
,false);
2052 getParallelFreeUndirected(G
,m_parallelEdges
);
2053 m_parallelCount
= 0;
2056 if (!m_parallelEdges
[e
].empty())
2058 ListIterator
<edge
> it
;
2059 for (it
= m_parallelEdges
[e
].begin(); it
.valid(); it
++)
2061 m_isParallel
[*it
] = true;
2071 /*******************************************************************************
2073 ********************************************************************************/
2076 void CconnectClusterPlanarEmbed::constructWheelGraph(ClusterGraph
&Ccopy
,
2081 EdgeArray
<node
> &outgoingTable
,
2085 OGDF_ASSERT(Ccopy
.consistencyCheck());
2086 PQNode
<edge
,IndInfo
*,bool>* root
= T
->root();
2087 PQNode
<edge
,IndInfo
*,bool>* checkNode
= 0;
2089 Queue
<PQNode
<edge
,IndInfo
*,bool>*> treeNodes
;
2090 treeNodes
.append(root
);
2092 node correspond
= Gcopy
.newNode(); // Corresponds to the root node.
2093 // root node is either a leaf or a P-node
2094 m_nodeTableCopy2Orig
[correspond
] = 0; // Node does not correspond to a node
2095 // in the original graph
2096 m_wheelGraphNodes
[correspond
] = origOfAct
;
2097 Ccopy
.reassignNode(correspond
,parent
);
2099 Queue
<node
> graphNodes
;
2100 graphNodes
.append(correspond
);
2105 node newNode
; // corresponds to anchor of a hub or a cut node
2109 while (!treeNodes
.empty())
2111 checkNode
= treeNodes
.pop();
2112 correspond
= graphNodes
.pop();
2114 PQNode
<edge
,IndInfo
*,bool>* firstSon
= 0;
2115 PQNode
<edge
,IndInfo
*,bool>* nextSon
= 0;
2116 PQNode
<edge
,IndInfo
*,bool>* oldSib
= 0;
2117 PQNode
<edge
,IndInfo
*,bool>* holdSib
= 0;
2120 if (checkNode
->type() == PQNodeRoot::PNode
)
2122 // correspond is a cut node
2124 OGDF_ASSERT(checkNode
->referenceChild())
2125 firstSon
= checkNode
->referenceChild();
2127 if (firstSon
->type() != PQNodeRoot::leaf
)
2129 treeNodes
.append(firstSon
);
2130 newNode
= Gcopy
.newNode();
2131 m_nodeTableCopy2Orig
[newNode
] = 0;
2132 m_wheelGraphNodes
[newNode
] = origOfAct
;
2133 Ccopy
.reassignNode(newNode
,parent
);
2134 graphNodes
.append(newNode
);
2135 Gcopy
.newEdge(correspond
,newNode
);
2139 // insert Edge to the outside
2140 PQLeaf
<edge
,IndInfo
*,bool>* leaf
=
2141 (PQLeaf
<edge
,IndInfo
*,bool>*) firstSon
;
2142 edge f
= leaf
->getKey()->m_userStructKey
;
2143 //node x = outgoingTable[f];
2144 edge newEdge
= Gcopy
.newEdge(correspond
,outgoingTable
[f
]);
2147 if ((*m_clusterOutgoingEdgesAnker
[origOfAct
])[f
])
2149 m_outgoingEdgesAnker
[newEdge
]
2150 = (*m_clusterOutgoingEdgesAnker
[origOfAct
])[f
];
2153 m_outgoingEdgesAnker
[newEdge
] = OGDF_NEW Stack
<edge
>;
2154 m_outgoingEdgesAnker
[newEdge
]->push(f
);
2157 nextSon
= firstSon
->getNextSib(oldSib
);
2160 while (nextSon
&& nextSon
!= firstSon
)
2162 if (nextSon
->type() != PQNodeRoot::leaf
)
2164 treeNodes
.append(nextSon
);
2165 newNode
= Gcopy
.newNode(); // new node corresponding to anchor
2167 m_nodeTableCopy2Orig
[newNode
] = 0;
2168 m_wheelGraphNodes
[newNode
] = origOfAct
;
2169 Ccopy
.reassignNode(newNode
,parent
);
2170 graphNodes
.append(newNode
);
2171 Gcopy
.newEdge(correspond
,newNode
);
2175 // insert Edge to the outside
2176 PQLeaf
<edge
,IndInfo
*,bool>* leaf
=
2177 (PQLeaf
<edge
,IndInfo
*,bool>*) nextSon
;
2178 edge f
= leaf
->getKey()->m_userStructKey
;
2179 //node x = outgoingTable[f];
2180 edge newEdge
= Gcopy
.newEdge(correspond
,outgoingTable
[f
]);
2182 if ((*m_clusterOutgoingEdgesAnker
[origOfAct
])[f
])
2184 m_outgoingEdgesAnker
[newEdge
]
2185 = (*m_clusterOutgoingEdgesAnker
[origOfAct
])[f
];
2188 m_outgoingEdgesAnker
[newEdge
] = OGDF_NEW Stack
<edge
>;
2189 m_outgoingEdgesAnker
[newEdge
]->push(f
);
2191 holdSib
= nextSon
->getNextSib(oldSib
);
2197 else if (checkNode
->type() == PQNodeRoot::QNode
)
2200 // correspond is the achor of a hub
2201 OGDF_ASSERT(T
->scanLeftEndmost(checkNode
))
2202 firstSon
= T
->scanLeftEndmost(checkNode
);
2204 hub
= Gcopy
.newNode();
2205 m_nodeTableCopy2Orig
[hub
] = 0;
2206 m_currentHubs
[hub
] = true;
2207 m_wheelGraphNodes
[hub
] = origOfAct
;
2208 Ccopy
.reassignNode(hub
,parent
);
2210 Gcopy
.newEdge(hub
,correspond
); // link achor and hub
2211 next
= Gcopy
.newNode(); // for first son
2212 m_nodeTableCopy2Orig
[next
] = 0;
2213 m_wheelGraphNodes
[next
] = origOfAct
;
2214 Ccopy
.reassignNode(next
,parent
);
2215 Gcopy
.newEdge(hub
,next
);
2216 Gcopy
.newEdge(correspond
,next
);
2218 if (firstSon
->type() != PQNodeRoot::leaf
)
2220 treeNodes
.append(firstSon
);
2221 newNode
= Gcopy
.newNode();
2222 m_nodeTableCopy2Orig
[newNode
] = 0;
2223 m_wheelGraphNodes
[newNode
] = origOfAct
;
2224 Ccopy
.reassignNode(newNode
,parent
);
2225 graphNodes
.append(newNode
);
2226 Gcopy
.newEdge(next
,newNode
);
2230 // insert Edge to the outside
2231 PQLeaf
<edge
,IndInfo
*,bool>* leaf
=
2232 (PQLeaf
<edge
,IndInfo
*,bool>*) firstSon
;
2233 edge f
= leaf
->getKey()->m_userStructKey
;
2234 //node x = outgoingTable[f];
2235 edge newEdge
= Gcopy
.newEdge(next
,outgoingTable
[f
]);
2237 if ((*m_clusterOutgoingEdgesAnker
[origOfAct
])[f
])
2239 m_outgoingEdgesAnker
[newEdge
]
2240 = (*m_clusterOutgoingEdgesAnker
[origOfAct
])[f
];
2243 m_outgoingEdgesAnker
[newEdge
] = OGDF_NEW Stack
<edge
>;
2244 m_outgoingEdgesAnker
[newEdge
]->push(f
);
2247 nextSon
= T
->scanNextSib(firstSon
,oldSib
);
2252 next
= Gcopy
.newNode();
2253 m_nodeTableCopy2Orig
[next
] = 0;
2254 m_wheelGraphNodes
[next
] = origOfAct
;
2255 Ccopy
.reassignNode(next
,parent
);
2256 Gcopy
.newEdge(hub
,next
);
2257 Gcopy
.newEdge(pre
,next
);
2258 if (nextSon
->type() != PQNodeRoot::leaf
)
2260 treeNodes
.append(nextSon
);
2261 newNode
= Gcopy
.newNode(); // new node corresponding to anchor
2263 m_nodeTableCopy2Orig
[newNode
] = 0;
2264 m_wheelGraphNodes
[newNode
] = origOfAct
;
2265 Ccopy
.reassignNode(newNode
,parent
);
2266 graphNodes
.append(newNode
);
2268 Gcopy
.newEdge(next
,newNode
);
2272 // insert Edge to the outside
2273 PQLeaf
<edge
,IndInfo
*,bool>* leaf
=
2274 (PQLeaf
<edge
,IndInfo
*,bool>*) nextSon
;
2275 edge f
= leaf
->getKey()->m_userStructKey
;
2276 //node x = outgoingTable[f];
2277 edge newEdge
= Gcopy
.newEdge(next
,outgoingTable
[f
]);
2279 if ((*m_clusterOutgoingEdgesAnker
[origOfAct
])[f
])
2281 m_outgoingEdgesAnker
[newEdge
]
2282 = (*m_clusterOutgoingEdgesAnker
[origOfAct
])[f
];
2285 m_outgoingEdgesAnker
[newEdge
] = OGDF_NEW Stack
<edge
>;
2286 m_outgoingEdgesAnker
[newEdge
]->push(f
);
2288 holdSib
= T
->scanNextSib(nextSon
,oldSib
);
2294 Gcopy
.newEdge(next
,correspond
);
2298 OGDF_ASSERT(Ccopy
.consistencyCheck());
2299 }// constructWheelGraph
2302 } // end namespace ogdf