6 * $Date: 2012-07-06 15:04:28 +0200 (Fr, 06. Jul 2012) $
7 ***************************************************************/
10 * \brief Implementation of OrderComparer and LayerBasedUPRLayout classes.
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/upward/LayerBasedUPRLayout.h>
44 #include <ogdf/basic/simple_graph_alg.h>
45 #include <ogdf/basic/Queue.h>
46 #include <ogdf/basic/Stack.h>
52 OrderComparer::OrderComparer(const UpwardPlanRep
&_UPR
, Hierarchy
&_H
) : UPR(_UPR
), H(_H
)
55 crossed
.init(UPR
, false);
59 hasSingleSource(UPR
, start
);
60 NodeArray
<bool> visited(UPR
, false);
61 adjEntry rightAdj
= UPR
.getAdjEntry(UPR
.getEmbedding(), start
, UPR
.getEmbedding().externalFace());
63 dfsNum
[start
] = num
++;
64 adjEntry run
= rightAdj
;
66 run
= run
->cyclicSucc();
67 if (!visited
[run
->theEdge()->target()])
68 dfs_LR(run
->theEdge(), visited
, dfsNum
, num
);
69 } while(run
!= rightAdj
);
75 bool OrderComparer::left(edge e1UPR
, edge e2UPR
) const
77 OGDF_ASSERT(e1UPR
->source() == e2UPR
->source() || e1UPR
->target() == e2UPR
->target());
78 OGDF_ASSERT(e1UPR
!= e2UPR
);
80 node v
= e1UPR
->source();
81 if (e2UPR
->source() != v
)
84 adjEntry inLeft
= 0, outLeft
= 0;
85 //compute left in and left out edge of the common node v if exist
86 if (v
->indeg() != 0) {
89 if (run
->cyclicSucc()->theEdge()->source() == v
)
94 if (v
->outdeg() != 0) {
97 if (run
->cyclicPred()->theEdge()->target() == v
)
99 if (UPR
.getEmbedding().leftFace(run
) == UPR
.getEmbedding().externalFace())
106 if (v
== e2UPR
->source()) {
108 if (outLeft
->theEdge() == e1UPR
)
110 if (outLeft
->theEdge() == e2UPR
)
112 outLeft
= outLeft
->cyclicSucc();
118 if (inLeft
->theEdge() == e1UPR
)
120 if (inLeft
->theEdge() == e2UPR
)
122 inLeft
= inLeft
->cyclicPred();
129 bool OrderComparer::left(node v1UPR
, List
<edge
> chain1
, node v2UPR
, List
<edge
> chain2
) const
131 //mark the edges an nodes of chain2 list
132 NodeArray
<bool> visitedNode(UPR
, false);
133 EdgeArray
<bool> visitedEdge(UPR
, false);
134 forall_listiterators(edge
, it
, chain2
) {
136 visitedNode
[e
->source()] = visitedNode
[e
->target()] = true;
137 visitedEdge
[e
] = true;
140 // traverse from vUPR2 to the super source using left path p and marks it.
141 visitedNode
[v2UPR
] = true;
142 adjEntry run
= UPR
.leftInEdge(v2UPR
);
144 visitedNode
[run
->theEdge()->source()] = visitedNode
[run
->theEdge()->target()] = true;
145 visitedEdge
[run
->theEdge()] = true;
146 run
= UPR
.leftInEdge(run
->theEdge()->source());
149 //is one of the node of chain1 marked?
150 ListIterator
<edge
> it
;
151 for(it
= chain1
.rbegin(); it
.valid(); --it
) {
152 node u
= (*it
)->source();
153 if (visitedNode
[u
]) {
156 if (visitedEdge
[run
->theEdge()] && run
->theEdge()->source() == run
->theNode()) // outgoing edges only
157 return left(*it
, run
->theEdge()); //(outEdgeOrder[*it] > outEdgeOrder[run->theEdge()]);
162 // traverse from vUPR1 to a node of path p (using left path).
163 adjEntry adj_v1
= 0, adj_v2
= 0;
164 run
= UPR
.leftInEdge(v1UPR
);
166 if (visitedNode
[run
->theEdge()->source()]) {
167 adj_v1
= run
->twin(); //reached a marked node
170 run
= UPR
.leftInEdge(run
->theEdge()->source());
173 OGDF_ASSERT(adj_v1
!= 0);
175 forall_adj(run
, adj_v1
->theNode()) {
176 if (visitedEdge
[run
->theEdge()] && run
->theEdge()->source() == run
->theNode()){ // outgoing edges only
182 OGDF_ASSERT(adj_v2
!= 0);
184 return left(adj_v1
->theEdge(), adj_v2
->theEdge());
189 bool OrderComparer::checkUp(node vUPR
, int level
) const
191 const GraphCopy
&GC
= H
;
193 //traverse from vUPR (going up)
194 NodeArray
<bool> inList(UPR
, false);
199 node v
= l
.popFrontRet();
200 node vOrig
= UPR
.original(v
);
201 if (vOrig
!= 0 && H
.rank(GC
.copy(vOrig
)) <= level
)
204 UPR
.outEdges(v
, outEdges
);
205 forall_listiterators(edge
, it
, outEdges
) {
206 node tgt
= (*it
)->target();
218 bool OrderComparer::left(List
<edge
> &chain1
, List
<edge
> &chain2
, int level
) const
220 //mark the source nodes of the edges of chain1
221 NodeArray
<bool> markedNodes(UPR
, false);
222 EdgeArray
<bool> markedEdges(UPR
, false);
223 forall_listiterators(edge
, iter
, chain1
) {
224 node v
= (*iter
)->source();
225 markedNodes
[v
] = true;
226 markedEdges
[*iter
] = true;
229 //compute the list of common nodes of chain1 and chain2
230 List
< Tuple2
<node
, bool> > commonNodeList
; // first: common node; second: true if vH1 (associated with chain1) is on the left hand side
231 forall_listiterators(edge
, iter
, chain2
) {
232 node v
= (*iter
)->source();
233 if (markedNodes
[v
]) {
236 adjEntry adj
= e
->adjSource();
238 adj
= adj
->cyclicSucc();
239 if (adj
->theEdge()->target() == v
) {
243 if (markedEdges
[adj
->theEdge()]) {
248 Tuple2
<node
, bool> tulp(v
, value
);
249 commonNodeList
.pushFront(tulp
);
253 //no crossings between the associated edges
254 if (commonNodeList
.empty()) {
255 if (chain1
.front()->source() == chain2
.front()->source()) {
256 return left(chain1
.front(), chain2
.front());
259 return left(chain1
.front()->source(), chain1
, chain2
.front()->source(), chain2
);
262 // there is a least one crossing
263 ListIterator
< Tuple2
<node
, bool> > it
= commonNodeList
.begin();
265 Tuple2
<node
, bool> tulp
= *it
;
266 // is there a node above which level is lower or equal the given level?
267 // if so, then return the value
268 if (checkUp(tulp
.x1(), level
)) {
269 // there is a node above, which is lower or equal the given level
275 // the both edges are on the "first segment" of the crossing
276 Tuple2
<node
, bool> tulp
= *(commonNodeList
.rbegin());
282 bool OrderComparer::less(node vH1
, node vH2
) const
288 case:vH1 and vH2 are not long-edge dummies.
290 const GraphCopy
&GC
= H
;
291 if (!H
.isLongEdgeDummy(vH1
) && !H
.isLongEdgeDummy(vH2
)) {
292 node v1
= UPR
.copy(GC
.original(vH1
));
293 node v2
= UPR
.copy(GC
.original(vH2
));
294 if (dfsNum
[v1
] > dfsNum
[v2
])
301 vH1 and vH2 are long-edge-dummies
303 if (H
.isLongEdgeDummy(vH1
) && H
.isLongEdgeDummy(vH2
)) {
304 List
<edge
> chain1
= UPR
.chain(GC
.original(vH1
->firstAdj()->theEdge()));
305 List
<edge
> chain2
= UPR
.chain(GC
.original(vH2
->firstAdj()->theEdge()));
307 OGDF_ASSERT(!chain1
.empty() && !chain2
.empty());
309 int level
= H
.rank(vH1
);
310 return (left(chain1
, chain2
, level
));
311 }//end both are long edge dummies
314 only vH1 or vH2 is a long-edge dummy
317 List
<edge
> chain1
, chain2
;
318 if (H
.isLongEdgeDummy(vH1
)) {
319 chain1
= UPR
.chain(GC
.original(vH1
->firstAdj()->theEdge()));
320 v
= UPR
.copy(GC
.original(vH2
));
322 OGDF_ASSERT(!chain1
.empty());
324 return left(chain1
.front()->source(), chain1
, v
, chain2
);
327 chain2
= UPR
.chain(GC
.original(vH2
->firstAdj()->theEdge()));
328 v
= UPR
.copy(GC
.original(vH1
));
330 OGDF_ASSERT(!chain2
.empty());
332 return left(v
, chain1
, chain2
.front()->source(), chain2
);
338 void OrderComparer::dfs_LR(
340 NodeArray
<bool> &visited
,
341 NodeArray
<int> &dfsNum
,
344 node v
= e
->target();
345 //outEdgeOrder[e] = num++;
347 if (e
->target()->outdeg() > 0) {
348 // compute left out edge
351 adjEntry adj_pred
= run
->cyclicPred();
352 if (adj_pred
->theEdge()->target() == v
&& run
->theEdge()->source() == v
)
353 break; // run is the left out-edge
357 if (!visited
[run
->theEdge()->target()]) {
358 dfs_LR(run
->theEdge(), visited
, dfsNum
, num
);
360 run
= run
->cyclicSucc();
361 } while(run
->theEdge()->target() != e
->target());
368 void LayerBasedUPRLayout::doCall(const UpwardPlanRep
&UPR
, GraphAttributes
&AG
)
370 OGDF_ASSERT(UPR
.augmented());
376 const Graph
&G
= UPR
.original();
377 NodeArray
<int> rank_G(G
);
378 computeRanking(UPR
, rank_G
);
379 Hierarchy
H(G
, rank_G
);
380 const GraphCopy
&GC
= H
;
384 //UPR.outputFaces(UPR.getEmbedding());
387 cout << "vOrig " << x << "; vUPR " << UPR.copy(x) << endl;
389 forall_nodes(x, UPR) {
390 cout << "UPR edge order:" << endl;
391 adjEntry adj = x->firstAdj();
392 cout << "node " << x << endl;
394 cout << " edge : " << adj->theEdge() << endl;
395 adj = adj->cyclicSucc();
396 } while (adj != x->firstAdj());
401 OrderComparer
oComparer(UPR
, H
);
402 for(int i
= 0; i
< H
.size(); ++i
) {
404 l
.sortOrder(oComparer
);
408 // ********************** postprocessing *******************************************
411 forall_nodes(vTmp
, GC
) {
412 if (vTmp
->indeg() == 0)
413 sources
.pushBack(vTmp
);
418 sources
.quicksort(comp
);
423 postProcessing_reduceLED(H
, sources
);
428 cout << endl << endl;
429 for(int i = 0; i <= H.high(); i++) {
431 cout << "level : " << lvl.index() << endl;
433 for(int j = 0; j <= lvl.high(); j++) {
434 cout << lvl[j] << " ";
440 postProcessing_sourceReorder(H
, sources
);
441 m_crossings
= H
.calculateCrossings();
443 OGDF_ASSERT(m_crossings
<= UPR
.numberOfCrossings());
444 OGDF_ASSERT(m_layout
.valid());
446 GraphCopyAttributes
AGC(H
, AG
);
447 m_layout
.get().call(H
,AG
);
448 // ********************** end postprocessing *******************************************
450 numberOfLevels
= H
.size();
452 for(int i
= 0; i
<= H
.high(); i
++) {
454 if (m_maxLevelSize
< l
.size())
455 m_maxLevelSize
= l
.size();
460 void LayerBasedUPRLayout::computeRanking(const UpwardPlanRep
&UPR
, NodeArray
<int> &rank
)
462 OGDF_ASSERT(UPR
.augmented());
464 GraphCopy GC
= UPR
.original();
466 forall_edges(e
, UPR
.original()) {
467 if (UPR
.isReversed(e
)) {
468 GC
.reverseEdge(GC
.copy(e
));
472 // compute auxiliary edges
473 EdgeArray
<int> cost(GC
,1);
474 List
< Tuple2
<node
, node
> > auxEdges
;
475 NodeArray
<int> inL(UPR
, -1);
478 forall_nodes(v
, UPR
) {
480 if (UPR
.isDummy(v
) || v
->indeg()==0)
484 //compute all "adjacent" non dummy nodes
485 List
<node
> toDo
, srcNodes
;
488 while (!toDo
.empty()) {
489 node u
= toDo
.popFrontRet();
491 UPR
.inEdges(u
, inEdges
);
492 forall_listiterators(edge
, it
, inEdges
) {
493 node w
= (*it
)->source();
494 if (UPR
.isDummy(w
)) {
502 OGDF_ASSERT(UPR
.original(w
) != 0 && UPR
.original(v
) != 0);
504 node wGC
= GC
.copy(UPR
.original(w
));
505 node vGC
= GC
.copy(UPR
.original(v
));
506 edge eNew
= GC
.newEdge(wGC
, vGC
);
515 OGDF_ASSERT(isAcyclic(GC
));
518 // ****************************debug*******************************
520 GraphAttributes GA(GC, GraphAttributes::nodeGraphics|
521 GraphAttributes::edgeGraphics|
522 GraphAttributes::nodeColor|
523 GraphAttributes::edgeColor|
524 GraphAttributes::nodeLabel|
525 GraphAttributes::edgeLabel);
527 // label the nodes with their index
528 forall_nodes(vTmp, GC) {
530 node w = GC.original(vTmp);
531 sprintf_s(str, 255, "%d", w->index()); // convert to string
532 GA.labelNode(vTmp) = str;
534 GA.writeGML("c:/temp/ranking_graph.gml");
536 //********************************************************************
539 NodeArray
<int> ranking(GC
, 0);
540 EdgeArray
<int> length(GC
,1);
542 m_ranking
.get().call(GC
, length
, cost
, ranking
);
545 int minRank
= INT_MAX
;
547 if(ranking
[v
] < minRank
)
548 minRank
= ranking
[v
];
553 ranking
[v
] -= minRank
;
557 node vOrig
= GC
.original(v
);
558 rank
[vOrig
] = ranking
[v
];
562 //debug output ranking
563 cout << "Ranking GOrig: " << endl;
564 forall_nodes(v, UPR.original())
565 cout << "node :" << v << " ranking : "<< rank[v] << endl;
571 void LayerBasedUPRLayout::postProcessing_sourceReorder(Hierarchy
&H
, List
<node
> &sources
)
573 //reorder the sources;
574 forall_listiterators(node
, it
, sources
) {
576 Level
&l
= H
[H
.rank(s
)];
578 //compute the desire position (heuristic)
581 if (s
->outdeg() == 1) {
582 node tgt
= s
->firstAdj()->theEdge()->target();
585 forall_adj(adj
, tgt
) {
586 if (adj
->theEdge()->target() == tgt
)
587 nodes
.pushBack(adj
->theEdge()->source());
592 nodes
.quicksort(comp
);
594 //postion of the median
595 node v
= *nodes
.get(nodes
.size()/2);
596 wantedPos
= H
.pos(v
);
602 nodes
.pushBack(adj
->theEdge()->source());
606 nodes
.quicksort(comp
);
608 //postion of the median
609 node v
= *nodes
.get(nodes
.size()/2);
610 wantedPos
= H
.pos(v
);
613 //move s to front of the array
620 // compute the position of s, which cause min. crossing
622 int oldCr
= H
.calculateCrossings(l
.index());;
623 while(pos
!= l
.size()-1) {
625 int newCr
= H
.calculateCrossings(l
.index());
626 if (newCr
<= oldCr
) {
632 if (abs(minPos
- wantedPos
) > abs(pos
+1 - wantedPos
)) {
643 while (pos
!= minPos
) {
658 void LayerBasedUPRLayout::postProcessing_markUp(Hierarchy
&H
, node s
, NodeArray
<bool> &markedNodes
)
660 const GraphCopy
&GC
= H
;
661 NodeArray
<bool> inQueue(GC
, false);
662 Queue
<node
> nodesToDo
;
665 while(!nodesToDo
.empty()) {
666 node w
= nodesToDo
.pop();
667 markedNodes
[w
] = true;
669 GC
.outEdges(w
, outEdges
);
670 ListIterator
<edge
> it
;
671 for (it
= outEdges
.begin(); it
.valid(); ++it
) {
673 if (!inQueue
[e
->target()] && !markedNodes
[e
->target()]) { // put the next node in queue if it is not already in queue
674 nodesToDo
.append( e
->target() );
675 inQueue
[e
->target()] = true;
683 void LayerBasedUPRLayout::postProcessing_reduceLED(Hierarchy
&H
, node s
)
685 const GraphCopy
&GC
= H
;
686 NodeArray
<bool> markedNodes(GC
, false);
688 // mark all nodes dominated by s, we call the graph induced by the marked node G*
689 // note that not necessary all nodes are marked.
690 postProcessing_markUp(H
, s
, markedNodes
);
693 for (int i
= H
.rank(s
) + 1; i
<= H
.high(); i
++) {
694 const Level
&lvl
= H
[i
];
696 // Compute the start and end index of the marked graph on this level.
697 int minIdx
= INT_MAX
;
703 int numMarkedNodes
= 0;
705 for(int j
= 0; j
<= lvl
.high(); j
++) {
708 if (markedNodes
[u
]) {
711 if (H
.isLongEdgeDummy(u
))
714 if (H
.pos(u
)< minIdx
)
716 if (H
.pos(u
) > maxIdx
)
719 sumInDeg
+= u
->indeg();
722 if (adj
->theEdge()->target()==u
&& markedNodes
[adj
->theEdge()->source()])
727 if (numEdges
!=sumInDeg
|| maxIdx
-minIdx
+1!=numMarkedNodes
)
730 if (numDummies
!=numMarkedNodes
)
733 //delete long edge dummies
734 for (int k
= minIdx
; k
<= maxIdx
; k
++) {
737 OGDF_ASSERT(H
.isLongEdgeDummy(u
));
739 edge inEdge
= u
->firstAdj()->theEdge();
740 edge outEdge
= u
->lastAdj()->theEdge();
741 if (inEdge
->target() != u
)
742 swap(inEdge
, outEdge
);
743 H
.m_GC
.unsplit(inEdge
, outEdge
);
748 cout << endl << endl;
749 cout << "vor : " << endl;
750 for(int ii = 0; ii <= H.high(); ii++) {
753 cout << "level : " << lvl.index() << endl;
755 for(int jj = 0; jj <= lvl.high(); jj++) {
756 cout << lvl[jj] << "/" << H.pos(lvl[jj]) << " ";
762 post_processing_reduce(H
, i
, s
, minIdx
, maxIdx
, markedNodes
);
766 cout << endl << endl;
767 cout << endl << endl;
768 cout << "nach : " << endl;
769 for(int ii = 0; ii <= H.high(); ii++) {
772 cout << "level : " << lvl.index() << endl;
774 for(int jj = 0; jj <= lvl.high(); jj++) {
775 cout << lvl[jj] << "/" << H.pos(lvl[jj]) << " ";
785 void LayerBasedUPRLayout::post_processing_reduce(
791 NodeArray
<bool> &markedNodes
)
793 const Level
&lvl
= H
[i
];
795 if (maxIdx
-minIdx
+1 == lvl
.size()) {
796 post_processing_deleteLvl(H
, i
);
801 // delete the dummies in interval[minIdx,maxIdx] and copy the nodes in lvl i-1 to lvl i for i={0,..,i-1}
802 int startLvl
= H
.rank(s
);
803 for (int j
= i
; j
> startLvl
; j
--) {
809 for (int k
= 0; k
<=H
[j
].high(); k
++) {
812 if (markedNodes
[u
]) {
820 for (int k
= 0; k
<=H
[j
-1].high(); k
++) {
823 if (markedNodes
[u
]) {
832 post_processing_deleteInterval(H
, idxl1
, idxh1
, j
);
835 return; //a level was deleted, we are done
840 cout << endl << endl;
841 cout << "nach delete : " << endl;
842 for(int ii = 0; ii <= H.high(); ii++) {
845 cout << "level : " << lvl.index() << endl;
847 for(int jj = 0; jj <= lvl.high(); jj++) {
848 cout << lvl[jj] << "/" << H.pos(lvl[jj]) << " ";
854 post_processing_CopyInterval(H
, j
, idxl2
, idxh2
, idxl1
);
858 cout << endl << endl;
859 cout << "nach copy : " << endl;
860 for(int ii = 0; ii <= H.high(); ii++) {
863 cout << "level : " << lvl.index() << endl;
865 for(int jj = 0; jj <= lvl.high(); jj++) {
866 cout << lvl[jj] << "/" << H.pos(lvl[jj]) << " ";
876 for (int k
= 0; k
<=H
[startLvl
].high(); k
++) {
877 node u
= H
[startLvl
][k
];
879 if (markedNodes
[u
]) {
887 post_processing_deleteInterval(H
, idxl1
, idxh1
, startLvl
);
893 void LayerBasedUPRLayout::post_processing_CopyInterval(Hierarchy
&H
, int i
, int beginIdx
, int endIdx
, int pos
)
895 Level
&lvl_cur
= H
[i
];
896 int intervalSize
= endIdx
- beginIdx
+1;
897 int lastIdx
= lvl_cur
.high();
899 OGDF_ASSERT(intervalSize
> 0);
902 lvl_cur
.m_nodes
.grow(intervalSize
);
903 //move all the data block [pos,lvl_cur.high()] to the end of the array
904 for (int k
= 0; k
< (lastIdx
- pos
+ 1) ; k
++) {
906 H
.m_pos
[lvl_cur
[lastIdx
- k
]] = lvl_cur
.high() - k
;
907 lvl_cur
[lvl_cur
.high() - k
] = lvl_cur
[lastIdx
- k
];
912 cout << endl << endl;
913 cout << "level after shift block to end of array : " << lvl.index() << endl;
915 for(int j = 0; j <= lvl.high(); j++) {
916 cout << lvl[j] << " ; pos() " << pos(lvl[j]) << " ";
921 //copy the nodes of nodeList into the array
922 Level
&lvl_low
= H
[i
-1];
924 for (int k
= beginIdx
; k
<= endIdx
; k
++) {
927 // update member data
929 H
.m_rank
[u
] = lvl_cur
.index();
936 void LayerBasedUPRLayout::post_processing_deleteInterval(Hierarchy
&H
, int beginIdx
, int endIdx
, int &j
)
941 while ((endIdx
+ i
) < lvl
.high()) {
942 lvl
[beginIdx
+ i
] = lvl
[endIdx
+ i
+1];
943 H
.m_pos
[lvl
[endIdx
+ i
+1]] = beginIdx
+ i
;
947 int blockSize
= endIdx
- beginIdx
+ 1;
949 if (lvl
.m_nodes
.size()==blockSize
) {
951 post_processing_deleteLvl(H
, l
); //delete the lvl
955 lvl
.m_nodes
.grow(-blockSize
); // reduce the size of the lvl
960 void LayerBasedUPRLayout::post_processing_deleteLvl(Hierarchy
&H
, int i
)
962 //move the pointer to end, then delete the lvl
964 while (curPos
< H
.high()) {
965 swap(H
.m_pLevel
[curPos
], H
.m_pLevel
[curPos
+1]);
966 Level
&lvlTmp
= H
[curPos
];
967 lvlTmp
.m_index
= curPos
;
969 for(int i
= 0; i
<= lvlTmp
.high(); i
++) {
970 H
.m_rank
[lvlTmp
[i
]] = curPos
;
975 delete H
.m_pLevel
[H
.high()];
982 void LayerBasedUPRLayout::UPRLayoutSimple(const UpwardPlanRep
&UPR
, GraphAttributes
&GA
)
986 forall_edges(e
, GA
.constGraph()) {
990 // -------------layout the representation-------------------
991 GraphAttributes
GA_UPR(UPR
);
993 forall_nodes(v
, GA
.constGraph()) {
994 node vUPR
= UPR
.copy(v
);
995 GA_UPR
.height(vUPR
) = GA
.height(v
);
996 GA_UPR
.width(vUPR
) = GA
.width(v
);
1000 //compute the left edge
1002 forall_adj(adj
, UPR
.getSuperSource()) {
1003 if (UPR
.getEmbedding().rightFace(adj
) == UPR
.getEmbedding().externalFace())
1006 adj
= adj
->cyclicSucc();
1007 callSimple(GA_UPR
, adj
);
1010 forall_nodes(v
, GA
.constGraph()) {
1011 double vX
= GA_UPR
.x(UPR
.copy(v
));
1012 double vY
= GA_UPR
.y(UPR
.copy(v
));
1017 // add bends to original edges
1018 forall_edges(e
, GA
.constGraph()) {
1019 List
<edge
> chain
= UPR
.chain(e
);
1020 forall_nonconst_listiterators(edge
, it
, chain
) {
1022 node tgtUPR
= eUPR
->target();
1024 //add bend point of eUPR to original edge
1025 ListIterator
<DPoint
> iter
;
1026 DPolyline
&line
= GA_UPR
.bends(eUPR
);
1027 for(iter
= line
.begin(); iter
.valid(); iter
++) {
1028 double x2
= (*iter
).m_x
;
1029 double y2
= (*iter
).m_y
;
1031 GA
.bends(e
).pushBack(p
);
1033 //add target node of a edge segment as bend point
1034 if (tgtUPR
!= chain
.back()->target()) {
1035 double pX
= GA_UPR
.x(tgtUPR
);
1036 double pY
= GA_UPR
.y(tgtUPR
);
1038 GA
.bends(e
).pushBack(p
);
1042 DPolyline
&poly
= GA
.bends(e
);
1043 DPoint
pSrc(GA
.x(e
->source()), GA
.y(e
->source()));
1044 DPoint
pTgt(GA
.x(e
->target()), GA
.y(e
->target()));
1045 poly
.normalize(pSrc
, pTgt
);
1048 //layers and max. layer size
1052 void LayerBasedUPRLayout::callSimple(GraphAttributes
&GA
, adjEntry adj
)
1054 m_numLevels
= -1; //not implemented yet!
1055 m_maxLevelSize
= -1; //not implemented yet!
1057 const Graph
&G
= GA
.constGraph();
1059 OGDF_ASSERT(adj
->graphOf() == &G
);
1061 // We make a copy stGraph of the input graph G
1063 GraphCopySimple
stGraph(G
);
1065 // determine single source s, single sink t and edge (s,t)
1067 hasSingleSource(G
, s
);
1068 hasSingleSink(G
, t
);
1069 s
= stGraph
.copy(s
);
1070 t
= stGraph
.copy(t
);
1072 adjEntry adjCopy
= stGraph
.copy(adj
->theEdge())->adjSource();
1074 /*cout << "stGraph:" << endl;
1076 forall_nodes(x,stGraph) {
1079 forall_adj_edges(e,x)
1084 // For the st-graph, we compute a longest path ranking. Since the graph
1085 // is st-planar, it is also level planar for the computed rank assignment.
1086 NodeArray
<int> stRank(stGraph
);
1087 longestPathRanking(stGraph
,stRank
);
1090 forall_edges(e
,stGraph
)
1091 OGDF_ASSERT(stRank
[e
->source()] < stRank
[e
->target()]);
1094 // We translate the rank assignment for stGraph to a rank assignment of G
1095 // a compute a proper hierarchy for G with this ranking. Since G is a
1096 // subgraph of stGraph, G is level planar with this ranking.
1097 NodeArray
<int> rank(G
);
1101 rank
[vG
] = stRank
[stGraph
.copy(vG
)];
1104 /*cout << "rank assignment G:" << endl;
1105 forall_nodes(vG,G) {
1106 cout << vG << ": " << rank[vG] << endl;
1109 Hierarchy
H(G
,rank
);
1111 // GC is the underlying graph of the proper hierarchy H.
1112 const GraphCopy
&GC
= H
;
1115 // We compute the positions of the nodes of GC on each level. It is
1116 // important to determine also the positions of the dummy nodes which
1117 // resulted from splitting edges. The node array st2GC maps the nodes in
1118 // stGraph to the nodes in GC.
1119 NodeArray
<node
> st2GC(stGraph
,0);
1121 // For nodes representing real nodes in G this is simple.
1122 forall_nodes(vG
,G
) {
1123 OGDF_ASSERT(H
.rank(GC
.copy(vG
)) == stRank
[stGraph
.copy(vG
)]);
1124 st2GC
[stGraph
.copy(vG
)] = GC
.copy(vG
);
1127 // For the dummy nodes, we first have to split edges in stGraph.
1128 // For an edge e=(v,w), we have to split e stRank[w]-stRank[v]-1 times.
1130 forall_edges(eG
,G
) {
1131 edge eSt
= stGraph
.copy(eG
);
1132 const List
<edge
> &pathGC
= GC
.chain(eG
);
1134 ListConstIterator
<edge
> it
;
1135 int r
= stRank
[eSt
->source()];
1136 for(it
= pathGC
.begin().succ(); it
.valid(); ++it
) {
1137 eSt
= stGraph
.split(eSt
);
1138 node v
= eSt
->source();
1139 node vGC
= (*it
)->source();
1143 OGDF_ASSERT(stRank
[v
] == H
.rank(vGC
));
1148 forall_nodes(v
,stGraph
) {
1149 node vGC
= st2GC
[v
];
1150 OGDF_ASSERT(vGC
== 0 || stRank
[v
] == H
.rank(vGC
));
1153 /*cout << "mapping stGraph -> GC -> G:" << endl;
1155 forall_nodes(v,stGraph)
1156 cout << v << ": " << st2GC[v] << " " << stGraph.original(v) << endl;*/
1159 // The array nodes contains the sorted nodes of stGraph on each level.
1160 Array
<SListPure
<node
> > nodes(stRank
[s
],stRank
[t
]);
1162 dfsSortLevels(adjCopy
,stRank
,nodes
);
1164 /*for(int i = stRank[s]; i <= stRank[t]; ++i) {
1166 SListPure<node> &L = nodes[i];
1167 SListConstIterator<node> it;
1168 for(it = L.begin(); it.valid(); ++it) {
1169 cout << stGraph.original(*it) << " ";
1170 node vGC = st2GC[*it];
1171 OGDF_ASSERT(vGC == 0 || H.rank(vGC) == i);
1176 // We translate the node lists to node lists of nodes in GC using node
1177 // array st2GC. Note that there are also nodes in stGraph which have
1178 // no counterpart in GC (these are face nodes of the face-sink graph
1179 // introduced by the augmentation). We can simply ignore such nodes.
1181 for (i
= 0; i
<= H
.high(); ++i
) {
1182 Level
&level
= H
[i
];
1184 //cout << i << endl;
1185 //cout << level << endl;
1188 SListConstIterator
<node
> itSt
;
1189 for(itSt
= nodes
[i
].begin(); itSt
.valid(); ++itSt
) {
1190 node vGC
= st2GC
[*itSt
];
1195 //cout << level << endl;
1198 level
.recalcPos(); // Recalculate some internal data structures in H
1204 //cout << "crossings: " << H.calculateCrossings() << endl;
1205 OGDF_ASSERT(H
.calculateCrossings() == 0);
1207 // Finally, we draw the computed hierarchy applying a hierarchy layout
1209 m_layout
.get().call(H
,GA
);
1213 // This procedure computes the sorted nodes lists on each level of an st-graph.
1214 // adj1 corresponds to the leftmost outgoing edge of v = adj1->theNode().
1215 // Levels are build from left to right.
1216 void LayerBasedUPRLayout::dfsSortLevels(
1217 adjEntry adj1
, // leftmost outgoing edge
1218 const NodeArray
<int> &rank
, // ranking
1219 Array
<SListPure
<node
> > &nodes
) // sorted nodes on levels
1221 node v
= adj1
->theNode();
1223 nodes
[rank
[v
]].pushBack(v
);
1225 // iterate over all outgoing edges from left to right
1226 adjEntry adj
= adj1
;
1228 node w
= adj
->theEdge()->target();
1229 OGDF_ASSERT(v
!= w
);
1231 // Is adjW the leftmost outgoing edge of w ?
1232 adjEntry adjW
= adj
->twin()->cyclicSucc();
1233 if(adjW
->theEdge()->source() == w
)
1234 dfsSortLevels(adjW
,rank
,nodes
);
1236 adj
= adj
->cyclicSucc();
1237 } while (adj
!= adj1
&& adj
->theEdge()->source() == v
);
1241 // for UPRLayoutSimple
1242 void LayerBasedUPRLayout::longestPathRanking(
1244 NodeArray
<int> &rank
)
1246 StackPure
<node
> sources
;
1247 NodeArray
<int> indeg(G
);
1251 indeg
[v
] = v
->indeg();
1258 while(!sources
.empty())
1263 forall_adj_edges(e
,v
) {
1264 node w
= e
->target();
1265 if (w
== v
) continue;
1267 if(rank
[w
] < rank
[v
]+1)
1268 rank
[w
] = rank
[v
]+1;
1270 if(--indeg
[w
] == 0) {
1279 }// end namespace ogdf