6 * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $
7 ***************************************************************/
10 * \brief Implementation of class PlanarSPQRTree
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/decomposition/PlanarSPQRTree.h>
45 #include <ogdf/basic/extended_graph_alg.h>
50 //-------------------------------------------------------------------
52 //-------------------------------------------------------------------
55 // initialization: additionally embeds skeleton graphs or adpots embedding
56 // given by original graph
57 void PlanarSPQRTree::init(bool isEmbedded
)
65 forall_nodes(v
,tree())
66 planarEmbed(skeleton(v
).getGraph());
71 void PlanarSPQRTree::adoptEmbedding()
73 OGDF_ASSERT_IF(dlExtendedChecking
, originalGraph().representsCombEmbedding());
75 // ordered list of adjacency entries (for one original node) in all
76 // skeletons (where this node occurs)
77 NodeArray
<SListPure
<adjEntry
> > adjEdges(tree());
78 // copy in skeleton of current original node
79 NodeArray
<node
> currentCopy(tree(),0);
80 NodeArray
<adjEntry
> lastAdj(tree(),0);
81 SListPure
<node
> current
; // currently processed nodes
84 forall_nodes(vOrig
,originalGraph())
87 forall_adj(adjOrig
,vOrig
)
89 edge eOrig
= adjOrig
->theEdge();
90 const Skeleton
&S
= skeletonOfReal(eOrig
);
91 edge eCopy
= copyOfReal(eOrig
);
93 adjEntry adjCopy
= (S
.original(eCopy
->source()) == vOrig
) ?
94 eCopy
->adjSource() : eCopy
->adjTarget();
96 setPosInEmbedding(adjEdges
,currentCopy
,lastAdj
,current
,S
,adjCopy
);
99 SListConstIterator
<node
> it
;
100 for(it
= current
.begin(); it
.valid(); ++it
) {
103 skeleton(vT
).getGraph().sort(currentCopy
[vT
],adjEdges
[vT
]);
105 adjEdges
[vT
].clear();
114 void PlanarSPQRTree::setPosInEmbedding(
115 NodeArray
<SListPure
<adjEntry
> > &adjEdges
,
116 NodeArray
<node
> ¤tCopy
,
117 NodeArray
<adjEntry
> &lastAdj
,
118 SListPure
<node
> ¤t
,
122 node vT
= S
.treeNode();
124 adjEdges
[vT
].pushBack(adj
);
126 node vCopy
= adj
->theNode();
127 node vOrig
= S
.original(vCopy
);
129 if(currentCopy
[vT
] == 0) {
130 currentCopy
[vT
] = vCopy
;
131 current
.pushBack(vT
);
134 forall_adj(adjVirt
,vCopy
) {
135 edge eCopy
= S
.twinEdge(adjVirt
->theEdge());
136 if (eCopy
== 0) continue;
137 if (adjVirt
== adj
) {
142 const Skeleton
&STwin
= skeleton(S
.twinTreeNode(adjVirt
->theEdge()));
144 adjEntry adjCopy
= (STwin
.original(eCopy
->source()) == vOrig
) ?
145 eCopy
->adjSource() : eCopy
->adjTarget();
147 setPosInEmbedding(adjEdges
,currentCopy
,lastAdj
,current
,
151 } else if (lastAdj
[vT
] != 0 && lastAdj
[vT
] != adj
) {
152 adjEntry adjVirt
= lastAdj
[vT
];
153 edge eCopy
= S
.twinEdge(adjVirt
->theEdge());
155 const Skeleton
&STwin
= skeleton(S
.twinTreeNode(adjVirt
->theEdge()));
157 adjEntry adjCopy
= (STwin
.original(eCopy
->source()) == vOrig
) ?
158 eCopy
->adjSource() : eCopy
->adjTarget();
160 setPosInEmbedding(adjEdges
,currentCopy
,lastAdj
,current
,
170 // embed original graph according to embedding of skeletons
172 // The procedure also handles the case when some (real or virtual)
173 // edges are reversed (used in upward-planarity algorithms)
174 void PlanarSPQRTree::embed(Graph
&G
)
176 OGDF_ASSERT(&G
== &originalGraph());
178 const Skeleton
&S
= skeleton(rootNode());
179 const Graph
&M
= S
.getGraph();
184 node vOrig
= S
.original(v
);
185 SListPure
<adjEntry
> adjEdges
;
189 edge e
= adj
->theEdge();
190 edge eOrig
= S
.realEdge(e
);
193 adjEntry adjOrig
= (vOrig
== eOrig
->source()) ?
194 eOrig
->adjSource() : eOrig
->adjTarget();
195 OGDF_ASSERT(adjOrig
->theNode() == S
.original(v
));
196 adjEdges
.pushBack(adjOrig
);
199 node wT
= S
.twinTreeNode(e
);
200 edge eTwin
= S
.twinEdge(e
);
201 expandVirtualEmbed(wT
,
202 (vOrig
== skeleton(wT
).original(eTwin
->source())) ?
203 eTwin
->adjSource() : eTwin
->adjTarget(),
208 G
.sort(vOrig
,adjEdges
);
212 forall_adj_edges(e
,rootNode()) {
213 node wT
= e
->target();
214 if (wT
!= rootNode())
215 createInnerVerticesEmbed(G
, wT
);
220 void PlanarSPQRTree::expandVirtualEmbed(node vT
,
222 SListPure
<adjEntry
> &adjEdges
)
224 const Skeleton
&S
= skeleton(vT
);
226 node v
= adjVirt
->theNode();
227 node vOrig
= S
.original(v
);
230 for (adj
= adjVirt
->cyclicSucc(); adj
!= adjVirt
; adj
= adj
->cyclicSucc())
232 edge e
= adj
->theEdge();
233 edge eOrig
= S
.realEdge(e
);
236 adjEntry adjOrig
= (vOrig
== eOrig
->source()) ?
237 eOrig
->adjSource() : eOrig
->adjTarget();
238 OGDF_ASSERT(adjOrig
->theNode() == S
.original(v
));
239 adjEdges
.pushBack(adjOrig
);
242 node wT
= S
.twinTreeNode(e
);
243 edge eTwin
= S
.twinEdge(e
);
244 expandVirtualEmbed(wT
,
245 (vOrig
== skeleton(wT
).original(eTwin
->source())) ?
246 eTwin
->adjSource() : eTwin
->adjTarget(),
253 void PlanarSPQRTree::createInnerVerticesEmbed(Graph
&G
, node vT
)
255 const Skeleton
&S
= skeleton(vT
);
256 const Graph
& M
= S
.getGraph();
258 node src
= S
.referenceEdge()->source();
259 node tgt
= S
.referenceEdge()->target();
264 if (v
== src
|| v
== tgt
) continue;
266 node vOrig
= S
.original(v
);
267 SListPure
<adjEntry
> adjEdges
;
271 edge e
= adj
->theEdge();
272 edge eOrig
= S
.realEdge(e
);
275 adjEntry adjOrig
= (vOrig
== eOrig
->source()) ?
276 eOrig
->adjSource() : eOrig
->adjTarget();
277 OGDF_ASSERT(adjOrig
->theNode() == S
.original(v
));
278 adjEdges
.pushBack(adjOrig
);
280 node wT
= S
.twinTreeNode(e
);
281 edge eTwin
= S
.twinEdge(e
);
282 expandVirtualEmbed(wT
,
283 (vOrig
== skeleton(wT
).original(eTwin
->source())) ?
284 eTwin
->adjSource() : eTwin
->adjTarget(),
289 G
.sort(vOrig
,adjEdges
);
293 forall_adj_edges(e
,vT
) {
294 node wT
= e
->target();
296 createInnerVerticesEmbed(G
, wT
);
303 // basic update functions for manipulating embeddings
305 // reversing the skeleton of an R- or P-node
306 void PlanarSPQRTree::reverse(node vT
)
308 skeleton(vT
).getGraph().reverseAdjEdges();
312 // swapping two adjacency entries in the skeleton of a P-node
313 void PlanarSPQRTree::swap(node vT
, adjEntry adj1
, adjEntry adj2
)
315 OGDF_ASSERT(typeOf(vT
) == PNode
);
317 Graph
&M
= skeleton(vT
).getGraph();
319 M
.swapAdjEdges(adj1
,adj2
);
320 M
.swapAdjEdges(adj1
->twin(),adj2
->twin());
324 // swapping two edges in the skeleton of a P-node
325 void PlanarSPQRTree::swap(node vT
, edge e1
, edge e2
)
327 OGDF_ASSERT(typeOf(vT
) == PNode
);
329 if (e1
->source() == e2
->source())
330 swap(vT
,e1
->adjSource(),e2
->adjSource());
332 swap(vT
,e1
->adjSource(),e2
->adjTarget());
337 // number of possible embeddings of original graph
339 double PlanarSPQRTree::numberOfEmbeddings(node vT
) const
347 //node vFirst = skeleton(vT).getGraph().firstNode();
348 for (int i
= skeleton(vT
).getGraph().firstNode()->degree()-1; i
>= 2; --i
)
356 forall_adj_edges(e
,vT
) {
357 node wT
= e
->target();
359 num
*= numberOfEmbeddings(wT
);
368 // randomly embed skeleton graphs
370 void PlanarSPQRTree::randomEmbed()
373 forall_nodes(vT
,tree()) {
374 if (typeOf(vT
) == RNode
) {
375 int doReverse
= randomNumber(0,1);
380 } else if (typeOf(vT
) == PNode
) {
381 const Skeleton
&S
= skeleton(vT
);
382 adjEntry adjRef
= S
.referenceEdge()->adjSource();
384 SList
<adjEntry
> adjEdges
;
386 for (adj
= adjRef
->cyclicSucc(); adj
!= adjRef
; adj
= adj
->cyclicSucc())
387 adjEdges
.pushBack(adj
);
391 adj
= adjRef
->cyclicSucc();
392 SListConstIterator
<adjEntry
> it
;
393 for (it
= adjEdges
.begin(); it
.valid(); ++it
)
395 adjEntry adjNext
= *it
;
396 if (adjNext
!= adj
) {
397 swap(vT
,adj
,adjNext
);
400 adj
= adj
->cyclicSucc();
407 } // end namespace ogdf