6 * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $
7 ***************************************************************/
10 * \brief Implements the class NonPlanarCore.
12 * \author Carsten Gutwenger
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/planarity/NonPlanarCore.h>
45 #include <ogdf/decomposition/StaticSPQRTree.h>
46 #include <ogdf/basic/extended_graph_alg.h>
47 #include <ogdf/basic/Queue.h>
48 #include <ogdf/basic/CombinatorialEmbedding.h>
49 #include <ogdf/basic/FaceArray.h>
55 NonPlanarCore::NonPlanarCore(const Graph
&G
) : m_pOriginal(&G
), m_orig(m_graph
),
56 m_real(m_graph
,0), m_mincut(m_graph
), m_cost(m_graph
)
58 if(G
.numberOfNodes() <= 4)
59 return; // nothing to do; planar graph => empty core
61 // Build SPQR-tree of graph
64 // mark tree nodes in the core
68 NodeArray
<node
> map(G
,0);
69 NodeArray
<node
> mapAux(G
,0);
70 const Graph
&tree
= T
.tree();
73 forall_nodes(v
,tree
) {
77 Skeleton
&S
= T
.skeleton(v
);
79 forall_edges(e
,S
.getGraph()) {
80 node src
= S
.original(e
->source());
81 node tgt
= S
.original(e
->target());
84 m_orig
[map
[src
] = m_graph
.newNode()] = S
.original(e
->source());
87 m_orig
[map
[tgt
] = m_graph
.newNode()] = S
.original(e
->target());
91 node w
= S
.twinTreeNode(e
);
92 if(mark
[w
] == false) {
93 // new virtual edge in core graph
94 edge eC
= m_graph
.newEdge(map
[src
],map
[tgt
]);
95 traversingPath(S
,e
,m_mincut
[eC
],mapAux
);
99 // new real edge in core graph
100 edge eC
= m_graph
.newEdge(map
[src
],map
[tgt
]);
101 m_real
[eC
] = S
.realEdge(e
);
102 m_mincut
[eC
].pushBack(S
.realEdge(e
));
108 forall_edges(e
, m_graph
) {
109 m_cost
[e
] = m_mincut
[e
].size();
114 // This function marks all nodes in the SPQR-tree which induce the
116 void NonPlanarCore::markCore(const SPQRTree
&T
, NodeArray
<bool> &mark
)
118 const Graph
&tree
= T
.tree();
120 // We mark every tree node that belongs to the core
121 mark
.init(tree
,true); // start with all nodes and unmark planar leaves
122 NodeArray
<int> degree(tree
);
127 forall_nodes(v
,tree
) {
128 degree
[v
] = v
->degree();
129 if(degree
[v
] <= 1) // also append deg-0 node (T has only one node)
137 // if v has a planar skeleton
138 if(T
.typeOf(v
) != SPQRTree::RNode
||
139 isPlanar(T
.skeleton(v
).getGraph()) == true)
141 mark
[v
] = false; // unmark this leaf
146 node x
= adj
->twinNode();
147 if(mark
[x
] == true) {
161 struct OGDF_EXPORT QueueEntry
163 QueueEntry(node p
, node v
) : m_parent(p
), m_current(v
) { }
169 void NonPlanarCore::traversingPath(Skeleton
&Sv
, edge eS
, List
<edge
> &path
, NodeArray
<node
> &mapV
)
171 const SPQRTree
&T
= Sv
.owner();
173 //-----------------------------------------------------
174 // Build the graph representing the planar st-component
176 EdgeArray
<edge
> mapE(H
,0);
177 SListPure
<node
> nodes
;
180 Q
.append(QueueEntry(Sv
.treeNode(),Sv
.twinTreeNode(eS
)));
184 QueueEntry x
= Q
.pop();
185 node parent
= x
.m_parent
;
186 node current
= x
.m_current
;
188 const Skeleton
&S
= T
.skeleton(current
);
191 forall_edges(e
,S
.getGraph()) {
192 if(S
.isVirtual(e
) == true)
195 node src
= S
.original(e
->source());
196 node tgt
= S
.original(e
->target());
200 mapV
[src
] = H
.newNode();
204 mapV
[tgt
] = H
.newNode();
207 mapE
[H
.newEdge(mapV
[src
],mapV
[tgt
])] = S
.realEdge(e
);
211 forall_adj(adj
,current
) {
212 node w
= adj
->twinNode();
214 Q
.append(QueueEntry(current
,w
));
219 edge e_st
= H
.newEdge(mapV
[Sv
.original(eS
->source())],mapV
[Sv
.original(eS
->target())]);
221 // Compute planar embedding of H
227 CombinatorialEmbedding
E(H
);
229 //---------------------------------
230 // Compute corresponding dual graph
232 FaceArray
<node
> nodeOf(E
);
233 EdgeArray
<adjEntry
> primalAdj(dual
);
235 // insert a node in the dual graph for each face in E
238 nodeOf
[f
] = dual
.newNode();
241 node s
= nodeOf
[E
.rightFace(e_st
->adjSource())];
242 node t
= nodeOf
[E
.rightFace(e_st
->adjTarget())];
244 // Insert an edge into the dual graph for each adjacency entry in E.
245 // The edges are directed from the left face to the right face.
252 // do not insert edges crossing e_st
253 if(adj
->theEdge() == e_st
)
256 node vLeft
= nodeOf
[E
.leftFace (adj
)];
257 node vRight
= nodeOf
[E
.rightFace(adj
)];
259 primalAdj
[dual
.newEdge(vLeft
,vRight
)] = adj
;
263 //---------------------------
264 // Find shortest path in dual
265 NodeArray
<edge
> spPred(dual
,0);
266 QueuePure
<edge
> queue
;
269 forall_adj_edges(eDual
,s
) {
270 if(s
== eDual
->source())
274 // actual search (using bfs on directed dual)
277 // next candidate edge
278 edge eCand
= queue
.pop();
279 node v
= eCand
->target();
281 // leads to an unvisited node?
284 // yes, then we set v's predecessor in search tree
287 // have we reached t ...
290 // ... then search is done.
291 // constructed list of used edges (translated to crossed
292 // edges entries in G) from t back to s (including first
296 edge eDual
= spPred
[v
];
297 edge eG
= mapE
[primalAdj
[eDual
]->theEdge()];
306 // append next candidate edges to queue
307 // (all edges leaving v)
309 forall_adj_edges(e
,v
) {
310 if (v
== e
->source())
319 SListConstIterator
<node
> it
;
320 for(it
= nodes
.begin(); it
.valid(); ++it
)
325 } // end namespace ogdf