1 /** \file
2 * \brief Implements class BiconnectedShellingOrder which computes
3 * a shelling order for a biconnected planar graph.
4 *
5 * \author Carsten Gutwenger
6 *
7 * \par License:
8 * This file is part of the Open Graph Drawing Framework (OGDF).
9 *
10 * \par
11 * Copyright (C)<br>
12 * See README.md in the OGDF root directory for details.
13 *
14 * \par
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * Version 2 or 3 as published by the Free Software Foundation;
18 * see the file LICENSE.txt included in the packaging of this file
19 * for details.
20 *
21 * \par
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * \par
28 * You should have received a copy of the GNU General Public
29 * License along with this program; if not, see
30 * http://www.gnu.org/copyleft/gpl.html
31 */
32
33
34 #include <ogdf/planarlayout/BiconnectedShellingOrder.h>
35 #include <ogdf/basic/CombinatorialEmbedding.h>
36 #include <ogdf/basic/FaceArray.h>
37 #include <ogdf/basic/SList.h>
38
39 #include <ogdf/basic/extended_graph_alg.h>
40 #include <ogdf/basic/simple_graph_alg.h>
41
42
43 //#define OUTPUT_BSO
44
45 namespace ogdf {
46
47 // pair of node v and list itrator it
48 struct PairFaceItem;
49
50 struct PairNodeItem
51 {
52 // constructor
PairNodeItemogdf::PairNodeItem53 PairNodeItem() { }
54
PairNodeItemogdf::PairNodeItem55 explicit PairNodeItem(node v, ListIterator<PairFaceItem> it = ListIterator<PairFaceItem>()) : m_v(v), m_it(it) { }
56
57 node m_v;
58 ListIterator<PairFaceItem> m_it;
59 };
60
61 // pair of face f and list iterator it
62 struct PairFaceItem
63 {
64 // constructor
PairFaceItemogdf::PairFaceItem65 PairFaceItem() : m_f(nullptr), m_it(nullptr) { }
66
PairFaceItemogdf::PairFaceItem67 explicit PairFaceItem(face f) : m_f(f), m_it(nullptr) { }
68
PairFaceItemogdf::PairFaceItem69 PairFaceItem(face f, ListIterator<PairNodeItem> it) : m_f(f), m_it(it) { }
70
71 face m_f;
72 ListIterator<PairNodeItem> m_it;
73 };
74
75
76 // defines (as shortcuts)
77 // initialization of a variable
78 #define INIT_VAR(x,var,val) \
79 var[x] = (val); \
80 setUpdate(x);
81
82 // decrement of a variable
83 #define DEC_VAR(x,var) \
84 --var[x]; \
85 setUpdate(x);
86
87 // increment of a variable
88 #define INC_VAR(x,var) \
89 ++var[x]; \
90 setUpdate(x);
91
92
93 class ComputeBicOrder
94 {
95 public:
96 // types of structures to be removed
97 enum class CandidateType { Face, Node, Edge };
98
99
100 // constructor
101 ComputeBicOrder (
102 const Graph &G, // biconnected planar graph
103 ConstCombinatorialEmbedding &E, // combinatorial embedding of G
104 face extFace, // external face
105 double baseRatio); // size of base (baseRatio * size(extFace)
106
107 // returns external face
externalFace()108 face externalFace() { return m_extFace; }
109
110 // returns face left of adj
left(adjEntry adj)111 face left(adjEntry adj) { return m_pEmbedding->leftFace(adj); }
112
113 // returns face right of adj
right(adjEntry adj)114 face right(adjEntry adj) { return m_pEmbedding->rightFace(adj); }
115
116 // if v = c_i, returns face right of c_i -> c_i+1
right(node v)117 face right(node v) { return left(m_nextSucc[v]); }
118
119 // if v = c_i, returns face left of c_i -> c_i-1
left(node v)120 face left(node v) { return right(m_prevPred[v]); }
121
122 // returns number of virtual edges adjacent to v
123 int virte (node v);
124
125 // returns successor of v on contour (if v=c_i returns c_i+1)
next(node v)126 node next(node v) { return m_next[v]; }
127
128 // returns predecessor of v on contour (if v=c_i returns c_ii1)
prev(node v)129 node prev(node v) { return m_prev[v]; }
130
131 // returns true <=> f contains a virtual edge
cutv(face f)132 bool cutv(face f) { return m_virtSrc[f] != nullptr; }
133
134 // returns true <=> f is a possible next face, i.e
135 // outv(f) >= 3 and outv(f) = oute(f)+1
isPossFace(face f)136 bool isPossFace(face f) {
137 return f != externalFace()
138 && m_outv[f] >= 3
139 && m_outv[f] == m_oute[f] + 1;
140 }
141
142 // returns true <=> v is a possible next node, i.e.
143 // cutf(v) <= 1, cutf(v) = virte(v), numsf(v) = 0 and deg(v) >= 3
isPossNode(node v)144 bool isPossNode(node v) { // precond.: v on C_k'
145 return !m_onBase[v]
146 && m_cutf[v] <= 1
147 && m_cutf[v] == virte(v)
148 && m_numsf[v] == 0
149 && m_deg[v] >= 3;
150 }
151
152 // returns true <=> v=c_i and c_i -> c_i+1 is a possible next virtual edge, i.e.
153 // c_i -> c_i+1 is a virtual edge and (deg(c_i) = 2 and c_i != vLeft) or
154 // deg(c_i+1) = 2 and c_i+1 != vRight)
isPossVirt(node v)155 bool isPossVirt(node v) { // precond.: v on C_k'
156 return m_virtEdge[v] && ((m_deg[v] == 2 && v != m_vLeft) ||
157 (m_deg[next(v)] == 2 && next(v) != m_vRight));
158 }
159
160 // stores the next candidate in m_nextType and m_nextF, m_nextV or
161 // m_nextE (depending on type)
162 // returns true <=> there is a next candidate
163 bool getPossible();
164
165 // returns the type of the next candidate
nextPoss()166 CandidateType nextPoss() { return m_nextType; }
167
168 // puts nodes on base into shelling order set V
169 void setV1(ShellingOrderSet &V);
170
171 // initializes possible nodes and faces
172 void initPossibles();
173
174 // removes next possible face
175 void removeNextFace(ShellingOrderSet &V);
176 // removes next possible node
177 void removeNextNode(ShellingOrderSet &V);
178 // removes next possible virtual edge
179 void removeNextVirt(ShellingOrderSet &V);
180
181 // updates variables of face and nodes contained in m_updateFaces and
182 // m_updateNodes; also updates list of possible nodes, faces and virtual edges
183 void doUpdate();
184
185 // outputs contour and some node and face variables
186 // for debugging only
187 void print();
188
189 private:
190 // if adj = w->v, puts edge (v,w) onto contour
191 void edgeToContour(adjEntry adj);
192 // puts virtual edge (v,w) onto contour and sets m_nextSucc[v] and m_prevPred[w]
193 void virtToContour(node v, node w, adjEntry adjNextSucc, adjEntry adjPrevPred);
194 // puts virtual edge (v,w) onto contour
195 void virtToContour(node v, node w);
196
197 // returns vertex cl of a face to be removed
198 node getFaceCl(face f);
199
200 void setOutv(node v);
201 void setSeqp(node cl, node cr);
202 void delOuterNode(node v);
203 void decSeqp(node v);
204 void putOnOuter(node v, face f);
205 void delOuterRef(face f);
206
207 // returns faces adjacent with v in list L
208 void getAdjFaces(node v, SListPure<face> &L);
209 // returns nodes adjacent with v in list L; nodes are sorted from left
210 // to right
211 void getAdjNodes(node v, SListPure<node> &L);
212
213 // marks face f to be updated
214 void setUpdate(face f);
215 // marks node v to be updated
216 void setUpdate(node v);
217
218 void initVInFStruct(const ConstCombinatorialEmbedding &E);
219 bool vInF(node v, face f);
220 void delVInF(node v, face f);
221
222 int getBaseChain(ConstCombinatorialEmbedding &E,
223 face f,
224 double baseRatio,
225 adjEntry &adjLeft,
226 adjEntry &adjRight);
227
228 adjEntry findMaxBaseChain(ConstCombinatorialEmbedding &E,
229 face f,
230 int &length);
231
232 const Graph *m_pGraph; // the graph
233 ConstCombinatorialEmbedding *m_pEmbedding; // the embedding of the graph
234
235 face m_extFace; // the external face
236
237 adjEntry m_adjLeft; // adjacency entry z_1 -> z_2 (if z_1,...,z_p is base)
238 adjEntry m_adjRight; // adjacency entry z_p-1 -> z_p
239
240 node m_vLeft, m_vRight; // left and right node on base
241 int m_baseLength; // length of base
242
243 // next candidate to be removed
244 CandidateType m_nextType; // type of next candidate
245 face m_nextF; // next face (if m_nextType = typeFace)
246 node m_nextV; // next node (if m_nextType = typeNode)
247 node m_nextE; // next virtual edge (if m_nextType = typeEdge)
248
249 // variables of nodes
250 NodeArray<int> m_deg; // current degree
251 NodeArray<int> m_cutf; // number of adjacent faces f with cutv(f) = true
252 NodeArray<int> m_numsf; // number of adjacent faces f with outv(f) > seqp(f)+1
253 NodeArray<bool> m_onOuter; // true <=> v on contour
254 NodeArray<bool> m_onBase; // true <=> v on base
255
256 // list iterator in m_possNodes containing node (or nil if not contained)
257 NodeArray<ListIterator<node> > m_vLink;
258 // list iterator in m_possVirt containing virtual edge at node (or nil if not contained)
259 NodeArray<ListIterator<node> > m_virtLink;
260 NodeArray<bool> m_vUpdate; // true <=> node marked to be updated
261 NodeArray<ListPure<PairFaceItem> > m_inOutNodes;
262
263 // variables of faces
264 FaceArray<int> m_outv, // number of nodes contained in face on contour
265 m_oute, // number of edges contained in face on contour
266 m_seqp; // number of sequential pairs c_i,c_i+1 of face
267 FaceArray<node> m_virtSrc; // if face contains virtual edge e then source(e), otherwise nil
268 // list iterator in m_possFaces containing face (or nil if not contained)
269 FaceArray<ListIterator<face> > m_fLink;
270 FaceArray<bool> m_fUpdate; // true <=> face marked to be updated
271 FaceArray<bool> m_isSf; // true <=> outv(f) > seqp(f)+1
272 FaceArray<ListPure<PairNodeItem> > m_outerNodes; // list of all nodes of face on contour
273
274 // represantation of the contour
275 NodeArray<node> m_next, m_prev;
276 NodeArray<adjEntry> m_nextSucc, m_prevPred;
277 NodeArray<bool> m_virtEdge; // virt_edge[c_i] = true <=> (c_i,c_i+1) virtuelle Kante
278
279 // lists of possible faces, nodes and edges
280 ListPure<face> m_possFaces; // faces with outv(f) >= 3 und outv(f) = oute(f)+1
281 ListPure<node> m_possNodes; // nodes with cutf(v) <= 1, cutf(v) = virte(v), numsf(v) = 0 and deg(v) >= 3
282 ListPure<node> m_possVirt; // node v denotes virtual edge e = (v,next[v]), that satisfies (deg(v) = 2 and v != vLeft) or (deg(next(v)) = 2 and next(v) != vRight)
283
284 ListPure <node> m_updateNodes; // list of nodes to be updated
285 SListPure<face> m_updateFaces; // list of faces to be updated
286
287 // deciding "v in F ?" in constant time
288 NodeArray<List<PairFaceItem> > m_facesOf;
289 FaceArray<List<PairNodeItem> > m_nodesOf;
290 };
291
292
print()293 void ComputeBicOrder::print()
294 {
295 std::cout << "contour:\n";
296 for(node v = m_vLeft; v != nullptr; v = m_next[v])
297 std::cout << " " << v << "[" << m_prev[v] << "," << m_prevPred[v] <<
298 " : " << m_next[v] << "," << m_nextSucc[v] <<
299 "; " << m_virtEdge[v] << "]\n";
300
301 std::cout << "node infos:\n";
302 for(node v : m_pGraph->nodes)
303 std::cout << v << ": deg = " << m_deg[v] << ", cutf = " << m_cutf[v] <<
304 ", numsf = " << m_numsf[v] << std::endl;
305
306 std::cout << "face infos:\n";
307 for(face f : m_pEmbedding->faces) {
308 std::cout << f->index() << ": outv = " << m_outv[f] << ", oute = " <<
309 m_oute[f] << ", seqp = " << m_seqp[f] << ", isSF = " <<
310 m_isSf[f] << ", virtSrc = " << m_virtSrc[f] << std::endl;
311 }
312 std::cout << std::endl;
313 }
314
315
ComputeBicOrder(const Graph & G,ConstCombinatorialEmbedding & E,face extFace,double baseRatio)316 ComputeBicOrder::ComputeBicOrder(const Graph &G, // the graph
317 ConstCombinatorialEmbedding &E, // embedding of the graph
318 face extFace, // the external face
319 double baseRatio) // length of the base = baseRatio*size(extface)
320 {
321 m_pGraph = &G;
322 m_pEmbedding = &E;
323
324 #ifdef OUTPUT_BSO
325 std::cout << "faces:" << std::endl;
326 for(face fh : E.faces) {
327 std::cout << fh->index() << ":";
328 for(adjEntry adj : fh->entries)
329 std::cout << " " << adj;
330 std::cout << std::endl;
331 }
332
333 std::cout << "adjacency lists:" << std::endl;
334 for(node vh : G.nodes) {
335 std::cout << vh << ":";
336 for(adjEntry adj : vh->adjEntries)
337 std::cout << " " << adj;
338 std::cout << std::endl;
339 }
340 #endif
341
342 m_vLink .init(G, ListIterator<node>());
343 m_virtLink.init(G, ListIterator<node>());
344
345 m_extFace = extFace;
346
347 #ifdef OUTPUT_BSO
348 std::cout << "external face = " << extFace->index() << std::endl;
349 #endif
350
351 m_baseLength = getBaseChain(E, m_extFace, baseRatio, m_adjLeft, m_adjRight);
352 m_vLeft = m_adjLeft->theNode();
353 m_vRight = m_adjRight->twinNode();
354
355 #ifdef OUTPUT_BSO
356 std::cout << "vLeft = " << m_vLeft << ", " << "vRight = " << m_vRight << std::endl;
357 #endif
358
359 // initialization of node and face variables
360 m_deg .init (G);
361 m_cutf .init (G, 0);
362 m_numsf .init (G, 0);
363 m_onOuter .init (G, false);
364 m_next .init (G);
365 m_prev .init (G);
366 m_nextSucc .init (G);
367 m_prevPred .init (G);
368 m_virtEdge .init (G, false);
369 m_vUpdate .init (G, false);
370 m_inOutNodes .init (G);
371 m_outv .init (E, 0);
372 m_oute .init (E, 0);
373 m_seqp .init (E, 0);
374 m_virtSrc .init (E, nullptr);
375 m_fLink .init (E, ListIterator<face>());
376 m_fUpdate .init (E, false);
377 m_isSf .init (E, false);
378 m_outerNodes .init (E);
379 m_onBase .init (G, false);
380
381 initVInFStruct(E);
382
383 // initialization of degree
384 for(node v : G.nodes)
385 m_deg[v] = v->degree();
386
387 // initialization of m_onBase[v]
388 adjEntry adj;
389 for(adj = m_adjRight; adj != m_adjLeft; adj = adj->faceCyclePred())
390 m_onBase[adj->theNode()] = true;
391 m_onBase [m_vLeft] = m_onBase [m_vRight] = true;
392
393 adj = m_adjLeft;
394 do {
395 node v = adj->theNode();
396 for(adjEntry adj2 : v->adjEntries)
397 {
398 face f = E.rightFace(adj2);
399 if (f != m_extFace) {
400 m_outv[f] ++;
401 putOnOuter(v,f);
402 }
403 }
404 adj = adj->faceCyclePred();
405 } while(adj != m_adjRight);
406
407 for(adj = m_adjRight->faceCycleSucc(); adj != m_adjLeft; adj = adj->faceCycleSucc())
408 m_oute[E.leftFace(adj)]++;
409
410 m_onOuter [m_vLeft] = true;
411 m_prevPred[m_vLeft] = m_nextSucc[m_vRight] = nullptr;
412 m_prev[m_vLeft] = m_next[m_vRight] = nullptr;
413 for (adj = m_adjLeft->faceCyclePred(); adj != m_adjRight; adj = adj->faceCyclePred())
414 {
415 node v = adj->twinNode();
416 node w = adj->theNode();
417 m_onOuter[w] = true;
418 edgeToContour(adj);
419
420 for(adjEntry adj2 : w->adjEntries)
421 {
422 face f = left(adj2);
423 if (vInF(v,f))
424 ++m_seqp[f];
425 }
426 }
427
428 for (node v = m_vLeft; v != nullptr; v = next(v))
429 {
430 for(adjEntry adjV : v->adjEntries) {
431 face f = left(adjV);
432 if ((m_isSf[f] = (m_outv[f] > m_seqp[f]+1)))
433 ++m_numsf[v];
434 }
435 }
436 }
437
438
setV1(ShellingOrderSet & V)439 void ComputeBicOrder::setV1(ShellingOrderSet &V)
440 {
441 V = ShellingOrderSet(m_baseLength, nullptr, nullptr);
442
443 int i;
444 adjEntry adj;
445 for (i = 1, adj = m_adjLeft; i <= m_baseLength;
446 i++, adj = adj->faceCycleSucc())
447 {
448 V[i] = adj->theNode();
449 }
450 }
451
452
edgeToContour(adjEntry adj)453 void ComputeBicOrder::edgeToContour(adjEntry adj)
454 {
455 node v = adj->twinNode(), w = adj->theNode();
456
457 m_next [v] = w;
458 m_prev [w] = v;
459 m_nextSucc [v] = adj->twin()->cyclicSucc();
460 m_prevPred [w] = adj->cyclicPred();
461 m_virtEdge [v] = false;
462 }
463
464
virtToContour(node v,node w,adjEntry adjNextSucc,adjEntry adjPrevPred)465 void ComputeBicOrder::virtToContour(
466 node v,
467 node w,
468 adjEntry adjNextSucc,
469 adjEntry adjPrevPred)
470 {
471 m_next [v] = w;
472 m_prev [w] = v;
473 m_nextSucc [v] = adjNextSucc;
474 m_prevPred [w] = adjPrevPred;
475 m_virtEdge [v] = true;
476 }
477
478
virtToContour(node v,node w)479 void ComputeBicOrder::virtToContour(node v, node w)
480 {
481 m_next [v] = w;
482 m_prev [w] = v;
483 m_virtEdge [v] = true;
484 }
485
486
putOnOuter(node v,face f)487 void ComputeBicOrder::putOnOuter(node v, face f)
488 {
489 ListIterator<PairNodeItem> it;
490
491 it = m_outerNodes[f].pushBack(PairNodeItem(v));
492 (*it).m_it = m_inOutNodes[v].pushBack(PairFaceItem(f,it));
493 }
494
495
delOuterRef(face f)496 void ComputeBicOrder::delOuterRef(face f)
497 {
498 ListPure<PairNodeItem> &L = m_outerNodes[f];
499 PairNodeItem x;
500
501 while (!L.empty()) {
502 x = L.popFrontRet();
503 m_inOutNodes[x.m_v].del(x.m_it);
504 }
505 }
506
507
virte(node v)508 int ComputeBicOrder::virte(node v)
509 {
510 int num = 0;
511
512 if (m_onOuter[v])
513 {
514 if (m_virtEdge[v])
515 num++;
516 if (v != m_vLeft && m_virtEdge[prev(v)])
517 num++;
518 }
519 return num;
520 }
521
522
initVInFStruct(const ConstCombinatorialEmbedding & E)523 void ComputeBicOrder::initVInFStruct(const ConstCombinatorialEmbedding &E)
524 {
525 const Graph &G = E;
526
527 m_facesOf.init(G);
528 m_nodesOf.init(E);
529
530 for (face f : E.faces)
531 {
532 for (adjEntry adj : f->entries) {
533 node v = adj->theNode();
534
535 ListIterator<PairFaceItem> it = m_facesOf[v].pushBack(PairFaceItem(f));
536 (*it).m_it = m_nodesOf[f].pushBack(PairNodeItem(v, it));
537 }
538 }
539
540 SListPure<node> smallV;
541 for (node v : G.nodes) {
542 if (m_facesOf[v].size() <= 5)
543 smallV.pushBack(v);
544 }
545
546 SListPure<face> smallF;
547 for (face f : E.faces) {
548 if (m_nodesOf[f].size() <= 5)
549 smallF.pushBack(f);
550 }
551
552 for (;;)
553 {
554 if (!smallV.empty()) {
555 node v = smallV.popFrontRet();
556
557 for (const PairFaceItem &f_it : m_facesOf[v]) {
558 m_nodesOf[f_it.m_f].del(f_it.m_it);
559 if (m_nodesOf[f_it.m_f].size() == 5)
560 smallF.pushBack(f_it.m_f);
561 }
562 }
563 else if (!smallF.empty()) {
564 face f = smallF.popFrontRet();
565 for (const PairNodeItem &v_it : m_nodesOf[f]) {
566 m_facesOf[v_it.m_v].del(v_it.m_it);
567 if (m_facesOf[v_it.m_v].size() == 5)
568 smallV.pushBack(v_it.m_v);
569 }
570 }
571 else
572 break;
573 }
574 }
575
576
vInF(node v,face f)577 bool ComputeBicOrder::vInF(node v, face f)
578 {
579 for(const PairNodeItem &ni : m_nodesOf[f])
580 if (ni.m_v == v) return true;
581
582 for(const PairFaceItem &fi : m_facesOf[v])
583 if (fi.m_f == f) return true;
584
585 return false;
586 }
587
588
delVInF(node v,face f)589 void ComputeBicOrder::delVInF(node v, face f)
590 {
591 List<PairNodeItem> &L_f = m_nodesOf[f];
592 List<PairFaceItem> &L_v = m_facesOf[v];
593
594 ListIterator<PairNodeItem> itNI;
595 for(itNI = L_f.begin(); itNI.valid(); ++itNI) {
596 if ((*itNI).m_v == v) {
597 L_f.del(itNI);
598 return;
599 }
600 }
601
602 ListIterator<PairFaceItem> itFI;
603 for(itFI = L_v.begin(); itFI.valid(); ++itFI) {
604 if ((*itFI).m_f == f) {
605 L_v.del(itFI);
606 return;
607 }
608 }
609 }
610
611
initPossibles()612 void ComputeBicOrder::initPossibles()
613 {
614 for(face f : m_pEmbedding->faces) {
615 if (isPossFace(f))
616 m_fLink[f] = m_possFaces.pushBack(f);
617 }
618
619 for (node v = next(m_vLeft); v != m_vRight; v = next(v))
620 if (isPossNode(v))
621 m_vLink[v] = m_possNodes.pushBack(v);
622 }
623
624
getPossible()625 bool ComputeBicOrder::getPossible()
626 {
627 if (!m_possFaces.empty()) {
628 m_nextType = CandidateType::Face;
629 m_nextF = m_possFaces.popFrontRet();
630 m_fLink[m_nextF] = ListIterator<face>();
631 return true;
632
633 } else if (!m_possNodes.empty()) {
634 m_nextType = CandidateType::Node;
635 m_nextV = m_possNodes.popFrontRet();
636 m_vLink[m_nextV] = ListIterator<node>();
637 return true;
638
639 } else if (!m_possVirt.empty()) {
640 m_nextType = CandidateType::Edge;
641 m_nextE = m_possVirt.popFrontRet();
642 m_virtLink[m_nextE] = ListIterator<node>();
643 return true;
644
645 } else
646 return false;
647 }
648
649
getFaceCl(face f)650 node ComputeBicOrder::getFaceCl(face f)
651 {
652 node v = nullptr;
653
654 if (cutv(f)) {
655 v = m_virtSrc [f];
656
657 } else {
658 for(adjEntry adj : f->entries) {
659 if (m_onOuter[v = adj->theNode()] && m_deg[v] == 2)
660 break;
661 }
662 }
663
664 while (v != m_vLeft && m_deg[v] == 2)
665 v = prev(v);
666
667 return v;
668 }
669
670
getAdjFaces(node v,SListPure<face> & L)671 void ComputeBicOrder::getAdjFaces(node v, SListPure<face> &L)
672 {
673 L.clear();
674 if (m_deg[v] <= 1) return;
675
676 adjEntry adjEnd = (v != m_vLeft) ? m_prevPred[v] : m_adjLeft->cyclicPred();
677 adjEntry adjStart = (v != m_vRight) ? m_nextSucc[v] : m_adjRight->twin()->cyclicSucc();
678
679 if (left(adjStart) != m_extFace)
680 L.pushBack(left(adjStart));
681
682 if (m_deg[v] >= 3) {
683 adjEntry adj;
684 for (adj = adjStart; adj != adjEnd; adj = adj->cyclicSucc())
685 L.pushBack(right(adj));
686
687 L.pushBack(right(adjEnd));
688 }
689 }
690
691
getAdjNodes(node v,SListPure<node> & L)692 void ComputeBicOrder::getAdjNodes(node v, SListPure<node> &L)
693 {
694 adjEntry adjEnd = (v != m_vLeft) ? m_prevPred[v] : m_adjLeft->cyclicPred();
695 adjEntry adjStart = (v != m_vRight) ? m_nextSucc[v] : m_adjRight->twin()->cyclicSucc();
696
697 L.clear();
698 L.pushBack((v != m_vLeft) ? prev(v) : m_adjLeft->twinNode());
699
700 if (m_deg[v] >= 3) {
701 adjEntry adj;
702 for (adj = adjEnd; adj != adjStart; adj = adj->cyclicPred())
703 L.pushBack(adj->twinNode());
704 L.pushBack(adjStart->twinNode());
705 }
706 L.pushBack((v != m_vRight) ? next(v) : m_adjRight->theNode());
707 }
708
709
decSeqp(node v)710 void ComputeBicOrder::decSeqp(node v)
711 {
712 node vNext = next(v);
713 node vPrev = prev(v);
714
715 SListPure<face> L;
716 getAdjFaces(v, L);
717
718 for (face f : L) {
719 if (vInF(vNext, f))
720 m_seqp[f]--;
721 if (vInF(vPrev, f))
722 m_seqp[f]--;
723 }
724 }
725
726
delOuterNode(node v)727 void ComputeBicOrder::delOuterNode(node v)
728 {
729 for(const PairFaceItem &fi : m_inOutNodes[v])
730 m_outerNodes[fi.m_f].del(fi.m_it);
731 }
732
733
setOutv(node v)734 void ComputeBicOrder::setOutv(node v)
735 {
736 SListPure<face> L;
737 getAdjFaces(v, L);
738
739 for (face f : L) {
740 INC_VAR(f, m_outv)
741 putOnOuter(v, f);
742 if (cutv(f)) {
743 INC_VAR(v, m_cutf)
744 }
745 if (m_isSf[f]) {
746 INC_VAR(v, m_numsf)
747 }
748 }
749 }
750
751
setSeqp(node cl,node cr)752 void ComputeBicOrder::setSeqp(node cl, node cr)
753 {
754 SListPure<face> L;
755
756 node w;
757 for (node v = cl; v != cr; v = w)
758 {
759 w = next(v);
760
761 node wSmall, wBig;
762 if (m_deg[v] < m_deg[w]) {
763 wSmall = v;
764 wBig = w;
765 } else {
766 wSmall = w;
767 wBig = v;
768 }
769
770 getAdjFaces(wSmall, L);
771
772 for(face f : L) {
773 if (vInF(wBig,f)) {
774 INC_VAR (f,m_seqp)
775 }
776 }
777 }
778 }
779
780
removeNextFace(ShellingOrderSet & V)781 void ComputeBicOrder::removeNextFace(ShellingOrderSet &V)
782 {
783 #ifdef OUTPUT_BSO
784 std::cout << "remove next face: " << m_nextF->index() << std::endl;
785 #endif
786
787 node cl = getFaceCl(m_nextF), cr, v;
788
789 V = ShellingOrderSet(m_outv[m_nextF]-2);
790 V.left(cl);
791
792 int i;
793 for (i = 1, cr = next(cl); cr != m_vRight && m_deg[cr] == 2; i++, cr = next(cr))
794 V [i] = cr ;
795 V.right (cr);
796 V.leftAdj (m_virtEdge[cl] ? nullptr : m_nextSucc[cl]->cyclicSucc()->twin());
797 V.rightAdj(m_virtEdge[prev(cr)] ? nullptr : m_prevPred[cr]->cyclicPred()->twin());
798
799 if (cutv(m_nextF) && next(m_virtSrc[m_nextF]) == cr)
800 setUpdate(cr);
801
802 if (cutv(m_nextF)) {
803 DEC_VAR(cl,m_cutf)
804 DEC_VAR(cr,m_cutf)
805 v = m_virtSrc[m_nextF];
806 if (v != cr) {
807 m_possVirt.del(m_virtLink[v]);
808 m_virtLink[v] = ListIterator<node>();
809 }
810 }
811
812 adjEntry adj = m_nextSucc[cl]->twin();
813 for( ; ; ) {
814 edgeToContour(adj);
815
816 if (adj->theNode() == cr)
817 break;
818 else {
819 INIT_VAR(adj->theNode(),m_onOuter,true)
820 }
821
822 adj = adj->faceCyclePred();
823 }
824 DEC_VAR (cl,m_deg)
825 DEC_VAR (cr,m_deg)
826
827 for (v = cl; v != cr; v = next(v)) {
828 INC_VAR(right(v),m_oute)
829 if (v != cl)
830 setOutv(v);
831 }
832
833 setSeqp(cl, cr);
834
835 // possibly remove virtual edge
836 if (cutv(m_nextF)) {
837 if (m_virtSrc[m_nextF] == cl) {
838 setUpdate(cl);
839 m_virtEdge[cl] = false;
840 }
841 m_virtSrc[m_nextF] = nullptr;
842 }
843 delOuterRef(m_nextF);
844 }
845
846
removeNextNode(ShellingOrderSet & V)847 void ComputeBicOrder::removeNextNode(ShellingOrderSet &V)
848 {
849 #ifdef OUTPUT_BSO
850 std::cout << "remove next node: " << m_nextV << std::endl;
851 #endif
852
853 node cl = prev(m_nextV);
854 node cr = next(m_nextV);
855
856 V = ShellingOrderSet(1);
857 V[1] = m_nextV;
858
859 if (m_virtEdge[prev(m_nextV)]) {
860 V.left(m_prevPred[m_nextV]->twinNode());
861 V.leftAdj(m_prevPred[m_nextV]);
862 } else {
863 V.left(prev(m_nextV));
864 V.leftAdj(m_prevPred[m_nextV]->cyclicPred());
865 }
866
867 if (m_virtEdge[m_nextV]) {
868 V.right(m_nextSucc[m_nextV]->twinNode());
869 V.rightAdj(m_nextSucc[m_nextV]);
870 } else {
871 V.right(next(m_nextV));
872 V.rightAdj(m_nextSucc[m_nextV]->cyclicSucc());
873 }
874
875 node vVirt = nullptr;
876 face fVirt = nullptr;
877 if (m_virtEdge[prev(m_nextV)]) {
878 INIT_VAR(prev(m_nextV), m_virtEdge, false)
879 vVirt = cl;
880 fVirt = left(m_nextV);
881 m_virtSrc [fVirt] = nullptr;
882 }
883
884 if (m_virtEdge[m_nextV]) {
885 if (m_virtLink[m_nextV].valid()) {
886 m_possVirt.del(m_virtLink[m_nextV]);
887 m_virtLink[m_nextV] = ListIterator<node>();
888 }
889 vVirt = cr;
890 fVirt = right(m_nextV);
891 m_virtSrc[fVirt] = nullptr;
892 }
893
894 SListPure<face> L;
895 getAdjFaces(m_nextV, L);
896 for(face f : L)
897 --m_outv[f];
898
899 SListPure<node> L_v;
900 getAdjNodes(m_nextV, L_v);
901
902 delOuterNode(m_nextV);
903 --m_oute[left (m_nextV)];
904 --m_oute[right(m_nextV)];
905 decSeqp(m_nextV);
906
907 for(node w : L_v) {
908 m_onOuter[w] = true;
909 DEC_VAR (w, m_deg)
910 }
911
912 face potF = nullptr;
913 node w1 = L_v.popFrontRet();
914 bool firstTime = true;
915 adjEntry adj,adj2;
916 for(node w : L_v)
917 {
918 if (firstTime) {
919 adj2 = m_nextSucc[prev(m_nextV)];
920 adj = m_prevPred[m_nextV];
921 firstTime = false;
922
923 if (prev(m_nextV) != m_vLeft) {
924 face f = left(adj2);
925 if (vInF(prev(prev(m_nextV)),f))
926 potF = f;
927 }
928
929 } else {
930 adj2 = adj->twin()->faceCyclePred()->twin();
931 adj = adj->cyclicPred();
932 }
933
934 for( ; ; )
935 {
936 node v = adj2->twinNode();
937
938 if (v != w && m_onOuter[v])
939 {
940 face f = left(adj2);
941
942 // possibly remove "v in F" relation
943 if (adj2->theNode() != w1)
944 {
945 adjEntry adj1 = adj2->twin()->faceCycleSucc();
946 do {
947 delVInF(adj1->twinNode(),f);
948 adj1 = adj1->faceCycleSucc();
949 } while (adj1->theNode() != w1);
950 }
951 if (f == potF && adj2->theNode() != prev(m_nextV)) {
952 DEC_VAR(f,m_seqp)
953 }
954
955 // insert new virtual edge
956 virtToContour(adj2->theNode(), w, adj2, (w == next(m_nextV)) ?
957 m_prevPred[w] : adj->twin()->cyclicPred());
958
959 setUpdate(f);
960
961 INC_VAR(adj2->theNode(),m_deg)
962 INC_VAR(w,m_deg)
963
964 if (f != fVirt) {
965 for(const PairNodeItem &ni : m_outerNodes[f]) {
966 INC_VAR(ni.m_v, m_cutf);
967 }
968 }
969 m_virtSrc[f] = adj2->theNode();
970
971 break;
972 }
973
974 edgeToContour(adj2->twin());
975
976 if (v == w) {
977 delOuterRef(left(adj2));
978 break;
979 }
980 INIT_VAR(v,m_onOuter,true)
981 if (adj2->theNode() == cl)
982 {
983 ListIterator<PairNodeItem> it, itSucc;
984 ListPure<PairNodeItem> &listPNI = m_outerNodes[left(adj2)];
985 for(it = listPNI.begin(); it.valid(); it = itSucc) {
986 itSucc = it.succ();
987 if ((*it).m_v == cl) {
988 m_inOutNodes[cl].del((*it).m_it);
989 listPNI.del(it);
990 break;
991 }
992 }
993 m_outv[left(adj2)]--;
994 }
995 adj2 = adj2->twin()->faceCyclePred()->twin();
996 }
997 w1 = w;
998 }
999
1000 for (node v = cl; v != cr; v = next(v)) {
1001 INC_VAR(right(v),m_oute)
1002 if (v != cl)
1003 setOutv(v);
1004 }
1005
1006 setSeqp(cl,cr);
1007
1008 if ((vVirt != nullptr && m_virtSrc[fVirt] == nullptr) ||
1009 (vVirt == cl && m_virtSrc[fVirt] != cl)) {
1010 DEC_VAR(vVirt,m_cutf)
1011 }
1012 }
1013
1014
removeNextVirt(ShellingOrderSet & V)1015 void ComputeBicOrder::removeNextVirt(ShellingOrderSet &V)
1016 {
1017 #ifdef OUTPUT_BSO
1018 std::cout << "remove next virt: " << m_nextE << std::endl;
1019 #endif
1020
1021 node v, cl = m_nextE, cr = next(m_nextE);
1022 int i = 0;
1023
1024 while (m_deg[cl] == 2 && cl != m_vLeft)
1025 { cl = prev(cl); i++; }
1026 while (m_deg[cr] == 2 && cr != m_vRight)
1027 { cr = next(cr); i++; }
1028
1029 V = ShellingOrderSet(i,m_virtEdge[cl] ? nullptr : m_prevPred[next(cl)],
1030 m_virtEdge[prev(cr)] ? nullptr : m_nextSucc[prev(cr)]);
1031 for (i = 1, v = next(cl); v != cr; v = next(v)) {
1032 V[i++] = v;
1033 delOuterNode(v);
1034 }
1035 V.left (cl);
1036 V.right(cr);
1037
1038 face f = right(cl);
1039 m_virtSrc[f] = cl;
1040
1041 virtToContour(cl, cr);
1042
1043 INIT_VAR(f,m_outv,(m_outv[f] - V.len()))
1044 INIT_VAR(f,m_oute,(m_oute[f] - V.len()))
1045 INIT_VAR(f,m_seqp,(m_seqp[f] - V.len()-1))
1046 setSeqp(cl,cr);
1047 setUpdate(cl);
1048 setUpdate(cr);
1049 }
1050
1051
setUpdate(node v)1052 void ComputeBicOrder::setUpdate(node v)
1053 {
1054 if (!m_vUpdate[v]) {
1055 m_updateNodes.pushBack(v);
1056 m_vUpdate[v] = true;
1057 }
1058 }
1059
1060
setUpdate(face f)1061 void ComputeBicOrder::setUpdate(face f)
1062 {
1063 if (!m_fUpdate[f]) {
1064 m_updateFaces.pushBack(f);
1065 m_fUpdate[f] = true;
1066 }
1067 }
1068
1069
doUpdate()1070 void ComputeBicOrder::doUpdate()
1071 {
1072 while (!m_updateFaces.empty())
1073 {
1074 face f = m_updateFaces.popFrontRet();
1075 m_fUpdate[f] = false;
1076 bool isSeperatingFace = (m_outv[f] > m_seqp[f]+1);
1077 if (isSeperatingFace != m_isSf[f])
1078 {
1079 for(const PairNodeItem &ni : m_outerNodes[f])
1080 {
1081 if (isSeperatingFace) {
1082 INC_VAR(ni.m_v,m_numsf)
1083 } else {
1084 DEC_VAR(ni.m_v,m_numsf)
1085 }
1086 }
1087 m_isSf[f] = isSeperatingFace;
1088 }
1089 bool possible = isPossFace(f);
1090 if (possible && !m_fLink[f].valid())
1091 m_fLink[f] = m_possFaces.pushBack(f);
1092 else if (!possible && m_fLink[f].valid()) {
1093 m_possFaces.del(m_fLink[f]);
1094 m_fLink[f] = ListIterator<face>();
1095 }
1096 }
1097
1098 for (node v : reverse(m_updateNodes)) {
1099 if (v != m_vLeft && m_virtEdge[prev(v)])
1100 setUpdate(prev(v));
1101 }
1102
1103 while (!m_updateNodes.empty())
1104 {
1105 node v = m_updateNodes.popFrontRet();
1106 m_vUpdate[v] = false;
1107
1108 bool possible = isPossNode(v);
1109 if (possible && !m_vLink[v].valid())
1110 m_vLink[v] = m_possNodes.pushBack(v);
1111 else if (!possible && m_vLink[v].valid()) {
1112 m_possNodes.del(m_vLink[v]);
1113 m_vLink[v] = ListIterator<node>();
1114 }
1115 possible = isPossVirt(v);
1116 if (possible && !m_virtLink[v].valid())
1117 m_virtLink[v] = m_possVirt.pushBack(v);
1118 else if (!possible && m_virtLink[v].valid()) {
1119 m_possVirt.del(m_virtLink[v]);
1120 m_virtLink[v] = ListIterator<node>();
1121 }
1122 }
1123 }
1124
1125
getBaseChain(ConstCombinatorialEmbedding & E,face f,double baseRatio,adjEntry & adjLeft,adjEntry & adjRight)1126 int ComputeBicOrder::getBaseChain(ConstCombinatorialEmbedding &E,
1127 face f,
1128 double baseRatio,
1129 adjEntry &adjLeft,
1130 adjEntry &adjRight)
1131 {
1132 int len;
1133 adjLeft = findMaxBaseChain(E, f, len);
1134 len = max(2, min(len, (int)(baseRatio*f->size()+0.5)));
1135
1136 adjRight = adjLeft;
1137 for (int i = 2; i < len; i++)
1138 adjRight = adjRight->faceCycleSucc();
1139
1140 return len;
1141 }
1142
1143
1144 struct QType
1145 {
QTypeogdf::QType1146 QType (adjEntry adj, int i) {
1147 m_start = adj;
1148 m_limit = i;
1149 }
QTypeogdf::QType1150 QType () {
1151 m_start = nullptr;
1152 m_limit = 0;
1153 }
1154
1155 adjEntry m_start;
1156 int m_limit;
1157 };
1158
1159
findMaxBaseChain(ConstCombinatorialEmbedding & E,face f,int & length)1160 adjEntry ComputeBicOrder::findMaxBaseChain(ConstCombinatorialEmbedding &E,
1161 face f,
1162 int &length)
1163 {
1164 const Graph &G = (const Graph &) E;
1165 int p = f->size();
1166
1167 NodeArray<int> num(G, -1);
1168
1169 int i = 0;
1170
1171 for (adjEntry adj : f->entries)
1172 num[adj->theNode()] = i++;
1173
1174 Array<SListPure<int> > diag(0, p - 1);
1175 for (adjEntry adj : f->entries)
1176 {
1177 i = num[adj->theNode()];
1178 adjEntry adj2;
1179 for (adj2 = adj->cyclicPred(); adj2 != adj->cyclicSucc();
1180 adj2 = adj2->cyclicPred())
1181 {
1182 int j = num[adj2->twinNode()];
1183 if (j != -1)
1184 diag[i].pushBack(j);
1185 }
1186 }
1187
1188 SListPure<QType> Q;
1189 Array<SListIterator<QType> > posInQ(0, p - 1, SListIterator<QType>());
1190
1191 length = 0;
1192 bool firstRun = true;
1193 adjEntry adj = f->firstAdj();
1194 i = num[adj->theNode()];
1195
1196 adjEntry adjStart = nullptr;
1197 do {
1198 if (posInQ[i].valid()) {
1199 adjEntry adj2 = Q.front().m_start;
1200 int d = (i - num[adj2->theNode()] + p) % p + 1;
1201 if (d > length || (d == length && adj2->theNode()->index() < adjStart->theNode()->index())) {
1202 length = d;
1203 adjStart = adj2;
1204 }
1205 SListIterator<QType> it, itLimit = posInQ[i];
1206 do {
1207 it = Q.begin();
1208 posInQ[(*it).m_limit] = SListIterator<QType>();
1209 Q.popFront();
1210 } while (it != itLimit);
1211 }
1212
1213 int j = -1;
1214 if (diag[i].empty())
1215 j = (i - 2 + p) % p;
1216 else {
1217 int m = p;
1218 for (int k : diag[i]) {
1219 int d = (k - i + p) % p;
1220 if (d < m) {
1221 m = d;
1222 j = k;
1223 }
1224 }
1225 OGDF_ASSERT(j != -1);
1226 j = (j - 1 + p) % p;
1227 if (!firstRun) {
1228 posInQ[Q.back().m_limit] = nullptr;
1229 Q.back().m_limit = j;
1230 posInQ[j] = Q.backIterator();
1231 }
1232 }
1233
1234 if (firstRun)
1235 posInQ[j] = Q.pushBack(QType(adj, j));
1236
1237 adj = adj->faceCycleSucc();
1238 i = num[adj->theNode()];
1239 if (i == 0) firstRun = false;
1240 } while (!Q.empty());
1241
1242 return adjStart;
1243 }
1244
1245
doCall(const Graph & G,adjEntry adj,List<ShellingOrderSet> & partition)1246 void BiconnectedShellingOrder::doCall(const Graph &G,
1247 adjEntry adj,
1248 List<ShellingOrderSet> &partition)
1249 {
1250 OGDF_ASSERT(isBiconnected(G));
1251 OGDF_ASSERT(G.representsCombEmbedding());
1252
1253 ConstCombinatorialEmbedding E(G);
1254
1255 face extFace = (adj != nullptr) ? E.rightFace(adj) : E.maximalFace();
1256 ComputeBicOrder cpo(G,E,extFace,m_baseRatio);
1257
1258 cpo.initPossibles();
1259
1260 #ifdef OUTPUT_BSO
1261 std::cout << "after initialization:\n";
1262 cpo.print();
1263 #endif
1264
1265 while(cpo.getPossible())
1266 {
1267 switch(cpo.nextPoss())
1268 {
1269 case ComputeBicOrder::CandidateType::Face:
1270 partition.pushFront(ShellingOrderSet());
1271 cpo.removeNextFace(partition.front());
1272 break;
1273
1274 case ComputeBicOrder::CandidateType::Node:
1275 partition.pushFront(ShellingOrderSet());
1276 cpo.removeNextNode(partition.front());
1277 break;
1278
1279 case ComputeBicOrder::CandidateType::Edge:
1280 partition.pushFront(ShellingOrderSet());
1281 cpo.removeNextVirt(partition.front());
1282 break;
1283 }
1284
1285 cpo.doUpdate();
1286
1287 #ifdef OUTPUT_BSO
1288 std::cout << "after update:\n";
1289 cpo.print();
1290 #endif
1291 }
1292
1293 partition.pushFront(ShellingOrderSet(2));
1294 cpo.setV1(partition.front());
1295 }
1296
1297 }
1298