6 * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $
7 ***************************************************************/
10 * \brief Implementation of Mixed-Model basic functionality.
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 "MixedModelBase.h"
45 #include <ogdf/basic/extended_graph_alg.h>
46 #include <ogdf/basic/simple_graph_alg.h>
52 /********************************************************************
55 Determine if the kth set in the ordered partition has a "real"
56 left or right vertex, respectively.
57 ********************************************************************/
59 bool MixedModelBase::hasLeft (int k
) const
61 const ShellingOrderSet
&V
= m_mmo
[k
];
62 const List
<InOutPoint
> &L
= m_iops
.inpoints(V
[1]);
64 ListConstIterator
<InOutPoint
> it
= L
.begin();
65 return (it
.valid() && (*it
).m_adj
->twinNode() == m_mmo
.m_left
[k
]);
68 bool MixedModelBase::hasRight(int k
) const
70 const ShellingOrderSet
&V
= m_mmo
[k
];
71 const List
<InOutPoint
> &L
= m_iops
.inpoints(V
[V
.len()]);
73 ListConstIterator
<InOutPoint
> it
= L
.rbegin();
74 return (it
.valid() && (*it
).m_adj
->twinNode() == m_mmo
.m_right
[k
]);
78 /********************************************************************
81 Computes the ordered partition (incl. m_left[k], m_right[k]) and
82 constructs the in- and outpoint lists.
83 ********************************************************************/
86 void MixedModelBase::computeOrder(
87 AugmentationModule
&augmenter
,
88 EmbedderModule
*pEmbedder
,
90 ShellingOrderModule
&compOrder
)
92 // remove (temporary) deg-1-nodes;
95 // augment PG (temporary) to achieve required connectivity
96 List
<edge
> augmentedEdges
;
97 augmenter
.call(m_PG
,augmentedEdges
);
99 // embed augmented graph (if required)
101 pEmbedder
->call(m_PG
,adjExternal
);
103 // compute ordering of biconnected plane graph
104 m_mmo
.init(m_PG
, compOrder
, adjExternal
);
106 // restore deg1-nodes and mark incident edges
107 m_iops
.restoreDeg1Nodes(m_PG
,m_deg1RestoreStack
);
109 // compute in- and outpoint lists
110 for (int k
= 1; k
<= m_mmo
.length(); ++k
)
112 const ShellingOrderSet
&V
= m_mmo
[k
];
113 for (int i
= 1; i
<= V
.len(); ++i
)
116 node cl
= (i
== 1) ? V
.left () : V
[i
-1];
117 node cr
= (i
== V
.len()) ? V
.right() : V
[i
+1];
119 //edge e, er = 0, el = 0;
120 adjEntry adj
, adjR
= 0, adjL
= 0;
123 node t
= adj
->twinNode();
124 if (t
== cr
) adjR
= adj
;
125 if (t
== cl
) adjL
= adj
;
127 // one of adjL and adjR is not 0 by definition of the ordering
128 if (adjR
== 0) adjR
= adjL
;
129 if (adjL
== 0) adjL
= adjR
;
134 m_iops
.pushInpoint(adj
);
135 adj
= adj
->cyclicSucc();
136 } while (m_iops
.marked(adj
) || (m_mmo
.rank(adj
->twinNode()) <= k
&& adj
!= adjR
));
138 for ( ; m_iops
.marked(adj
) || m_mmo
.rank(adj
->twinNode()) > k
; adj
= adj
->cyclicSucc())
140 m_iops
.appendOutpoint(adj
);
142 // move In-/Outpoints to deg1-nodes to appropriate places
143 adjL
= m_iops
.switchBeginIn(v
);
144 adjR
= m_iops
.switchEndIn (v
);
146 // has a left- or right edge ?
147 bool has_el
= (adjL
!= 0);
148 bool has_er
= (adjR
!= 0);
149 if (adjL
&& adjL
== adjR
) {
150 has_el
= (adjL
->twinNode() != cr
);
154 // determine left(k) and right(k)
155 if (i
== 1) m_mmo
.m_left
[k
] = (has_el
) ? adjL
->twinNode() : cl
;
156 if (i
== V
.len()) m_mmo
.m_right
[k
] = (has_er
) ? adjR
->twinNode() : cr
;
159 m_iops
.numDeg1(v
,xl
,xr
,has_el
|| has_er
);
162 if (!has_el
) x
+= xl
;
163 if (!has_er
) x
+= xr
;
165 int x_alpha
= max(0,min(x
, (m_iops
.in(v
)-m_iops
.out(v
)+1+2*x
-2)/2));
166 int x_beta
= x
- x_alpha
;
169 for( ; x_beta
> 0 && xl
> 0; --x_beta
, --xl
)
170 m_iops
.switchBeginOut(v
);
172 for( ; x_beta
> 0 && xr
> 0; --x_beta
, --xr
)
173 m_iops
.switchEndOut(v
);
177 // remove augmented edges
178 ListConstIterator
<edge
> itE
;
179 for(itE
= augmentedEdges
.begin(); itE
.valid(); ++itE
)
184 /********************************************************************
187 Removes deg-1-nodes and store informations for restoring them.
188 ********************************************************************/
190 void MixedModelBase::removeDeg1Nodes()
192 NodeArray
<bool> mark(m_PG
,false);
195 // mark all deg-1-nodes we want to remove
196 int n
= m_PG
.numberOfNodes();
197 forall_nodes(v
,m_PG
) {
199 if ((mark
[v
] = (v
->degree() == 1)) == true) {
200 node w
= v
->firstAdj()->twinNode();
201 if (mark
[w
]) mark
[w
] = false; else --n
;
205 m_PG
.removeDeg1Nodes(m_deg1RestoreStack
,mark
);
209 /********************************************************************
212 Computes the relative coordinates of the in- and outpoints,
213 incl. height(v), depth(v).
214 ********************************************************************/
216 void MixedModelBase::assignIopCoords()
218 for (int k
= 1; k
<= m_mmo
.length(); ++k
)
220 const ShellingOrderSet
&V
= m_mmo
[k
];
222 for (int i
= 1; i
<= V
.len(); ++i
)
226 bool onlyLeft
= (m_iops
.in(v
) == 2 &&
227 i
>= 2 && m_iops
.inpoints(v
).front().m_adj
->twinNode() == V
[i
-1] &&
228 m_iops
.marked(m_iops
.inpoints(v
).back().m_adj
));
229 bool onlyRight
= (m_iops
.in(v
) == 2 &&
230 i
< V
.len() && m_iops
.inpoints(v
).back().m_adj
->twinNode() == V
[i
+1] &&
231 m_iops
.marked(m_iops
.inpoints(v
).front().m_adj
));
233 if (m_iops
.out(v
) >= 1)
235 int outL
= 0, outR
= 0;
237 int outPlus
= m_iops
.out(v
)/2;
238 int outMinus
= m_iops
.out(v
) - 1 - outPlus
;
239 int deltaL
= 0, deltaR
= 0;
242 if (m_iops
.in(v
) == 2) {
243 deltaL
= (onlyRight
) ? 0 : 1;
244 deltaR
= (onlyLeft
) ? 0 : 1;
246 } else if (m_iops
.in(v
) >= 3) {
249 } else if (m_iops
.in(v
) == 1) {
250 node vl
= (i
== 1) ? m_mmo
.m_left
[k
] : V
[i
-1];
251 if (m_iops
.inpoints(v
).front().m_adj
->twinNode() != vl
) {
260 outR
= m_iops
.out(v
) - 1 - outL
;
262 List
<InOutPoint
> &opl
= m_iops
.outpoints(v
);
264 ListIterator
<InOutPoint
> it
= opl
.begin();
265 for (j
= 0; j
< outL
; j
++, ++it
)
266 m_iops
.setOutCoord(it
,-outL
+j
,deltaL
+j
);
267 m_iops
.m_height
[v
] = max(outL
+deltaL
,outR
+deltaR
)-1;
268 if (m_iops
.m_height
[v
] == 0 && m_iops
.marked((*it
).m_adj
))
269 m_iops
.m_height
[v
] = 1;
270 m_iops
.setOutCoord(it
,0,m_iops
.m_height
[v
]);
271 for (j
= 1, ++it
; j
<= outR
; j
++, ++it
)
272 m_iops
.setOutCoord(it
,j
,outR
+deltaR
-j
);
275 if (m_iops
.in(v
) <= 3)
277 List
<InOutPoint
> &ipl
= m_iops
.inpoints(v
);
278 int in_v
= m_iops
.in(v
);
280 if (in_v
== 3 || (in_v
== 2 && !onlyRight
)) {
281 if (m_iops
.marked(ipl
.front().m_adj
))
282 m_iops
.setInCoord(ipl
.begin(),-1,0);
284 if (in_v
== 3 || (in_v
== 2 && !onlyLeft
)) {
285 if (m_iops
.marked(ipl
.back().m_adj
))
286 m_iops
.setInCoord(ipl
.rbegin(), 1,0);
288 if (in_v
!= 0 && (in_v
!= 2 || onlyLeft
|| onlyRight
)) {
289 ListIterator
<InOutPoint
> it
= ipl
.begin();
290 if (in_v
== 3 || (in_v
== 2 && onlyLeft
))
292 if (m_iops
.marked((*it
).m_adj
)) {
293 m_iops
.setInCoord(it
,0,-1);
294 m_iops
.m_depth
[v
] = 1;
299 int in_l
= (m_iops
.in(v
)-3) / 2;
300 int in_r
= m_iops
.in(v
)-3 - in_l
;
303 List
<InOutPoint
> &ipl
= m_iops
.inpoints(v
);
304 ListIterator
<InOutPoint
> it
= ipl
.begin();
305 m_iops
.setInCoord(it
,(in_l
== 0 && m_iops
.marked((*it
).m_adj
)) ? -1 : -in_l
,0);
306 for (j
= 1, ++it
; j
<= in_l
; ++j
, ++it
)
307 m_iops
.setInCoord(it
,j
-in_l
-1,-j
);
308 m_iops
.setInCoord(it
,0,-in_r
);
309 m_iops
.m_depth
[v
] = in_r
; // inpoint with smallest y-coordinate
310 for (j
= 1, ++it
; j
<= in_r
; ++j
, ++it
)
311 m_iops
.setInCoord(it
,j
,j
-in_r
-1);
312 m_iops
.setInCoord(it
,in_r
,0);
319 /********************************************************************
322 Implements the placement step. Computes x[v] and y[v].
323 ********************************************************************/
325 void MixedModelBase::placeNodes()
327 m_dyl
.init(2,m_mmo
.length());
328 m_dyr
.init(2,m_mmo
.length());
330 m_leftOp
.init(2,m_mmo
.length());
331 m_rightOp
.init(2,m_mmo
.length());
333 m_nextLeft
.init(m_PG
);
334 m_nextRight
.init(m_PG
);
343 /********************************************************************
346 Computes the absolute x-coordinates x[v] of all nodes in the
347 ordering, furthermore dyla[k] and dyra[k] (used by compute_y_coordinates)
348 ********************************************************************/
350 void MixedModelBase::computeXCoords()
352 NodeArray
<int> &x
= m_gridLayout
.x();
357 // representation of the contour
358 NodeArray
<node
> prev(m_PG
), next(m_PG
);
359 NodeArray
<node
> father(m_PG
, 0);
361 // maintaining of free space for shifting
362 Array
<int> shiftSpace(1,m_mmo
.length(), 0);
363 NodeArray
<int> comp(m_PG
,0);
365 forall_nodes(v
,m_PG
) {
366 m_nextLeft
[v
] = m_iops
.firstRealOut(v
);
367 m_nextRight
[v
] = m_iops
.lastRealOut (v
);
370 // last_right[v] = last vertex of highest set with right vertex v
371 NodeArray
<node
> lastRight(m_PG
,0);
372 for(k
= 2; k
<= m_mmo
.length(); ++k
) {
373 const ShellingOrderSet
&V
= m_mmo
[k
];
374 lastRight
[m_mmo
.m_right
[k
]] = V
[V
.len()];
377 NodeArray
<int> high(m_PG
,0);
378 forall_nodes(v
,m_PG
) {
380 ListConstIterator
<InOutPoint
> it
;
381 for(it
= m_iops
.outpoints(v
).begin(); it
.valid(); ++it
) {
382 if (!m_iops
.marked((*it
).m_adj
))
383 high
[v
] = max(m_mmo
.rank((*it
).m_adj
->twinNode()), high
[v
]);
388 const ShellingOrderSet
&V1
= m_mmo
[1];
391 x
[V1
[1]] = m_iops
.outLeft(V1
[1]);
392 for (i
= 2; i
<= p
; i
++) {
393 x
[V1
[i
]] = m_iops
.maxRight(V1
[i
-1]) + m_iops
.maxLeft(V1
[i
]) + 1;
396 for (i
= 1; i
<= p
; i
++) {
397 if (i
< p
) next
[V1
[i
]] = V1
[i
+1];
398 if (i
> 1) prev
[V1
[i
]] = V1
[i
-1];
400 prev
[V1
[1]] = next
[V1
[p
]] = 0;
403 for(k
= 2; k
<= m_mmo
.length(); ++k
)
406 const ShellingOrderSet
&Vk
= m_mmo
[k
];
409 node cl
= m_mmo
.m_left
[k
];
410 node cr
= m_mmo
.m_right
[k
];
413 while(lastRight
[cl
] && high
[cl
] < k
&& !hasRight(m_mmo
.rank(lastRight
[cl
])))
414 cl
= m_mmo
.m_left
[k
] = lastRight
[cl
];
417 // determine temporarily the x-coordinates of c_l+1,...,c_r relative to cl
419 for (v
= next
[cl
]; v
!= cr
; v
= next
[v
]) {
420 sum
+= x
[v
]; x
[v
] = sum
;
424 m_leftOp
[k
] = m_nextRight
[cl
];
425 m_rightOp
[k
] = m_nextLeft
[cr
];
427 // compute dxl, dxr, dyl, dyr
429 m_dyl
[k
] = m_dyr
[k
] = 0;
431 ListConstIterator
<InOutPoint
> it
;
432 if ((it
= m_nextRight
[cl
]).valid()) {
434 if ((*it
).m_adj
->twinNode() != z1
)
437 m_nextRight
[cl
] = m_iops
.prevRealOut(it
);
440 m_dyl
[k
] = m_iops
.m_height
[cl
];
441 else if ((++it
).valid())
442 m_dyl
[k
] = (*it
).m_dy
;
444 dxl
= (m_iops
.out(cl
) == 0) ? 0 : -m_iops
.outLeft(cl
);
446 if ((it
= m_nextLeft
[cr
]).valid()) {
448 if ((*it
).m_adj
->twinNode() != Vk
[p
])
451 m_nextLeft
[cr
] = m_iops
.nextRealOut(it
);
454 m_dyr
[k
] = m_iops
.m_height
[cr
];
455 else if ((it
= it
.pred()).valid())
456 m_dyr
[k
] = (*it
).m_dy
;
458 dxr
= (m_iops
.out(cr
) == 0) ? 0 : m_iops
.outRight(cr
);
461 m_dxla
[Vk
[1]] = dxl
; m_dxra
[Vk
[p
]] = dxr
;
466 if (!m_iops
.isChain(z1
))
468 InOutPoint ip_ct
= m_iops
.middleNeighbor(z1
);
469 InOutPoint op_ct
= *m_iops
.pointOf(ip_ct
.m_adj
->twin());
470 node ct
= ip_ct
.m_adj
->twinNode();
472 int delta
= dxl
+ m_iops
.maxPlusLeft(z1
) + ip_ct
.m_dx
- (x
[ct
] + op_ct
.m_dx
);
473 if (delta
< 0) delta
= 0;
476 int x_0
= x
[ct
] + op_ct
.m_dx
- ip_ct
.m_dx
;
479 for (v
= prev
[ct
]; v
!= cl
; v
= prev
[v
]) {
481 if (m_nextRight
[v
].valid() && (*m_nextRight
[v
]).m_adj
->twinNode() == z1
) {
482 InOutPoint op_v
= *m_nextRight
[v
];
483 InOutPoint ip_v
= *m_iops
.pointOf(op_v
.m_adj
->twin());
484 int diff
= x
[v
] + op_v
.m_dx
- x_0
- ip_v
.m_dx
;
492 for (v
= next
[cl
]; v
!= next
[ct
]; v
= next
[v
])
498 for (v
= next
[ct
]; v
!= next
[cr
]; v
= next
[v
]) {
500 if (m_nextRight
[v
].valid() && (*m_nextRight
[v
]).m_adj
->twinNode() == z1
) {
501 InOutPoint op_v
= *m_nextRight
[v
];
502 InOutPoint ip_v
= *m_iops
.pointOf(op_v
.m_adj
->twin());
503 int diff
= x
[v
] + op_v
.m_dx
- x_0
- ip_v
.m_dx
;
513 old_x_cr
= x
[cr
] - x
[z1
];
514 x
[cr
] = max(old_x_cr
, m_iops
.maxPlusRight(z1
) - dxr
);
516 for (v
= next
[cl
]; v
!= cr
; v
= next
[v
]) {
523 int sum
= x
[z1
] = m_iops
.maxPlusLeft(z1
) + dxl
;
524 for (i
= 2; i
<= p
; i
++)
525 sum
+= (x
[Vk
[i
]] = m_iops
.maxRight(Vk
[i
-1]) + m_iops
.maxLeft(Vk
[i
]) + 1);
527 old_x_cr
= x
[cr
] - sum
;
528 int new_x_cr
= m_iops
.maxPlusRight(Vk
[p
]) - dxr
;
529 x
[cr
] = max(old_x_cr
, new_x_cr
);
530 shiftSpace
[k
] = max(0, old_x_cr
- new_x_cr
);
532 for (v
= next
[cl
]; v
!= cr
; v
= next
[v
]) {
538 int need
= x
[cr
] - old_x_cr
;
539 int k_cr
= m_mmo
.rank(cr
);
540 if (shiftSpace
[k_cr
] > 0) {
541 int use
= min(shiftSpace
[k_cr
], need
);
542 shiftSpace
[k_cr
] -= use
;
544 x
[m_mmo
.m_right
[k_cr
]] -= use
;
547 // update contour after insertion of z1,...,zp
548 for (i
= 1; i
<= p
; i
++) {
549 if (i
< p
) next
[Vk
[i
]] = Vk
[i
+1];
550 if (i
> 1) prev
[Vk
[i
]] = Vk
[i
-1];
553 next
[prev
[z1
] = cl
] = z1
;
554 prev
[next
[Vk
[p
]] = cr
] = Vk
[p
];
558 // compute final x-coordinates for nodes on final contour
560 for (v
= V1
[1]; v
!= 0; v
= next
[v
])
561 x
[v
] = (sum
+= x
[v
]);
563 // compute final x-coordinates for inner nodes
564 for (k
= m_mmo
.length(); k
>= 1; k
--) {
565 for (i
= 1; i
<= m_mmo
.len(k
); i
++) {
567 if (father
[v
] != 0) {
568 x
[v
] = x
[v
] + x
[father
[v
]] - comp
[father
[v
]];
575 /********************************************************************
578 Computes the absolute y-coordinates y[v] of all nodes in the
580 ********************************************************************/
585 SetYCoords(const Graph
&G
, const IOPoints
&iops
, const MMOrder
&mmo
,
586 const NodeArray
<int> &x
, const NodeArray
<int> &y
) :
587 m_G(G
), m_iops(iops
), m_mmo(mmo
), m_x(x
), m_y(y
) {
592 void checkYCoord (int xleft
, int xright
, int ys
, bool nodeSep
);
593 void checkYCoord (int xs
, int ys
, bool nodeSep
) {
594 checkYCoord (xs
, xs
, ys
, nodeSep
);
597 int getYmax() const {
601 // avoid automatic creation of assignment operator
602 SetYCoords
&operator=(const SetYCoords
&);
605 void getNextRegion();
606 node
z(int j
) const {
610 bool marked(adjEntry adj
) const {
611 return m_iops
.marked(adj
);
614 const InOutPoint
&outpoint(const InOutPoint
&ip
) {
615 return *m_iops
.pointOf(ip
.m_adj
->twin());
618 void searchNextInpoint();
621 const IOPoints
&m_iops
;
622 const MMOrder
&m_mmo
;
623 const NodeArray
<int> &m_x
;
624 const NodeArray
<int> &m_y
;
625 const ShellingOrderSet
*m_V
;
630 int m_ymax
, m_xNext
, m_lookAheadX
, m_lookAheadNextX
;
631 int m_i
, m_iNext
, m_deltaY
, m_infinity
;
632 ListConstIterator
<InOutPoint
> m_itIp
, m_itIpNext
, m_itLookAhead
;
636 void SetYCoords::init(int k
)
638 m_k
= k
; m_V
= &m_mmo
[k
];
643 m_cl
= m_mmo
.m_left
[k
]; m_cr
= m_mmo
.m_right
[k
];
645 m_onBase
= true; m_xNext
= -1;
646 m_infinity
= m_x
[m_cr
] + m_iops
.outRight(m_cr
) + 1;
649 m_itIp
= m_itIpNext
; m_i
= m_iNext
;
654 void SetYCoords::searchNextInpoint()
656 m_iNext
= m_i
; m_itIpNext
= m_itIp
;
659 if (!m_itIpNext
.valid()) {
660 if (++m_iNext
> m_V
->len()) {
661 m_itIpNext
= ListConstIterator
<InOutPoint
>();
664 m_itIpNext
= m_iops
.inpoints(z(m_iNext
)).begin();
668 } while (!m_itIpNext
.valid() || (*m_itIpNext
).m_dy
== 0);
670 if (m_itIpNext
.valid() && m_iops
.marked((*m_itIpNext
).m_adj
)) {
671 int ipX
= m_x
[z(m_iNext
)] + (*m_itIpNext
).m_dx
;
673 if (m_lookAheadX
<= ipX
) {
674 for (m_itLookAhead
= m_itIpNext
;
675 (*m_itLookAhead
).m_dx
< 0 && m_iops
.marked((*m_itLookAhead
).m_adj
);
678 const InOutPoint
&ipLookAhead
= *m_itLookAhead
;
679 m_lookAheadX
= m_x
[z(m_iNext
)] + ipLookAhead
.m_dx
;
680 if(ipLookAhead
.m_dx
< 0) {
681 m_lookAheadNextX
= m_x
[ipLookAhead
.m_adj
->twinNode()] + outpoint(ipLookAhead
).m_dx
;
683 m_lookAheadNextX
= m_lookAheadX
;
687 if (m_lookAheadNextX
<= ipX
) {
688 m_itIpNext
= m_itLookAhead
;
694 void SetYCoords::getNextRegion()
701 if (!m_itIp
.valid()) {
702 m_xNext
= m_infinity
;
704 const InOutPoint
&ip
= *m_itIp
;
705 m_xNext
= (marked(ip
.m_adj
)) ? (m_x
[z(m_i
)] + ip
.m_dx
) :
706 (m_x
[ip
.m_adj
->twinNode()] + outpoint(ip
).m_dx
);
708 m_onBase
= (m_iNext
!= m_i
);
711 const InOutPoint
&ip
= *m_itIp
;
714 if (m_itIpNext
.valid() && ip
.m_dx
< 0) {
715 const InOutPoint
&m_ipNext
= *m_itIpNext
;
716 m_xNext
= (marked(m_ipNext
.m_adj
)) ? (m_x
[z(m_i
)] + m_ipNext
.m_dx
) :
717 (m_x
[m_ipNext
.m_adj
->twinNode()] + outpoint(m_ipNext
).m_dx
);
719 m_xNext
= (marked(ip
.m_adj
)) ? (m_x
[z(m_i
)] + ip
.m_dx
+ 1) :
720 (m_x
[ip
.m_adj
->twinNode()] + outpoint(ip
).m_dx
+ 1);
723 m_onBase
= (m_iNext
!= m_i
);
724 m_i
= m_iNext
; m_itIp
= m_itIpNext
;
726 } while (m_xNext
<= xOld
);
729 void SetYCoords::checkYCoord(int xleft
, int xright
, int ys
, bool nodeSep
)
731 while (m_xNext
<= xleft
)
734 int maxDy
= m_deltaY
;
736 while (m_xNext
<= xright
) {
738 if (m_deltaY
> maxDy
) maxDy
= m_deltaY
;
741 if (nodeSep
&& maxDy
== 0)
744 if (ys
+ maxDy
> m_ymax
)
748 void MixedModelBase::computeYCoords()
750 NodeArray
<int> &x
= m_gridLayout
.x(), &y
= m_gridLayout
.y();
754 // representation of the contour
755 NodeArray
<node
> prev(m_PG
), next(m_PG
);
758 SetYCoords
setY(m_PG
,m_iops
,m_mmo
,x
,y
);
760 const ShellingOrderSet
&V1
= m_mmo
[1];
763 for (i
= 1; i
<= p
; ++i
) {
764 if (i
< p
) next
[V1
[i
]] = V1
[i
+1];
765 if (i
> 1) prev
[V1
[i
]] = V1
[i
-1];
767 prev
[V1
[1]] = next
[V1
[p
]] = 0;
770 for (k
= 2; k
<= m_mmo
.length(); ++k
)
773 const ShellingOrderSet
&Vk
= m_mmo
[k
];
775 node cl
= m_mmo
.m_left
[k
];
776 node cr
= m_mmo
.m_right
[k
];
780 for(node v
= cl
; v
!= next
[cr
]; v
= next
[v
])
782 ListConstIterator
<InOutPoint
> itFirst
, itLast
;
784 const List
<InOutPoint
> &out
= m_iops
.outpoints(v
);
787 if (!(itFirst
= m_leftOp
[k
]).valid())
788 itFirst
= out
.begin();
789 else if ((*itFirst
).m_adj
->twinNode() != Vk
[1])
792 for(itLast
= itFirst
; itLast
.valid() && (m_iops
.marked((*itLast
).m_adj
) ||
793 (*itLast
).m_adj
->twinNode() == Vk
[1]); ++itLast
) ;
795 } else if (v
== cr
) {
796 itLast
= m_rightOp
[k
];
797 if (itLast
.valid() && (*itLast
).m_adj
->twinNode() == Vk
[p
])
799 itFirst
= (itLast
.valid()) ? itLast
.pred() : out
.rbegin();
801 while(itFirst
.valid() && (m_iops
.marked((*itFirst
).m_adj
) ||
802 (*itFirst
).m_adj
->twinNode() == Vk
[p
]))
804 itFirst
= (itFirst
.valid()) ? itFirst
.succ() : out
.begin();
807 itFirst
= m_nextLeft
[v
];
808 itFirst
= (itFirst
.valid()) ? itFirst
.pred() : out
.rbegin();
810 while (itFirst
.valid() && m_iops
.marked((*itFirst
).m_adj
))
813 itFirst
= (itFirst
.valid()) ? itFirst
.succ() : out
.begin();
815 if (m_nextRight
[v
].valid() && m_nextLeft
[v
] == m_nextRight
[v
]) {
816 for (itLast
= m_nextRight
[v
].succ(); itLast
.valid() && m_iops
.marked((*itLast
).m_adj
);
819 itLast
= m_nextLeft
[v
];
822 if (v
!= cr
&& itFirst
!= itLast
&& m_mmo
.rank(next
[v
]) > m_mmo
.rank(v
)) {
823 int x_n_v
= x
[next
[v
]] - m_iops
.outLeft(next
[v
]);
824 ListConstIterator
<InOutPoint
> it
= (itLast
.valid()) ? itLast
.pred() : out
.rbegin();
826 if(x
[v
]+(*it
).m_dx
>= x_n_v
)
829 if (it
== itFirst
) break;
835 int xl
= x
[prev
[v
]], xr
= x
[v
];
836 int r_p_v
= m_mmo
.rank(prev
[v
]), r_v
= m_mmo
.rank(v
);
839 if (m_iops
.out(prev
[v
]) > 0)
840 xl
+= 1+m_iops
.outRight(prev
[v
]);
845 if (m_iops
.out(v
) > 0)
846 xr
-= 1+m_iops
.outLeft(v
);
848 xr
+= m_dxra
[prev
[v
]];
852 setY
.checkYCoord(xl
, xr
, 1+max(y
[prev
[v
]],y
[v
]), false);
855 for (ListConstIterator
<InOutPoint
> it
= itFirst
; it
!= itLast
; ++it
) {
856 const InOutPoint
&op
= *it
;
858 if (m_iops
.marked(op
.m_adj
))
859 setY
.checkYCoord(x
[v
]+op
.m_dx
, y
[v
]+op
.m_dy
+1, false);
861 setY
.checkYCoord(x
[v
]+op
.m_dx
, y
[v
]+op
.m_dy
,
862 (op
.m_dx
== 0 && op
.m_dy
== 0 && x
[v
] == x
[op
.m_adj
->twinNode()]));
866 for (i
= 1; i
<= p
; i
++) {
867 y
[Vk
[i
]] = setY
.getYmax();
870 // update contour after insertion of z1,...,zp
871 for (i
= 1; i
<= p
; i
++) {
872 if (i
< p
) next
[Vk
[i
]] = Vk
[i
+1];
873 if (i
> 1) prev
[Vk
[i
]] = Vk
[i
-1];
876 next
[prev
[Vk
[1]] = cl
] = Vk
[1];
877 prev
[next
[Vk
[p
]] = cr
] = Vk
[p
];
882 /********************************************************************
885 Assigns polylines to edges of the original graph and computes the
886 x- and y-coordinates of deg-1-nodes not in the ordering.
887 ********************************************************************/
889 void MixedModelBase::setBends ()
891 //printMMOrder(cout);
892 //printInOutPoints(cout);
895 NodeArray
<int> &x
= m_gridLayout
.x(), &y
= m_gridLayout
.y();
896 EdgeArray
<IPolyline
> &bends
= m_gridLayout
.bends();
898 for(int k
= 1; k
<= m_mmo
.length(); ++k
)
900 for (int i
= 1; i
<= m_mmo
[k
].len(); ++i
)
902 node v_s
= m_mmo(k
,i
);
906 node v_t
= adj
->twinNode();
907 edge e
= adj
->theEdge();
908 const InOutPoint
&p_s
= *m_iops
.pointOf(adj
);
909 if (m_iops
.marked(adj
)) {
910 x
[v_t
] = x
[v_s
] + p_s
.m_dx
;
911 y
[v_t
] = y
[v_s
] + p_s
.m_dy
;
913 else if(e
->source() == adj
->theNode())
915 const InOutPoint
&p_t
= *m_iops
.pointOf(adj
->twin());
916 IPoint
p1 (x
[v_s
] + p_s
.m_dx
, y
[v_s
] + p_s
.m_dy
);
917 IPoint
p2 (x
[v_t
] + p_t
.m_dx
, y
[v_t
] + p_t
.m_dy
);
919 bends
[e
].pushBack(p1
);
920 if (m_mmo
.rank(v_s
) < m_mmo
.rank(v_t
)) {
921 bends
[e
].pushBack(IPoint(p1
.m_x
,p2
.m_y
));
923 bends
[e
].pushBack(IPoint(p2
.m_x
,p1
.m_y
));
925 bends
[e
].pushBack(p2
);
933 /********************************************************************
936 Tries to reduce the number of bends by changing the outpoints of
937 nodes with indeg and outdeg 2.
938 ********************************************************************/
940 void MixedModelBase::postprocessing1()
942 NodeArray
<int> &x
= m_gridLayout
.x();
944 for(int k
= 2; k
<= m_mmo
.length(); ++k
) {
945 const ShellingOrderSet
&V
= m_mmo
[k
];
948 if (m_iops
.in(v
) != 2 || m_iops
.out(v
) != 2) continue;
950 const List
<InOutPoint
> &in
= m_iops
.inpoints (v
);
951 List
<InOutPoint
> &out
= m_iops
.outpoints(v
);
952 adjEntry adjL
= (*in
.begin ()).m_adj
;
953 adjEntry adjR
= (*in
.rbegin()).m_adj
;
955 if (!m_iops
.marked(adjL
) && !m_iops
.marked(adjR
) &&
956 x
[adjL
->twinNode()] + m_iops
.pointOf(adjL
->twin())->m_dx
< x
[v
] &&
957 x
[adjR
->twinNode()] + m_iops
.pointOf(adjR
->twin())->m_dx
== x
[v
]+1 &&
958 m_gridLayout
.y(adjR
->twinNode()) < m_gridLayout
.y(v
))
961 m_iops
.setOutDx(out
.begin (),-1);
962 m_iops
.setOutDx(out
.rbegin(), 0);
968 /********************************************************************
971 Tries to reduce the number of bends by moving degree-2 nodes on
973 ********************************************************************/
975 void MixedModelBase::firstPoint(int &x
, int &y
, adjEntry adj
)
977 edge e
= adj
->theEdge();
978 bool sameDirection
= (adj
->theNode() == e
->source());
980 if (m_gridLayout
.bends(e
).empty()) {
981 node t
= (sameDirection
) ? e
->target() : e
->source();
982 x
= m_gridLayout
.x(t
);
983 y
= m_gridLayout
.y(t
);
986 x
= m_gridLayout
.bends(e
).front().m_x
;
987 y
= m_gridLayout
.bends(e
).front().m_y
;
989 x
= m_gridLayout
.bends(e
).back().m_x
;
990 y
= m_gridLayout
.bends(e
).back().m_y
;
995 bool MixedModelBase::isRedundant(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
)
1001 if (dzy1
== 0) return (dyx1
== 0);
1003 int f
= dyx1
* dzy2
;
1005 return (f
% dzy1
== 0 && (y2
- y1
) == f
/ dzy1
);
1008 void MixedModelBase::postprocessing2()
1010 m_gridLayout
.compactAllBends();
1013 forall_nodes(v
,m_PG
)
1015 if(v
->degree() != 2) continue;
1017 adjEntry adj1
= v
->firstAdj();
1018 edge e1
= adj1
->theEdge();
1019 adjEntry adj2
= v
->lastAdj();
1020 edge e2
= adj2
->theEdge();
1022 IPolyline
&bends1
= m_gridLayout
.bends(e1
);
1023 IPolyline
&bends2
= m_gridLayout
.bends(e2
);
1025 if (bends1
.empty() && bends2
.empty()) continue;
1028 firstPoint(x1
,y1
,adj1
);
1029 firstPoint(x3
,y3
,adj2
);
1031 if (isRedundant(x1
,y1
,m_gridLayout
.x(v
),m_gridLayout
.y(v
),x3
,y3
)) {
1032 if (!bends1
.empty()) {
1033 m_gridLayout
.x(v
) = x1
;
1034 m_gridLayout
.y(v
) = y1
;
1035 if(adj1
->theNode() == e1
->source())
1040 m_gridLayout
.x(v
) = x3
;
1041 m_gridLayout
.y(v
) = y3
;
1042 if(adj2
->theNode() == e2
->source())
1052 /********************************************************************
1054 ********************************************************************/
1056 void MixedModelBase::printMMOrder(ostream
&os
)
1060 os
<< "left and right:\n\n";
1061 for (k
= 1; k
<= m_mmo
.length(); ++k
)
1063 const ShellingOrderSet
&V
= m_mmo
[k
];
1066 for (i
= 1; i
<= V
.len(); i
++)
1070 os
<< " cl = " << m_mmo
.m_left
[k
] <<
1071 ", cr = " << m_mmo
.m_right
[k
];
1078 void MixedModelBase::printInOutPoints(ostream
&os
)
1082 os
<< "\n\nin- and outpoint lists:\n";
1083 forall_nodes(v
,m_PG
) {
1084 const List
<InOutPoint
> &in
= m_iops
.inpoints (v
);
1085 const List
<InOutPoint
> &out
= m_iops
.outpoints(v
);
1087 os
<< "\n" << v
<< ":\n";
1088 os
<< " outpoints: ";
1089 ListConstIterator
<InOutPoint
> it
;
1090 for(it
= out
.begin(); it
.valid(); ++it
) {
1094 os
<< "\n inpoints: ";
1095 for(it
= in
.begin(); it
.valid(); ++it
) {
1103 void MixedModelBase::print(ostream
&os
, const InOutPoint
&iop
)
1106 os
<< "[(" << m_PG
.original(iop
.m_adj
->theNode()) << "," <<
1107 m_PG
.original(iop
.m_adj
->twinNode()) << ")," <<
1108 iop
.m_dx
<< "," << iop
.m_dy
<< "]";
1113 void MixedModelBase::printNodeCoords(ostream
&os
)
1117 os
<< "\nx- and y-coordinates:\n\n";
1118 forall_nodes(v
,m_PG
)
1119 os
<< v
<< ": (" << m_gridLayout
.x(v
) << "," << m_gridLayout
.y(v
) << ")\n";
1122 } // end namespace ogdf