6 * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $
7 ***************************************************************/
10 * \brief Implementation of PlanRep base class for planar rep.
12 * \author Hoi-Ming Wong
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 ***************************************************************/
43 #include <ogdf/basic/simple_graph_alg.h>
44 #include <ogdf/upward/UpwardPlanRep.h>
45 #include <ogdf/upward/FaceSinkGraph.h>
46 #include <ogdf/basic/FaceSet.h>
47 #include <ogdf/basic/tuples.h>
54 UpwardPlanRep::UpwardPlanRep(const CombinatorialEmbedding
&Gamma
) :
55 GraphCopy(Gamma
.getGraph()),
61 OGDF_ASSERT(Gamma
.externalFace() != 0);
62 OGDF_ASSERT(hasSingleSource(*this));
63 OGDF_ASSERT(isSimple(*this));
65 m_isSourceArc
.init(*this, false);
66 m_isSinkArc
.init(*this, false);
67 hasSingleSource(*this, s_hat
);
70 //compute the ext. face;
72 node v
= this->original(s_hat
);
73 adj
= getAdjEntry(Gamma
, v
, Gamma
.externalFace());
74 adj
= this->copy(adj
->theEdge())->adjSource();
75 m_Gamma
.setExternalFace(m_Gamma
.rightFace(adj
));
79 computeSinkSwitches();
83 UpwardPlanRep::UpwardPlanRep(const GraphCopy
&GC
, ogdf::adjEntry adj_ext
) :
90 OGDF_ASSERT(adj_ext
!= 0);
91 OGDF_ASSERT(hasSingleSource(*this));
93 m_isSourceArc
.init(*this, false);
94 m_isSinkArc
.init(*this, false);
95 hasSingleSource(*this, s_hat
);
98 //compute the ext. face;
99 node v
= copy(GC
.original(adj_ext
->theNode()));
100 extFaceHandle
= copy(GC
.original(adj_ext
->theEdge()))->adjSource();
101 if (extFaceHandle
->theNode() != v
)
102 extFaceHandle
= extFaceHandle
->twin();
103 m_Gamma
.setExternalFace(m_Gamma
.rightFace(extFaceHandle
));
106 forall_adj(adj
, s_hat
)
107 m_isSourceArc
[adj
->theEdge()] = true;
109 computeSinkSwitches();
114 UpwardPlanRep::UpwardPlanRep(const UpwardPlanRep
&UPR
) :
116 isAugmented(UPR
.isAugmented
),
117 crossings(UPR
.crossings
)
123 void UpwardPlanRep::copyMe(const UpwardPlanRep
&UPR
)
125 NodeArray
<node
> vCopy
;
126 EdgeArray
<edge
> eCopy
;
128 Graph::construct(UPR
,vCopy
,eCopy
);
131 m_pGraph
= UPR
.m_pGraph
;
133 m_vOrig
.init(*this,0); m_eOrig
.init(*this,0);
134 m_vCopy
.init(*m_pGraph
,0); m_eCopy
.init(*m_pGraph
);
135 m_eIterator
.init(*this,0);
139 m_vOrig
[vCopy
[v
]] = UPR
.m_vOrig
[v
];
143 m_eOrig
[eCopy
[e
]] = UPR
.m_eOrig
[e
];
145 forall_nodes(v
,*this)
146 if ((w
= m_vOrig
[v
]) != 0) m_vCopy
[w
] = v
;
148 forall_edges(e
,*m_pGraph
) {
149 ListConstIterator
<edge
> it
;
150 for (it
= UPR
.m_eCopy
[e
].begin(); it
.valid(); ++it
)
151 m_eIterator
[eCopy
[*it
]] = m_eCopy
[e
].pushBack(eCopy
[*it
]);
154 //GraphCopy::initGC(UPR,vCopy,eCopy);
156 m_isSinkArc
.init(*this, false);
157 m_isSourceArc
.init(*this, false);
159 if (UPR
.numberOfNodes() == 0)
162 s_hat
= vCopy
[UPR
.getSuperSource()];
164 t_hat
= vCopy
[UPR
.getSuperSink()];
166 OGDF_ASSERT(UPR
.extFaceHandle
!= 0);
168 e
= eCopy
[UPR
.extFaceHandle
->theEdge()];
169 v
= vCopy
[UPR
.extFaceHandle
->theNode()];
170 if (e
->adjSource()->theNode() == v
)
171 extFaceHandle
= e
->adjSource();
173 extFaceHandle
= e
->adjTarget();
175 m_Gamma
.setExternalFace(m_Gamma
.rightFace(extFaceHandle
));
177 forall_edges(e
, UPR
) {
179 if (UPR
.isSinkArc(e
))
180 m_isSinkArc
[a
] = true;
181 if (UPR
.isSourceArc(e
))
182 m_isSourceArc
[a
] = true;
185 computeSinkSwitches();
190 UpwardPlanRep
& UpwardPlanRep::operator =(const UpwardPlanRep
&cp
)
193 createEmpty(cp
.original());
194 isAugmented
= cp
.isAugmented
;
196 crossings
= cp
.crossings
;
202 void UpwardPlanRep::augment()
207 OGDF_ASSERT(hasSingleSource(*this));
209 List
< Tuple2
<adjEntry
, adjEntry
> > l
;
210 List
<adjEntry
> switches
;
212 hasSingleSource(*this, s_hat
);
215 forall_adj(adj
, s_hat
)
216 m_isSourceArc
[adj
->theEdge()] = true;
218 FaceSinkGraph
fsg(m_Gamma
, s_hat
);
219 List
<adjEntry
> dummyList
;
220 FaceArray
< List
<adjEntry
> > sinkSwitches(m_Gamma
, dummyList
);
221 fsg
.sinkSwitches(sinkSwitches
);
222 m_sinkSwitchOf
.init(*this, 0);
225 forall_faces(f
, m_Gamma
) {
227 switches
= sinkSwitches
[f
];
228 if (switches
.empty() || f
== m_Gamma
.externalFace())
231 adj_top
= switches
.popFrontRet(); // first switch in the list is a top sink switch
233 while (!switches
.empty()) {
234 adjEntry adj
= switches
.popFrontRet();
235 Tuple2
<adjEntry
, adjEntry
> pair(adj
, adj_top
);
239 // construct sink arcs
241 extFaceHandle
= getAdjEntry(m_Gamma
, s_hat
, m_Gamma
.externalFace());
242 node t
= this->newNode();
243 switches
= sinkSwitches
[m_Gamma
.externalFace()];
245 OGDF_ASSERT(!switches
.empty());
247 while (!switches
.empty()) {
248 adjEntry adj
= switches
.popFrontRet();
250 if (t
->degree() == 0) {
251 e_new
= m_Gamma
.splitFace(adj
, t
);
254 adjEntry adjTgt
= getAdjEntry(m_Gamma
, t
, m_Gamma
.rightFace(adj
));
255 e_new
= m_Gamma
.splitFace(adj
, adjTgt
);
257 m_isSinkArc
[e_new
] = true;
258 m_Gamma
.setExternalFace(m_Gamma
.rightFace(extFaceHandle
));
262 * set ext. face handle
263 * we add a additional node t_hat and an addtional edge e=(t, t_hat)
264 * e will never been crossed. we use e as the ext. face handle
266 t_hat
= this->newNode();
267 adjEntry adjSource
= getAdjEntry(m_Gamma
, t
, m_Gamma
.externalFace());
268 extFaceHandle
= m_Gamma
.splitFace(adjSource
, t_hat
)->adjTarget();
269 m_isSinkArc
[extFaceHandle
->theEdge()] = true; // not really a sink arc !! TODO??
271 m_Gamma
.setExternalFace(m_Gamma
.rightFace(extFaceHandle
));
275 Tuple2
<adjEntry
, adjEntry
> pair
= l
.popFrontRet();
279 if (pair
.x2()->theNode()->degree() == 0 ) {
280 e_new
= m_Gamma
.splitFace(pair
.x1(), pair
.x2()->theNode());
283 adjEntry adjTgt
= getAdjEntry(m_Gamma
, pair
.x2()->theNode(), m_Gamma
.rightFace(pair
.x1()));
284 e_new
= m_Gamma
.splitFace(pair
.x1(), adjTgt
);
286 m_isSinkArc
[e_new
] = true;
291 OGDF_ASSERT(isSimple(*this));
293 computeSinkSwitches();
297 void UpwardPlanRep::removeSinkArcs(SList
<adjEntry
> &crossedEdges
) {
299 if (crossedEdges
.size() == 2)
303 SListIterator
<adjEntry
> itPred
= crossedEdges
.begin(), itLast
= crossedEdges
.rbegin(), it
;
304 for(it
= itPred
.succ(); it
!= itLast
; ++it
) {
306 if (m_isSinkArc
[adj
->theEdge()]) {
307 m_Gamma
.joinFaces(adj
->theEdge());
308 crossedEdges
.delSucc(itPred
);
314 m_Gamma
.setExternalFace(m_Gamma
.rightFace(extFaceHandle
));
318 void UpwardPlanRep::insertEdgePathEmbedded(edge eOrig
, SList
<adjEntry
> crossedEdges
, EdgeArray
<int> &costOrig
)
320 removeSinkArcs(crossedEdges
);
322 //case the copy v of eOrig->source() is a sink switch
323 //we muss remove the sink arcs incident to v, since after inserting eOrig, v is not a sink witch
324 node v
= crossedEdges
.front()->theNode();
326 if (v
->outdeg() == 1)
327 this->outEdges(v
, outEdges
); // we delete this edges later
329 m_eCopy
[eOrig
].clear();
331 adjEntry adjSrc
, adjTgt
;
332 SListConstIterator
<adjEntry
> it
= crossedEdges
.begin();
333 SListConstIterator
<adjEntry
> itLast
= crossedEdges
.rbegin();
335 // iterate over all adjacency entries in crossedEdges except for first
338 List
<adjEntry
> dirtyList
; // left and right face of the element of this list are modified
339 for(++it
; it
!= itLast
; ++it
)
343 bool isASourceArc
= false, isASinkArc
= false;
344 if (m_isSinkArc
[adj
->theEdge()])
346 if (m_isSourceArc
[adj
->theEdge()])
350 if (original(adj
->theEdge()) != 0)
351 c
= costOrig
[original(adj
->theEdge())];
354 node u
= m_Gamma
.split(adj
->theEdge())->source();
355 if (!m_isSinkArc
[adj
->theEdge()] && !m_isSourceArc
[adj
->theEdge()])
356 crossings
= crossings
+ c
; // crossing sink/source arcs cost nothing
358 // determine target adjacency entry and source adjacency entry
359 // in the next iteration step
360 adjTgt
= u
->firstAdj();
361 adjEntry adjSrcNext
= adjTgt
->succ();
363 if (adjTgt
!= adj
->twin())
364 swap(adjTgt
,adjSrcNext
);
367 edge e_split
= adjTgt
->theEdge(); // the new split edge
368 if (e_split
->source() != u
)
369 e_split
= adjSrcNext
->theEdge();
372 m_isSinkArc
[e_split
] = true;
374 m_isSourceArc
[e_split
] = true;
376 // insert a new edge into the face
377 edge eNew
= m_Gamma
.splitFace(adjSrc
,adjTgt
);
378 m_eIterator
[eNew
] = GraphCopy::m_eCopy
[eOrig
].pushBack(eNew
);
379 m_eOrig
[eNew
] = eOrig
;
380 dirtyList
.pushBack(eNew
->adjSource());
386 edge eNew
= m_Gamma
.splitFace(adjSrc
,*it
);
387 m_eIterator
[eNew
] = m_eCopy
[eOrig
].pushBack(eNew
);
388 m_eOrig
[eNew
] = eOrig
;
389 dirtyList
.pushBack(eNew
->adjSource());
391 // remove the sink arc incident to v
392 if(!outEdges
.empty()) {
393 edge e
= outEdges
.popFrontRet();
395 m_Gamma
.joinFaces(e
);
398 m_Gamma
.setExternalFace(m_Gamma
.rightFace(extFaceHandle
));
400 //computeSinkSwitches();
401 FaceSinkGraph
fsg(m_Gamma
, s_hat
);
402 List
<adjEntry
> dummyList
;
403 FaceArray
< List
<adjEntry
> > sinkSwitches(m_Gamma
, dummyList
);
404 fsg
.sinkSwitches(sinkSwitches
);
406 //construct sinkArc for the dirty faces
407 List
< Tuple2
<adjEntry
, adjEntry
> > l
;
408 forall_listiterators(adjEntry
, it
, dirtyList
) {
409 face fLeft
= m_Gamma
.leftFace(*it
);
410 face fRight
= m_Gamma
.rightFace(*it
);
411 List
<adjEntry
> switches
= sinkSwitches
[fLeft
];
413 OGDF_ASSERT(!switches
.empty());
415 constructSinkArcs(fLeft
, switches
.front()->theNode());
417 OGDF_ASSERT(!switches
.empty());
419 switches
= sinkSwitches
[fRight
];
420 constructSinkArcs(fRight
, switches
.front()->theNode());
423 m_Gamma
.setExternalFace(m_Gamma
.rightFace(extFaceHandle
));
424 computeSinkSwitches();
429 void UpwardPlanRep::constructSinkArcs(face f
, node t
)
431 List
<adjEntry
> srcList
;
434 if (f
!= m_Gamma
.externalFace()) {
436 forall_face_adj(adj
, f
) {
437 node v
= adj
->theNode();
438 if (v
== adj
->theEdge()->target() && adj
->faceCyclePred()->theEdge()->target() == v
) {
440 srcList
.pushBack(adj
);
442 adjTgt
= adj
; // top-sink-switch of f
445 // contruct the sink arcs
446 while(!srcList
.empty()) {
447 adjEntry adjSrc
= srcList
.popFrontRet();
449 if (t
->degree() == 0)
450 eNew
= m_Gamma
.splitFace(adjSrc
, t
);
452 adjEntry adjTgt
= getAdjEntry(m_Gamma
, t
, m_Gamma
.rightFace(adjSrc
));
453 eNew
= m_Gamma
.splitFace(adjSrc
, adjTgt
);
455 m_isSinkArc
[eNew
] = true;
460 forall_face_adj(adj
, f
) {
461 node v
= adj
->theNode();
463 OGDF_ASSERT(s_hat
!= 0);
465 if (v
->outdeg() == 0 && v
!= t_hat
)
466 srcList
.pushBack(adj
);
469 // contruct the sink arcs
470 while(!srcList
.empty()) {
471 adjEntry adjSrc
= srcList
.popFrontRet();
473 if (adjSrc
->theNode() == adjSrc
->theEdge()->source()) // on the right face part of the ext. face
474 adjTgt
= extFaceHandle
;
476 adjTgt
= extFaceHandle
->cyclicPred(); // on the left face part
478 eNew
= m_Gamma
.splitFace(adjSrc
, adjTgt
);
479 m_isSinkArc
[eNew
] = true;
486 void UpwardPlanRep::computeSinkSwitches()
488 OGDF_ASSERT(m_Gamma
.externalFace() != 0);
491 hasSingleSource(*this, s_hat
);
492 FaceSinkGraph
fsg(m_Gamma
, s_hat
);
493 List
<adjEntry
> dummyList
;
494 FaceArray
< List
<adjEntry
> > sinkSwitches(m_Gamma
, dummyList
);
495 fsg
.sinkSwitches(sinkSwitches
);
496 m_sinkSwitchOf
.init(*this, 0);
499 forall_faces(f
, m_Gamma
) {
500 List
<adjEntry
> switches
= sinkSwitches
[f
];
501 ListIterator
<adjEntry
> it
= switches
.begin();
502 for (it
= it
.succ(); it
.valid(); it
++) {
503 m_sinkSwitchOf
[(*it
)->theNode()] = (*it
);
509 void UpwardPlanRep::initMe()
514 FaceSinkGraph
fsg(m_Gamma
, s_hat
);
515 SList
<face
> extFaces
;
516 fsg
.possibleExternalFaces(extFaces
);
518 OGDF_ASSERT(!extFaces
.empty());
521 forall_slistiterators(face
, it
, extFaces
) {
525 if (f_ext
->size() < (*it
)->size())
529 m_Gamma
.setExternalFace(f_ext
);
531 forall_adj(adj
, s_hat
) {
532 if (m_Gamma
.rightFace(adj
) == m_Gamma
.externalFace()) {
538 computeSinkSwitches();