Don't import ogdf namespace
[TortoiseGit.git] / ext / OGDF / src / tree / TreeLayout.cpp
blob660e6020b6dd5b32a785acef1feb78d8e3180151
1 /*
2 * $Revision: 2565 $
4 * last checkin:
5 * $Author: gutwenger $
6 * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $
7 ***************************************************************/
9 /** \file
10 * \brief Linear time layout algorithm for trees (TreeLayout)
11 * based on Walker's algorithm
13 * \author Christoph Buchheim
15 * \par License:
16 * This file is part of the Open Graph Drawing Framework (OGDF).
18 * \par
19 * Copyright (C)<br>
20 * See README.txt in the root directory of the OGDF installation for details.
22 * \par
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
27 * for details.
29 * \par
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.
35 * \par
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 <ogdf/tree/TreeLayout.h>
46 #include <ogdf/basic/List.h>
47 #include <ogdf/basic/Math.h>
50 #include <ogdf/basic/AdjEntryArray.h>
51 #include <math.h>
54 #include <ogdf/basic/simple_graph_alg.h>
55 #include <ogdf/basic/Stack.h>
58 namespace ogdf {
61 TreeLayout::TreeLayout()
62 :m_siblingDistance(20),
63 m_subtreeDistance(20),
64 m_levelDistance(50),
65 m_treeDistance(50),
66 m_orthogonalLayout(false),
67 m_orientation(topToBottom),
68 m_selectRoot(rootIsSource),
69 m_pGraph(0)
70 { }
73 TreeLayout::TreeLayout(const TreeLayout &tl)
74 :m_siblingDistance(tl.m_siblingDistance),
75 m_subtreeDistance(tl.m_subtreeDistance),
76 m_levelDistance(tl.m_levelDistance),
77 m_treeDistance(tl.m_treeDistance),
78 m_orthogonalLayout(tl.m_orthogonalLayout),
79 m_orientation(tl.m_orientation),
80 m_selectRoot(tl.m_selectRoot)
81 { }
84 TreeLayout::~TreeLayout()
85 { }
88 TreeLayout &TreeLayout::operator=(const TreeLayout &tl)
90 m_siblingDistance = tl.m_siblingDistance;
91 m_subtreeDistance = tl.m_subtreeDistance;
92 m_levelDistance = tl.m_levelDistance;
93 m_treeDistance = tl.m_treeDistance;
94 m_orthogonalLayout = tl.m_orthogonalLayout;
95 m_orientation = tl.m_orientation;
96 m_selectRoot = tl.m_selectRoot;
97 return *this;
101 // comparer class used for sorting adjacency entries according to their angle
102 class TreeLayout::AdjComparer
104 public:
105 AdjComparer(const AdjEntryArray<double> &angle) {
106 m_pAngle = &angle;
109 int compare(const adjEntry &adjX, const adjEntry &adjY) const {
110 if ((*m_pAngle)[adjX] < (*m_pAngle)[adjY])
111 return -1;
112 else
113 if ((*m_pAngle)[adjX] > (*m_pAngle)[adjY])
114 return 1;
115 else
116 return 0;
118 OGDF_AUGMENT_COMPARER(adjEntry)
120 private:
121 const AdjEntryArray<double> *m_pAngle;
126 void TreeLayout::setRoot(GraphAttributes &AG, Graph &tree)
128 m_pGraph = &tree;
130 NodeArray<bool> visited(tree,false);
131 StackPure<node> S;
133 node v;
134 forall_nodes(v,tree)
136 if(visited[v]) continue;
138 // process a new connected component
139 node root = 0;
140 S.push(v);
142 while(!S.empty())
144 node x = S.pop();
145 visited[x] = true;
147 if(!root) {
148 if(m_selectRoot == rootIsSource) {
149 if (x->indeg() == 0)
150 root = x;
151 } else if (m_selectRoot == rootIsSink) {
152 if (x->outdeg() == 0)
153 root = x;
154 } else { // selectByCoordinate
155 root = x;
158 } else if(m_selectRoot == rootByCoord) {
159 switch(m_orientation)
161 case bottomToTop:
162 if(AG.y(x) < AG.y(root))
163 root = x;
164 break;
165 case topToBottom:
166 if(AG.y(x) > AG.y(root))
167 root = x;
168 break;
169 case leftToRight:
170 if(AG.x(x) < AG.x(root))
171 root = x;
172 break;
173 case rightToLeft:
174 if(AG.x(x) > AG.x(root))
175 root = x;
176 break;
180 adjEntry adj;
181 forall_adj(adj,x) {
182 node w = adj->twinNode();
183 if(!visited[w])
184 S.push(w);
188 if(root == 0) {
189 undoReverseEdges(AG);
190 OGDF_THROW_PARAM(PreconditionViolatedException, pvcForest);
193 adjustEdgeDirections(tree,root,0);
198 void TreeLayout::adjustEdgeDirections(Graph &G, node v, node parent)
200 adjEntry adj;
201 forall_adj(adj,v) {
202 node w = adj->twinNode();
203 if(w == parent) continue;
204 edge e = adj->theEdge();
205 if(w != e->target()) {
206 G.reverseEdge(e);
207 m_reversedEdges.pushBack(e);
209 adjustEdgeDirections(G,w,v);
213 void TreeLayout::callSortByPositions(GraphAttributes &AG, Graph &tree)
215 OGDF_ASSERT(&tree == &(AG.constGraph()));
217 if (!isFreeForest(tree))
218 OGDF_THROW_PARAM(PreconditionViolatedException, pvcForest);
220 setRoot(AG,tree);
222 // stores angle of adjacency entry
223 AdjEntryArray<double> angle(tree);
225 AdjComparer cmp(angle);
227 node v;
228 forall_nodes(v,tree)
230 // position of node v
231 double cx = AG.x(v);
232 double cy = AG.y(v);
234 adjEntry adj;
235 forall_adj(adj,v)
237 // adjacent node
238 node w = adj->twinNode();
240 // relative position of w to v
241 double dx = AG.x(w) - cx;
242 double dy = AG.y(w) - cy;
244 // if v and w lie on the same point ...
245 if (dx == 0 && dy == 0) {
246 angle[adj] = 0;
247 continue;
250 if(m_orientation == leftToRight || m_orientation == rightToLeft)
251 swap(dx,dy);
252 if(m_orientation == topToBottom || m_orientation == rightToLeft)
253 dy = -dy;
255 // compute angle of adj
256 double alpha = atan2(fabs(dx),fabs(dy));
258 if(dx < 0) {
259 if(dy < 0)
260 angle[adj] = alpha;
261 else
262 angle[adj] = Math::pi - alpha;
263 } else {
264 if (dy > 0)
265 angle[adj] = Math::pi + alpha;
266 else
267 angle[adj] = 2*Math::pi - alpha;
271 // get list of all adjacency entries at v
272 SListPure<adjEntry> entries;
273 tree.adjEntries(v, entries);
275 // sort entries according to angle
276 entries.quicksort(cmp);
278 // sort entries accordingly in tree
279 tree.sort(v,entries);
282 // adjacency lists are now sorted, so we can apply the usual call
283 call(AG);
287 void TreeLayout::call(GraphAttributes &AG)
289 const Graph &tree = AG.constGraph();
290 if(tree.numberOfNodes() == 0) return;
292 if (!isForest(tree))
293 OGDF_THROW_PARAM(PreconditionViolatedException, pvcForest);
295 OGDF_ASSERT(m_siblingDistance > 0);
296 OGDF_ASSERT(m_subtreeDistance > 0);
297 OGDF_ASSERT(m_levelDistance > 0);
299 // compute the tree structure
300 List<node> roots;
301 initializeTreeStructure(tree,roots);
303 if(m_orientation == topToBottom || m_orientation == bottomToTop)
305 ListConstIterator<node> it;
306 double minX = 0, maxX = 0;
307 for(it = roots.begin(); it.valid(); ++it)
309 node root = *it;
311 // compute x-coordinates
312 firstWalk(root,AG,true);
313 secondWalkX(root,-m_preliminary[root],AG);
315 // compute y-coordinates
316 computeYCoordinatesAndEdgeShapes(root,AG);
318 if(it != roots.begin())
320 findMinX(AG,root,minX);
322 double shift = maxX + m_treeDistance - minX;
324 shiftTreeX(AG,root,shift);
327 findMaxX(AG,root,maxX);
330 // The computed layout draws a tree upwards. If we want to draw the
331 // tree downwards, we simply invert all y-coordinates.
332 if(m_orientation == topToBottom)
334 node v;
335 forall_nodes(v,tree)
336 AG.y(v) = -AG.y(v);
338 edge e;
339 forall_edges(e,tree) {
340 ListIterator<DPoint> it;
341 for(it = AG.bends(e).begin(); it.valid(); ++it)
342 (*it).m_y = -(*it).m_y;
346 } else {
347 ListConstIterator<node> it;
348 double minY = 0, maxY = 0;
349 for(it = roots.begin(); it.valid(); ++it)
351 node root = *it;
353 // compute y-coordinates
354 firstWalk(root,AG,false);
355 secondWalkY(root,-m_preliminary[root],AG);
357 // compute y-coordinates
358 computeXCoordinatesAndEdgeShapes(root,AG);
360 if(it != roots.begin())
362 findMinY(AG,root,minY);
364 double shift = maxY + m_treeDistance - minY;
366 shiftTreeY(AG,root,shift);
369 findMaxY(AG,root,maxY);
372 // The computed layout draws a tree upwards. If we want to draw the
373 // tree downwards, we simply invert all y-coordinates.
374 if(m_orientation == rightToLeft)
376 node v;
377 forall_nodes(v,tree)
378 AG.x(v) = -AG.x(v);
380 edge e;
381 forall_edges(e,tree) {
382 ListIterator<DPoint> it;
383 for(it = AG.bends(e).begin(); it.valid(); ++it)
384 (*it).m_x = -(*it).m_x;
390 // delete the tree structure
391 deleteTreeStructure();
393 // restore temporarily removed edges again
394 undoReverseEdges(AG);
397 void TreeLayout::undoReverseEdges(GraphAttributes &AG)
399 if(m_pGraph) {
400 while(!m_reversedEdges.empty()) {
401 edge e = m_reversedEdges.popFrontRet();
402 m_pGraph->reverseEdge(e);
403 AG.bends(e).reverse();
406 m_pGraph = 0;
410 void TreeLayout::findMinX(GraphAttributes &AG, node root, double &minX)
412 Stack<node> S;
413 S.push(root);
415 while(!S.empty())
417 node v = S.pop();
419 double left = AG.x(v) - AG.width(v)/2;
420 if(left < minX) minX = left;
422 edge e;
423 forall_adj_edges(e,v) {
424 node w = e->target();
425 if(w != v) S.push(w);
430 void TreeLayout::findMinY(GraphAttributes &AG, node root, double &minY)
432 Stack<node> S;
433 S.push(root);
435 while(!S.empty())
437 node v = S.pop();
439 double left = AG.y(v) - AG.height(v)/2;
440 if(left < minY) minY = left;
442 edge e;
443 forall_adj_edges(e,v) {
444 node w = e->target();
445 if(w != v) S.push(w);
451 void TreeLayout::shiftTreeX(GraphAttributes &AG, node root, double shift)
453 Stack<node> S;
454 S.push(root);
455 while(!S.empty())
457 node v = S.pop();
459 AG.x(v) += shift;
461 edge e;
462 forall_adj_edges(e,v) {
463 node w = e->target();
464 if(w != v) {
465 ListIterator<DPoint> itP;
466 for(itP = AG.bends(e).begin(); itP.valid(); ++itP)
467 (*itP).m_x += shift;
468 S.push(w);
474 void TreeLayout::shiftTreeY(GraphAttributes &AG, node root, double shift)
476 Stack<node> S;
477 S.push(root);
478 while(!S.empty())
480 node v = S.pop();
482 AG.y(v) += shift;
484 edge e;
485 forall_adj_edges(e,v) {
486 node w = e->target();
487 if(w != v) {
488 ListIterator<DPoint> itP;
489 for(itP = AG.bends(e).begin(); itP.valid(); ++itP)
490 (*itP).m_y += shift;
491 S.push(w);
498 void TreeLayout::findMaxX(GraphAttributes &AG, node root, double &maxX)
500 Stack<node> S;
501 S.push(root);
502 while(!S.empty())
504 node v = S.pop();
506 double right = AG.x(v) + AG.width(v)/2;
507 if(right > maxX) maxX = right;
509 edge e;
510 forall_adj_edges(e,v) {
511 node w = e->target();
512 if(w != v) S.push(w);
517 void TreeLayout::findMaxY(GraphAttributes &AG, node root, double &maxY)
519 Stack<node> S;
520 S.push(root);
521 while(!S.empty())
523 node v = S.pop();
525 double right = AG.y(v) + AG.height(v)/2;
526 if(right > maxY) maxY = right;
528 edge e;
529 forall_adj_edges(e,v) {
530 node w = e->target();
531 if(w != v) S.push(w);
537 //node TreeLayout::initializeTreeStructure(const Graph &tree)
538 void TreeLayout::initializeTreeStructure(const Graph &tree, List<node> &roots)
540 node v;
542 // initialize node arrays
543 m_number .init(tree,0);
544 m_parent .init(tree,0);
545 m_leftSibling.init(tree,0);
546 m_firstChild .init(tree,0);
547 m_lastChild .init(tree,0);
548 m_thread .init(tree,0);
549 m_ancestor .init(tree,0);
550 m_preliminary.init(tree,0);
551 m_modifier .init(tree,0);
552 m_change .init(tree,0);
553 m_shift .init(tree,0);
555 // compute the tree structure
557 // find the roots
558 //node root = 0;
559 forall_nodes(v,tree) {
560 if(v->indeg() == 0)
561 roots.pushBack(v);
564 int childCounter;
565 forall_nodes(v,tree) {
567 // determine
568 // - the parent node of v
569 // - the leftmost and rightmost child of v
570 // - the numbers of the children of v
571 // - the left siblings of the children of v
572 // and initialize the actual ancestor of v
574 m_ancestor[v] = v;
575 if(isLeaf(v)) {
576 if(v->indeg() == 0) { // is v a root
577 m_parent[v] = 0;
578 m_leftSibling[v] = 0;
580 else {
581 m_firstChild[v] = m_lastChild[v] = 0;
582 m_parent[v] = v->firstAdj()->theEdge()->source();
585 else {
587 // traverse the adjacency list of v
588 adjEntry first; // first leaving edge
589 adjEntry stop; // successor of last leaving edge
590 first = v->firstAdj();
591 if(v->indeg() == 0) { // is v a root
592 stop = first;
593 m_parent[v] = 0;
594 m_leftSibling[v] = 0;
596 else {
598 // search for first leaving edge
599 while(first->theEdge()->source() == v)
600 first = first->cyclicSucc();
601 m_parent[v] = first->theEdge()->source();
602 stop = first;
603 first = first->cyclicSucc();
606 // traverse the children of v
607 m_firstChild[v] = first->theEdge()->target();
608 m_number[m_firstChild[v]] = childCounter = 0;
609 m_leftSibling[m_firstChild[v]] = 0;
610 adjEntry previous = first;
611 while(first->cyclicSucc() != stop) {
612 first = first->cyclicSucc();
613 m_number[first->theEdge()->target()] = ++childCounter;
614 m_leftSibling[first->theEdge()->target()]
615 = previous->theEdge()->target();
616 previous = first;
618 m_lastChild[v] = first->theEdge()->target();
624 void TreeLayout::deleteTreeStructure()
626 m_number .init();
627 m_parent .init();
628 m_leftSibling.init();
629 m_firstChild .init();
630 m_lastChild .init();
631 m_thread .init();
632 m_ancestor .init();
633 m_preliminary.init();
634 m_modifier .init();
635 m_change .init();
636 m_shift .init();
640 int TreeLayout::isLeaf(node v) const
642 OGDF_ASSERT(v != 0);
644 // node v is a leaf if and only if no edge leaves v
645 return v->outdeg() == 0;
649 node TreeLayout::nextOnLeftContour(node v) const
651 OGDF_ASSERT(v != 0);
652 OGDF_ASSERT(v->graphOf() == m_firstChild.graphOf());
653 OGDF_ASSERT(v->graphOf() == m_thread.graphOf());
655 // if v has children, the successor of v on the left contour
656 // is its leftmost child,
657 // otherwise, the successor is the thread of v (may be 0)
658 if(m_firstChild[v] != 0)
659 return m_firstChild[v];
660 else
661 return m_thread[v];
665 node TreeLayout::nextOnRightContour(node v) const
667 OGDF_ASSERT(v != 0);
668 OGDF_ASSERT(v->graphOf() == m_lastChild.graphOf());
669 OGDF_ASSERT(v->graphOf() == m_thread.graphOf());
671 // if v has children, the successor of v on the right contour
672 // is its rightmost child,
673 // otherwise, the successor is the thread of v (may be 0)
674 if(m_lastChild[v] != 0)
675 return m_lastChild[v];
676 else
677 return m_thread[v];
681 void TreeLayout::firstWalk(node subtree,const GraphAttributes &AG,bool upDown)
683 OGDF_ASSERT(subtree != 0);
684 OGDF_ASSERT(subtree->graphOf() == m_leftSibling.graphOf());
685 OGDF_ASSERT(subtree->graphOf() == m_preliminary.graphOf());
686 OGDF_ASSERT(subtree->graphOf() == m_firstChild.graphOf());
687 OGDF_ASSERT(subtree->graphOf() == m_lastChild.graphOf());
688 OGDF_ASSERT(subtree->graphOf() == m_modifier.graphOf());
689 OGDF_ASSERT(subtree->graphOf() == m_change.graphOf());
690 OGDF_ASSERT(subtree->graphOf() == m_shift.graphOf());
692 // compute a preliminary x-coordinate for subtree
693 if(isLeaf(subtree)) {
695 // place subtree close to the left sibling
696 node leftSibling = m_leftSibling[subtree];
697 if(leftSibling != 0) {
698 if(upDown) {
699 m_preliminary[subtree] = m_preliminary[leftSibling]
700 + (AG.width(subtree) + AG.width(leftSibling)) / 2
701 + m_siblingDistance;
702 } else {
703 m_preliminary[subtree] = m_preliminary[leftSibling]
704 + (AG.height(subtree) + AG.height(leftSibling)) / 2
705 + m_siblingDistance;
708 else m_preliminary[subtree] = 0;
710 else {
711 node defaultAncestor = m_firstChild[subtree];
713 // collect the children of subtree
714 List<node> children;
715 node v = m_lastChild[subtree];
716 do {
717 children.pushFront(v);
718 v = m_leftSibling[v];
719 } while(v != 0);
721 ListIterator<node> it;
723 // apply firstwalk and apportion to the children
724 for(it = children.begin(); it.valid(); it = it.succ()) {
725 firstWalk(*it,AG,upDown);
726 apportion(*it,defaultAncestor,AG,upDown);
729 // shift the small subtrees
730 double shift = 0;
731 double change = 0;
732 children.reverse();
733 for(it = children.begin(); it.valid(); it = it.succ()) {
734 m_preliminary[*it] += shift;
735 m_modifier[*it] += shift;
736 change += m_change[*it];
737 shift += m_shift[*it] + change;
740 // place the parent node
741 double midpoint = (m_preliminary[children.front()] + m_preliminary[children.back()]) / 2;
742 node leftSibling = m_leftSibling[subtree];
743 if(leftSibling != 0) {
744 if(upDown) {
745 m_preliminary[subtree] = m_preliminary[leftSibling]
746 + (AG.width(subtree) + AG.width(leftSibling)) / 2
747 + m_siblingDistance;
748 } else {
749 m_preliminary[subtree] = m_preliminary[leftSibling]
750 + (AG.height(subtree) + AG.height(leftSibling)) / 2
751 + m_siblingDistance;
753 m_modifier[subtree] =
754 m_preliminary[subtree] - midpoint;
756 else m_preliminary[subtree] = midpoint;
760 void TreeLayout::apportion(
761 node subtree,
762 node &defaultAncestor,
763 const GraphAttributes &AG,
764 bool upDown)
766 OGDF_ASSERT(subtree != 0);
767 OGDF_ASSERT(subtree->graphOf() == defaultAncestor->graphOf());
768 OGDF_ASSERT(subtree->graphOf() == m_leftSibling.graphOf());
769 OGDF_ASSERT(subtree->graphOf() == m_firstChild.graphOf());
770 OGDF_ASSERT(subtree->graphOf() == m_modifier.graphOf());
771 OGDF_ASSERT(subtree->graphOf() == m_ancestor.graphOf());
772 OGDF_ASSERT(subtree->graphOf() == m_change.graphOf());
773 OGDF_ASSERT(subtree->graphOf() == m_shift.graphOf());
774 OGDF_ASSERT(subtree->graphOf() == m_thread.graphOf());
776 if(m_leftSibling[subtree] == 0) return;
778 // check distance to the left of the subtree
779 // and traverse left/right inside/outside contour
781 double leftModSumOut = 0; // sum of modifiers on left outside contour
782 double leftModSumIn = 0; // sum of modifiers on left inside contour
783 double rightModSumIn = 0; // sum of modifiers on right inside contour
784 double rightModSumOut = 0; // sum of modifiers on right outside contour
786 double moveDistance;
787 int numberOfSubtrees;
788 node leftAncestor,rightAncestor;
790 // start the traversal at the actual level
791 node leftContourOut = m_firstChild[m_parent[subtree]];
792 node leftContourIn = m_leftSibling[subtree];
793 node rightContourIn = subtree;
794 node rightContourOut = subtree;
795 bool stop = false;
796 do {
798 // add modifiers
799 leftModSumOut += m_modifier[leftContourOut];
800 leftModSumIn += m_modifier[leftContourIn];
801 rightModSumIn += m_modifier[rightContourIn];
802 rightModSumOut += m_modifier[rightContourOut];
804 // actualize ancestor for right contour
805 m_ancestor[rightContourOut] = subtree;
807 if(nextOnLeftContour(leftContourOut) != 0 && nextOnRightContour(rightContourOut) != 0)
809 // continue traversal
810 leftContourOut = nextOnLeftContour(leftContourOut);
811 leftContourIn = nextOnRightContour(leftContourIn);
812 rightContourIn = nextOnLeftContour(rightContourIn);
813 rightContourOut = nextOnRightContour(rightContourOut);
815 // check if subtree has to be moved
816 if(upDown) {
817 moveDistance = m_preliminary[leftContourIn] + leftModSumIn
818 + (AG.width(leftContourIn) + AG.width(rightContourIn)) / 2
819 + m_subtreeDistance
820 - m_preliminary[rightContourIn] - rightModSumIn;
821 } else {
822 moveDistance = m_preliminary[leftContourIn] + leftModSumIn
823 + (AG.height(leftContourIn) + AG.height(rightContourIn)) / 2
824 + m_subtreeDistance
825 - m_preliminary[rightContourIn] - rightModSumIn;
827 if(moveDistance > 0) {
829 // compute highest different ancestors of leftContourIn
830 // and rightContourIn
831 if(m_parent[m_ancestor[leftContourIn]] == m_parent[subtree])
832 leftAncestor = m_ancestor[leftContourIn];
833 else leftAncestor = defaultAncestor;
834 rightAncestor = subtree;
836 // compute the number of small subtrees in between (plus 1)
837 numberOfSubtrees =
838 m_number[rightAncestor] - m_number[leftAncestor];
840 // compute the shifts and changes of shift
841 m_change[rightAncestor] -= moveDistance / numberOfSubtrees;
842 m_shift[rightAncestor] += moveDistance;
843 m_change[leftAncestor] += moveDistance / numberOfSubtrees;
845 // move subtree to the right by moveDistance
846 m_preliminary[rightAncestor] += moveDistance;
847 m_modifier[rightAncestor] += moveDistance;
848 rightModSumIn += moveDistance;
849 rightModSumOut += moveDistance;
852 else stop = true;
853 } while(!stop);
855 // adjust threads
856 if(nextOnRightContour(rightContourOut) == 0 && nextOnRightContour(leftContourIn) != 0)
858 // right subtree smaller than left subforest
859 m_thread[rightContourOut] = nextOnRightContour(leftContourIn);
860 m_modifier[rightContourOut] += leftModSumIn - rightModSumOut;
863 if(nextOnLeftContour(leftContourOut) == 0 && nextOnLeftContour(rightContourIn) != 0)
865 // left subforest smaller than right subtree
866 m_thread[leftContourOut] = nextOnLeftContour(rightContourIn);
867 m_modifier[leftContourOut] += rightModSumIn - leftModSumOut;
868 defaultAncestor = subtree;
873 void TreeLayout::secondWalkX(node subtree,
874 double modifierSum,
875 GraphAttributes &AG)
877 OGDF_ASSERT(subtree != 0);
878 OGDF_ASSERT(subtree->graphOf() == m_preliminary.graphOf());
879 OGDF_ASSERT(subtree->graphOf() == m_modifier.graphOf());
881 // compute final x-coordinates for the subtree
882 // by recursively aggregating modifiers
883 AG.x(subtree) = m_preliminary[subtree] + modifierSum;
884 modifierSum += m_modifier[subtree];
885 edge e;
886 forall_adj_edges(e,subtree) if(e->target() != subtree)
887 secondWalkX(e->target(),modifierSum,AG);
890 void TreeLayout::secondWalkY(node subtree,
891 double modifierSum,
892 GraphAttributes &AG)
894 OGDF_ASSERT(subtree != 0);
895 OGDF_ASSERT(subtree->graphOf() == m_preliminary.graphOf());
896 OGDF_ASSERT(subtree->graphOf() == m_modifier.graphOf());
898 // compute final y-coordinates for the subtree
899 // by recursively aggregating modifiers
900 AG.y(subtree) = m_preliminary[subtree] + modifierSum;
901 modifierSum += m_modifier[subtree];
902 edge e;
903 forall_adj_edges(e,subtree) if(e->target() != subtree)
904 secondWalkY(e->target(),modifierSum,AG);
908 void TreeLayout::computeYCoordinatesAndEdgeShapes(node root, GraphAttributes &AG)
910 OGDF_ASSERT(root != 0);
912 // compute y-coordinates and edge shapes
913 node v,w;
914 edge e;
915 List<node> oldLevel; // the nodes of the old level
916 List<node> newLevel; // the nodes of the new level
917 ListIterator<node> it;
918 double yCoordinate; // the y-coordinate for the new level
919 double edgeCoordinate; // the y-coordinate for edge bends
920 double oldHeight; // the maximal node height on the old level
921 double newHeight; // the maximal node height on the new level
923 // traverse the tree level by level
924 newLevel.pushBack(root);
925 AG.y(root) = yCoordinate = 0;
926 newHeight = AG.height(root);
927 while(!newLevel.empty()) {
928 oldHeight = newHeight;
929 newHeight = 0;
930 oldLevel.conc(newLevel);
931 while(!oldLevel.empty()) {
932 v = oldLevel.popFrontRet();
933 forall_adj_edges(e,v) if(e->target() != v) {
934 w = e->target();
935 newLevel.pushBack(w);
937 // compute the shape of edge e
938 DPolyline &edgeBends = AG.bends(e);
939 edgeBends.clear();
940 if(m_orthogonalLayout) {
941 edgeCoordinate =
942 yCoordinate + (oldHeight + m_levelDistance) / 2;
943 edgeBends.pushBack(DPoint(AG.x(v),edgeCoordinate));
944 edgeBends.pushBack(DPoint(AG.x(w),edgeCoordinate));
947 // compute the maximal node height on the new level
948 if(AG.height(e->target()) > newHeight)
949 newHeight = AG.height(e->target());
953 // assign y-coordinate to the nodes of the new level
954 yCoordinate += (oldHeight + newHeight) / 2 + m_levelDistance;
955 for(it = newLevel.begin(); it.valid(); it = it.succ())
956 AG.y(*it) = yCoordinate;
960 void TreeLayout::computeXCoordinatesAndEdgeShapes(node root, GraphAttributes &AG)
962 OGDF_ASSERT(root != 0);
964 // compute y-coordinates and edge shapes
965 node v,w;
966 edge e;
967 List<node> oldLevel; // the nodes of the old level
968 List<node> newLevel; // the nodes of the new level
969 ListIterator<node> it;
970 double xCoordinate; // the x-coordinate for the new level
971 double edgeCoordinate; // the x-coordinate for edge bends
972 double oldWidth; // the maximal node width on the old level
973 double newWidth; // the maximal node width on the new level
975 // traverse the tree level by level
976 newLevel.pushBack(root);
977 AG.x(root) = xCoordinate = 0;
978 newWidth = AG.width(root);
979 while(!newLevel.empty()) {
980 oldWidth = newWidth;
981 newWidth = 0;
982 oldLevel.conc(newLevel);
983 while(!oldLevel.empty()) {
984 v = oldLevel.popFrontRet();
985 forall_adj_edges(e,v) if(e->target() != v) {
986 w = e->target();
987 newLevel.pushBack(w);
989 // compute the shape of edge e
990 DPolyline &edgeBends = AG.bends(e);
991 edgeBends.clear();
992 if(m_orthogonalLayout) {
993 edgeCoordinate =
994 xCoordinate + (oldWidth + m_levelDistance) / 2;
995 edgeBends.pushBack(DPoint(edgeCoordinate,AG.y(v)));
996 edgeBends.pushBack(DPoint(edgeCoordinate,AG.y(w)));
999 // compute the maximal node width on the new level
1000 if(AG.width(e->target()) > newWidth)
1001 newWidth = AG.width(e->target());
1005 // assign x-coordinate to the nodes of the new level
1006 xCoordinate += (oldWidth + newWidth) / 2 + m_levelDistance;
1007 for(it = newLevel.begin(); it.valid(); it = it.succ())
1008 AG.x(*it) = xCoordinate;
1013 } // end namespace ogdf