1 /** \file
2 * \brief Computes the Orthogonal Representation of a Planar
3 * Representation of a UML Graph.
4 *
5 * \author Karsten Klein
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/cluster/ClusterOrthoShaper.h>
35 #include <ogdf/graphalg/MinCostFlowReinelt.h>
36
37 namespace ogdf {
38
39 enum class NetArcType {defaultArc, angle, backAngle, bend};
40
41 //call function: compute a flow in a dual network and interpret
42 //result as bends and angles (representation shape)
call(ClusterPlanRep & PG,CombinatorialEmbedding & E,OrthoRep & OR,int startBoundBendsPerEdge,bool fourPlanar)43 void ClusterOrthoShaper::call(ClusterPlanRep &PG,
44 CombinatorialEmbedding &E,
45 OrthoRep &OR,
46 int startBoundBendsPerEdge,
47 bool fourPlanar)
48 {
49
50 if (PG.numberOfEdges() == 0)
51 return;
52
53 m_fourPlanar = fourPlanar;
54
55 // the min cost flow we use
56 MinCostFlowReinelt<int> flowModule;
57 const int infinity = flowModule.infinity();
58
59 //fix some values depending on traditional or progressive mode
60
61 //standard flow boundaries for traditional and progressive mode
62 const int upperAngleFlow = (m_traditional ? 4 : 1); //non zero
63 const int maxAngleFlow = (m_traditional ? 4 : 2); //use 2 for multialign zero degree
64 const int maxBackFlow = 2; //maximal flow on back arcs in progressive mode
65 const int upperBackAngleFlow = 2; // and 360 back (only progressive mode)
66 const int lowerAngleFlow = (m_traditional ? 1 : 0);
67 const int piAngleFlow = (m_traditional ? 2 : 0);
68 const int halfPiAngleFlow = 1;
69 #if 0
70 const int halfPiBackAngleFlow = 0; //(only progressive mode)
71 #endif
72 const int zeroAngleFlow = (m_traditional ? 0 : 2);
73 const int zeroBackAngleFlow = 0; //(only progressive mode)
74
75 //in progressive mode, angles need cost to work out properly
76 #if 0
77 const int tradAngleCost = 0;
78 #endif
79 const int progAngleCost = 1;
80 const int tradBendCost = 1;
81 const int progBendCost = 3*PG.numberOfNodes(); //should use supply
82 PG.getClusterGraph().setUpdateDepth(true);
83 const int clusterTreeDepth = PG.getClusterGraph().treeDepth();
84
85
86 OR.init(E);
87 FaceArray<node> F(E);
88
89 OGDF_ASSERT(PG.representsCombEmbedding());
90 OGDF_ASSERT(F.valid());
91
92
93 // NETWORK VARIABLES
94
95 Graph Network; //the dual network
96 EdgeArray<int> lowerBound(Network,0); // lower bound for flow
97 EdgeArray<int> upperBound(Network,0); // upper bound for flow
98
99 EdgeArray<int> cost(Network,0); // cost of an edge
100 NodeArray<int> supply(Network,0); // supply of every node
101
102
103 //alignment helper
104 NodeArray<bool> fixedVal(Network, false); //already set somewhere
105 EdgeArray<bool> noBendEdge(Network, false); //for splitter, brother edges etc.
106
107 //NETWORK TO PlanRep INFORMATION
108
109 // stores for edges of the Network the corresponding adjEntries
110 // nodes, and faces of PG
111 EdgeArray<adjEntry> adjCor(Network,nullptr);
112 EdgeArray<node> nodeCor(Network,nullptr);
113 EdgeArray<face> faceCor(Network,nullptr);
114
115 NodeArray<n_type> nodeTypeArray(Network, n_type::low);
116
117 //PlanRep TO NETWORK INFORMATION
118
119 //Contains for every node of PG the corresponding node in the network
120 NodeArray<node> networkNode(PG,nullptr);
121 //Contains for every adjEntry of PG the corresponding edge in the network
122 AdjEntryArray<edge> backAdjCor(PG,nullptr); //bends
123 //contains for every adjEntry of PG the corresponding angle arc in the network
124 //note: this doesn't need to correspond to resulting drawing angles
125 //bends on the boundary define angles at expanded nodes
126 AdjEntryArray<edge> angleArc(PG, nullptr); //angle
127 //contains the corresponding back arc face to node in progressive mode
128 AdjEntryArray<edge> angleBackArc(PG, nullptr); //angle
129
130 // OTHER INFORMATION
131
132 // Contains for adjacency Entry of PG the face it belongs to in PG
133 AdjEntryArray<face> adjF(PG,nullptr);
134
135 //Contains for angle network arc progressive mode backward arc
136 EdgeArray<edge> angleTwin(Network, nullptr);
137
138 auto setProgressiveBoundsEqually = [&](edge e, int flow, int flowTwin) {
139 upperBound[e] = lowerBound[e] = flow;
140 const edge aTwin = angleTwin[e];
141 if (aTwin != nullptr) {
142 upperBound[aTwin] = lowerBound[aTwin] = flowTwin;
143 }
144 };
145 auto setBoundsEqually = [&](edge e, int flow, int flowTwin) {
146 if (m_traditional) {
147 upperBound[e] = lowerBound[e] = flow;
148 } else {
149 setProgressiveBoundsEqually(e, flow, flowTwin);
150 }
151 };
152
153 //types of network edges, to be used in flow to values
154 EdgeArray<NetArcType> l_arcType(Network, NetArcType::angle);
155
156 //contains the outer face
157 //face theOuterFace = E.externalFace();
158
159
160 // GENERATE ALL NODES OF THE NETWORK
161
162 //corresponding to the graphs nodes
163 int checksum = 0;
164 for(node v : PG.nodes)
165 {
166 OGDF_ASSERT((!m_fourPlanar) || (v->degree() < 5));
167
168 networkNode[v] = Network.newNode();
169 //maybe install a shortcut here for degree 4 nodes if not expanded
170
171 if (v->degree() > 4) nodeTypeArray[networkNode[v]] = n_type::high;
172 else nodeTypeArray[networkNode[v]] = n_type::low;
173
174 //already set the supply
175 if (m_traditional) supply[networkNode[v]] = 4;
176 else supply[networkNode[v]] = 2*v->degree() - 4;
177
178 checksum += supply[networkNode[v]];
179 }
180
181 //corresponding to the graphs faces
182 for (face f : E.faces)
183 {
184 F[f] = Network.newNode();
185
186 if (f == E.externalFace())
187 {
188 nodeTypeArray[F[f]] = n_type::outer;
189 if (m_traditional) supply[F[f]] = - 2*f->size() - 4;
190 else supply[F[f]] = 4;
191 }
192 else {
193 nodeTypeArray[F[f]] = n_type::inner;
194 if (m_traditional) supply[F[f]] = - 2*f->size() + 4;
195 else supply[F[f]] = -4;
196 }
197 }
198
199 #ifdef OGDF_DEBUG
200 //check the supply sum
201 checksum = 0;
202 for(node v : Network.nodes)
203 checksum += supply[v];
204 OGDF_ASSERT(checksum == 0);
205 #endif
206
207
208 #ifdef OGDF_HEAVY_DEBUG
209 for(node v : PG.nodes)
210 Logger::slout() << " v = " << v << " corresponds to "
211 << networkNode[v] << std::endl;
212 for (face f : E.faces) {
213 Logger::slout() << " face = " << f->index() << " corresponds to " << F[f];
214 if (f == E.externalFace())
215 Logger::slout() << " (Outer Face)";
216 Logger::slout() << std::endl;
217 }
218 #endif
219
220
221 // GENERATE ALL EDGES OF THE NETWORK
222
223 // OPTIMIZATION POTENTIAL:
224 // Do not insert edges with upper bound 0 into the network.
225
226 // Locate for every adjacency entry its adjacent faces.
227 for (face f : E.faces)
228 {
229 for(adjEntry adj : f->entries)
230 adjF[adj] = f;
231 }
232
233 #ifdef OGDF_HEAVY_DEBUG
234 for(face f : E.faces) {
235 Logger::slout() << "Face " << f->index() << " : ";
236 for(adjEntry adj : f->entries)
237 Logger::slout() << adj << "; ";
238 Logger::slout() << std::endl;
239 }
240 #endif
241
242 // Insert for every edge the (two) network arcs
243 // entering the face nodes, flow defines bends on the edge
244 for(edge e : PG.edges)
245 {
246 OGDF_ASSERT(adjF[e->adjSource()]);
247 OGDF_ASSERT(adjF[e->adjTarget()]);
248 if (F[adjF[e->adjSource()]] != F[adjF[e->adjTarget()]])
249 {
250 // not a selfloop.
251 edge newE = Network.newEdge(F[adjF[e->adjSource()]],F[adjF[e->adjTarget()]]);
252
253 l_arcType[newE] = NetArcType::bend;
254
255 adjCor[newE] = e->adjSource();
256 if ( (PG.typeOf(e) == Graph::EdgeType::generalization) ||
257 (PG.isClusterBoundary(e) && (!m_traditional)))
258 upperBound[newE] = 0;
259 else
260 upperBound[newE] = infinity;
261 cost[newE] = (m_traditional ?
262 clusterTradBendCost(PG.getClusterGraph().clusterDepth(PG.clusterOfEdge(e)), clusterTreeDepth, tradBendCost) :
263 clusterProgBendCost(PG.getClusterGraph().clusterDepth(PG.clusterOfEdge(e)), clusterTreeDepth, progBendCost));
264
265 backAdjCor[e->adjSource()] = newE;
266
267 newE = Network.newEdge(F[adjF[e->adjTarget()]],F[adjF[e->adjSource()]]);
268
269 l_arcType[newE] = NetArcType::bend;
270
271 adjCor[newE] = e->adjTarget();
272 if ((PG.typeOf(e) == Graph::EdgeType::generalization) ||
273 (PG.isClusterBoundary(e) && (m_traditional)))
274 upperBound[newE] = 0;
275 else
276 upperBound[newE] = infinity;
277 cost[newE] = (m_traditional ?
278 clusterTradBendCost(PG.getClusterGraph().clusterDepth(PG.clusterOfEdge(e)), clusterTreeDepth, tradBendCost) :
279 clusterProgBendCost(PG.getClusterGraph().clusterDepth(PG.clusterOfEdge(e)), clusterTreeDepth, progBendCost));
280 backAdjCor[e->adjTarget()] = newE;
281 }
282 }
283
284
285 // insert for every node edges to all appearances of adjacent faces
286 // flow defines angles at nodes
287 // progressive: and vice-versa
288
289
290 // Observe that two generalizations are not allowed to bend on
291 // a node. There must be a 180 degree angle between them.
292
293 // assure that there is enough flow between adjacent generalizations
294 NodeArray<bool> genshift(PG, false);
295
296 //non-expanded vertex
297 for(node v : PG.nodes)
298 {
299 // Locate possible adjacent generalizations
300 adjEntry gen1 = nullptr;
301 adjEntry gen2 = nullptr;
302
303 if (PG.typeOf(v) != Graph::NodeType::generalizationMerger
304 && PG.typeOf(v) != Graph::NodeType::generalizationExpander)
305 {
306 for(adjEntry adj : v->adjEntries)
307 {
308 if (PG.typeOf(adj->theEdge()) == Graph::EdgeType::generalization)
309 {
310 if (!gen1) gen1 = adj;
311 else gen2 = adj;
312 }
313 }
314 }
315
316 for(adjEntry adj : v->adjEntries)
317 {
318 edge e2 = Network.newEdge(networkNode[v],F[adjF[adj]]);
319
320 l_arcType[e2] = NetArcType::angle;
321
322 //CHECK bounded edges? and upper == 2 for zero degree
323 //progressive and traditional
324 upperBound[e2] = upperAngleFlow;
325 nodeCor [e2] = v;
326 adjCor [e2] = adj;
327 faceCor [e2] = adjF[adj];
328 angleArc [adj] = e2;
329
330 //do not allow zero degree at non-expanded vertex
331 //&& !m_allowLowZero
332
333 //progressive and traditional (compatible)
334 if (m_fourPlanar) lowerBound[e2] = lowerAngleFlow; //trad 1 = 90, prog 0 = 180
335
336 //insert opposite arcs face to node in progressive style
337 edge e3;
338 if (!m_traditional)
339 {
340 e3 = Network.newEdge(F[adjF[adj]], networkNode[v]); //flow for >180 degree
341
342 l_arcType[e3] = NetArcType::backAngle;
343
344 angleTwin[e2] = e3;
345 angleTwin[e3] = e2;
346
347 cost[e2] = progAngleCost;
348 cost[e3] = progAngleCost;
349
350 lowerBound[e3] = lowerAngleFlow; //180 degree,check highdegree drawings
351 upperBound[e3] = upperBackAngleFlow; //infinity;
352 #if 0
353 nodeCor [e3] = v; has no node, is face to node
354 #endif
355 adjCor [e3] = adj;
356 faceCor [e3] = adjF[adj];
357 angleBackArc[adj] = e3;
358
359 }
360 }
361
362 //second run to have all angleArcs already initialized
363 //set the flow boundaries
364 for(adjEntry adj : v->adjEntries)
365 {
366 edge e2 = angleArc[adj];
367
368 //allow low degree node zero degree angle for non-expanded vertices
369 #if 0
370 if (false) {
371 if ((gen1 || gen2) && (PG.isVertex(v)))
372 {
373 lowerBound[e2] = 0;
374 }
375 }
376 #endif
377
378 //hier muss man fuer die Kanten, die rechts ansetzen noch lowerbound 2 setzen
379
380 if ((gen2 == adj && gen1 == adj->cyclicSucc())
381 || (gen1 == adj && gen2 == adj->cyclicSucc())) {
382 setBoundsEqually(e2, piAngleFlow, 0);
383 genshift[v] = true;
384 }
385 }
386 }
387
388
389 // Reset upper and lower Bounds for network arcs that
390 // correspond to edges of generalizationmerger faces
391 // and edges of expanded nodes.
392
393 for(node v : PG.nodes)
394 {
395 if (PG.expandAdj(v))
396 {
397 // Get the corresponding face in the original embedding.
398 face f = adjF[PG.expandAdj(v)];
399
400 //expanded merger cages
401 if (PG.typeOf(v) == Graph::NodeType::generalizationMerger)
402 {
403 // Set upperBound to 0 for all edges.
404 for(adjEntry adj : f->entries)
405 {
406 //no bends on boundary (except special case following)
407 upperBound[backAdjCor[adj]] = 0;
408 upperBound[backAdjCor[adj->twin()]] = 0;
409
410 // Node w is in Network
411 node w = networkNode[adj->twinNode()];
412 for(adjEntry adjW : w->adjEntries) {
413 edge e = adjW->theEdge();
414 if (e->target() == F[f]) {
415 // is this: 180 degree?
416 // traditional: 2 progressive: 0
417 // if not traditional, limit angle back arc
418 setBoundsEqually(e, piAngleFlow, 0);
419 }
420 }
421
422 }
423 //special bend case
424 // Set the upper and lower bound for the first edge of
425 // the mergeexpander face to guarantee a 90 degree bend.
426 if (m_traditional)
427 {
428 upperBound[backAdjCor[PG.expandAdj(v)]] = 1;
429 lowerBound[backAdjCor[PG.expandAdj(v)]]= 1;
430 }
431 else
432 {
433 //progressive mode: bends are in opposite direction
434 upperBound[backAdjCor[PG.expandAdj(v)->twin()]] = 1;
435 lowerBound[backAdjCor[PG.expandAdj(v)->twin()]]= 1;
436 }
437
438 // Set the upper and lower bound for the first node in
439 // clockwise order of the mergeexpander face to
440 // guaranty a 90 degree angle at the node in the interior
441 // and a 180 degree angle between the generalizations in the
442 // exterior.
443 node secFace;
444
445 if (F[f] == backAdjCor[PG.expandAdj(v)]->target())
446 secFace = backAdjCor[PG.expandAdj(v)]->source();
447 else {
448 OGDF_ASSERT(F[f] == backAdjCor[PG.expandAdj(v)]->source());
449 // Otherwise: Edges in Network mixed up.
450 secFace = backAdjCor[PG.expandAdj(v)]->target();
451 }
452 node w = networkNode[PG.expandAdj(v)->twinNode()];
453
454 adjEntry adjFound = nullptr;
455 for(adjEntry adj : w->adjEntries)
456 {
457 if (adj->theEdge()->target() == F[f]) {
458 // if not traditional, limit angle back arc
459 setBoundsEqually(adj->theEdge(), 1, 0);
460 adjFound = adj;
461 break;
462 }
463 }
464
465 edge e;
466 if (m_traditional)
467 e = adjFound->cyclicSucc()->theEdge();
468 else
469 {
470 //we have two edges instead of one per face
471 adjEntry ae = adjFound->cyclicSucc();
472 e = ae->theEdge();
473 if (e->target() != secFace)
474 //maybe we have to jump one step further
475 e = ae->cyclicSucc()->theEdge();
476
477 }
478
479 if (e->target() == secFace) {
480 setBoundsEqually(e, piAngleFlow, piAngleFlow);
481 }
482
483 // Set the upper and lower bound for the last edge of
484 // the mergeexpander face to guarantee a 90 degree bend.
485 if (m_traditional)
486 {
487 upperBound[backAdjCor[PG.expandAdj(v)->faceCyclePred()]] = 1;
488 lowerBound[backAdjCor[PG.expandAdj(v)->faceCyclePred()]] = 1;
489 }
490 else
491 {
492 //progressive mode: bends are in opposite direction
493 upperBound[backAdjCor[PG.expandAdj(v)->faceCyclePred()->twin()]] = 1;
494 lowerBound[backAdjCor[PG.expandAdj(v)->faceCyclePred()->twin()]] = 1;
495 }
496
497 // Set the upper and lower bound for the last node in
498 // clockwise order of the mergeexpander face to
499 // guaranty a 90 degree angle at the node in the interior
500 // and a 180 degree angle between the generalizations in the
501 // exterior.
502 if (F[f] == backAdjCor[PG.expandAdj(v)->faceCyclePred()]->target())
503 secFace = backAdjCor[PG.expandAdj(v)->faceCyclePred()]->source();
504 else if (F[f] == backAdjCor[PG.expandAdj(v)->faceCyclePred()]->source())
505 secFace = backAdjCor[PG.expandAdj(v)->faceCyclePred()]->target();
506 else
507 {
508 OGDF_ASSERT(false); // Edges in Network mixed up.
509 }
510 w = networkNode[PG.expandAdj(v)->faceCyclePred()->theNode()];
511
512 adjFound = nullptr;
513 for(adjEntry adj : w->adjEntries)
514 {
515 if (adj->theEdge()->target() == F[f]) {
516 setBoundsEqually(adj->theEdge(), 1, 0);
517 adjFound = adj;
518 break;
519 }
520 }
521
522 if (m_traditional)
523 e = adjFound->cyclicPred()->theEdge();
524 else
525 {
526 //we have two edges instead of one per face
527 adjEntry ae = adjFound->cyclicPred();
528 e = ae->theEdge();
529 if (e->target() != secFace)
530 //maybe we have to jump one step further
531 e = ae->cyclicPred()->theEdge();
532 }
533
534 if (e->target() == secFace) {
535 setBoundsEqually(e, piAngleFlow, piAngleFlow);
536 }
537 }
538
539 //expanded high degree cages
540 else if (PG.typeOf(v) == Graph::NodeType::highDegreeExpander )
541 {
542 // Set upperBound to 1 for all edges, allowing maximal one
543 // 90 degree bend.
544 // Set upperBound to 0 for the corresponding entering edge
545 // allowing no 270 degree bend.
546 // Set upperbound to 1 for every edge corresponding to the
547 // angle of a vertex. This permitts 270 degree angles in
548 // the face
549
550 adjEntry splitter = nullptr;
551
552
553 //assure that edges are only spread around the sides if not too
554 //many multi edges are aligned
555
556 //count multiedges at node
557 int multis = 0;
558 AdjEntryArray<bool> isMulti(PG, false);
559 if (m_multiAlign)
560 {
561 //if all edges are multi edges, find a 360 degree position
562 bool allMulti = true;
563 for(adjEntry adj : f->entries) //this double iteration slows the algorithm down
564 {
565 //no facesplitter in attributedgraph
566 #if 0
567 if (!PG.faceSplitter(adj->theEdge()))
568 #endif
569 {
570 adjEntry srcadj = adj->cyclicPred();
571 adjEntry tgtadj = adj->twin()->cyclicSucc();
572 //check if the nodes are expanded
573 node vt1, vt2;
574 if (PG.expandedNode(srcadj->twinNode()))
575 vt1 = PG.expandedNode(srcadj->twinNode());
576 else vt1 = srcadj->twinNode();
577 if (PG.expandedNode(tgtadj->twinNode()))
578 vt2 = PG.expandedNode(tgtadj->twinNode());
579 else vt2 = tgtadj->twinNode();
580 if (vt1 == vt2)
581 {
582 //we forbid bends between two incident multiedges
583 if (m_traditional)
584 {
585 lowerBound[backAdjCor[adj]] = upperBound[backAdjCor[adj]] = 0;
586 isMulti[adj] = true;
587 }
588 else
589 {
590 lowerBound[backAdjCor[adj->twin()]] =
591 lowerBound[backAdjCor[adj]] =
592 upperBound[backAdjCor[adj]] =
593 upperBound[backAdjCor[adj->twin()]] = 0;
594 isMulti[adj->twin()] = true;
595 }
596 multis++;
597 } else {
598 allMulti = false;
599 }
600 }
601 }
602 //multi edge correction: only multi edges => one edge needs 360 degree
603 if (allMulti)
604 {
605 //find an edge that allows 360 degree without bends
606 bool twoNodeCC = true; //no foreign non-multi edge to check for
607 for(adjEntry adj : f->entries)
608 {
609 //now check for expanded nodes
610 adjEntry adjOut = adj->cyclicPred(); //outgoing edge entry
611 node vOpp = adjOut->twinNode();
612 if (PG.expandedNode(vOpp))
613 {
614 adjOut = adjOut->faceCycleSucc(); //on expanded boundary
615 //does not end on self loops
616 node vStop = vOpp;
617 if (PG.expandedNode(vStop)) vStop = PG.expandedNode(vStop);
618 while (PG.expandedNode(adjOut->twinNode()) == vStop)
619 //we are still on vOpps cage
620 adjOut = adjOut->faceCycleSucc();
621 }
622 //now adjOut is either a "foreign" edge or one of the
623 //original multi edges if two-node-CC
624 //adjEntry testadj = adjCor[e]->faceCycleSucc()->twin();
625 adjEntry testAdj = adjOut->twin();
626 node vBack = testAdj->theNode();
627 if (PG.expandedNode(vBack))
628 {
629 vBack = PG.expandedNode(vBack);
630 }
631 if (vBack != v) //v is expanded node
632 {
633 //dont use iteration result, set firstedge!
634 upperBound[backAdjCor[adj]] = 4; //4 bends for 360
635 twoNodeCC = false;
636 break;
637 }
638 }
639 //if only two nodes with multiedges are in current CC,
640 //assign 360 degree to first edge
641 if (twoNodeCC)
642 {
643 //it would be difficult to guarantee that the networkedge
644 //on the other side of the face would get the 360, so alllow
645 //360 for all edges or search for the outer face
646
647 for(adjEntry adj : f->entries)
648 {
649 adjEntry ae = adj->cyclicPred();
650 if (adjF[ae] == E.externalFace())
651 {
652 upperBound[backAdjCor[adj]] = 4; //4 bends for 360
653 break;
654 }
655 }
656 }
657 }
658 //End multi edge correction
659 }
660
661 //now set the upper Bounds
662 for(adjEntry adj : f->entries)
663 {
664 //should be: no 270 degrees
665 if (m_traditional)
666 upperBound[backAdjCor[adj->twin()]] = 0;
667 else
668 upperBound[backAdjCor[adj]] = 0;
669
670 #if 0
671 if (false)//(PG.faceSplitter(adj->theEdge()))
672 {
673 // No bends allowed on the face splitter
674 upperBound[backAdjCor[adj]] = 0;
675
676 //CHECK
677 //progressive??? sollte sein:
678 upperBound[backAdjCor[adj->twin()]] = 0;
679
680 splitter = adj;
681 continue;
682 }
683 else
684 //should be: only one bend
685 #endif
686 {
687
688 if (m_distributeEdges)
689 //CHECK
690 //maybe we should change this to setting the lower bound too,
691 //depending on the degree (<= 4 => deg 90)
692 {
693 //check the special case degree >=4 with 2
694 // generalizations following each other if degree
695 // > 4, only 90 degree allowed, nodeType high
696 // bloed, da nicht original
697 #if 0
698 if (nodeTypeArray[ networkNode[adj->twinNode()] ] == high)
699 #endif
700 //hopefully size is original degree
701 if (m_traditional)
702 {
703 if (!isMulti[adj]) //m_multiAlign???
704 {
705 //check if original node degree minus multi edges
706 //is high enough
707 //Attention: There are some lowerBounds > 1
708 #ifdef OGDF_DEBUG
709 int oldBound = upperBound[backAdjCor[adj]];
710 #endif
711 if ((!genshift[v]) && (f->size()-multis>3))
712 upperBound[backAdjCor[adj]] =
713 //max(2, lowerBound[backAdjCor[adj]]);
714 //due to mincostflowreinelt errors, we are not
715 //allowed to set ub 1
716 max(1, lowerBound[backAdjCor[adj]]);
717 else upperBound[backAdjCor[adj]] =
718 max(2, lowerBound[backAdjCor[adj]]);
719 //nur zum Testen der Faelle
720 OGDF_ASSERT(oldBound >= upperBound[backAdjCor[adj]]);
721 }
722 } else {
723 //preliminary set the bound in all cases
724
725 if (!isMulti[adj])
726 {
727 //Attention: There are some lowerBounds > 1
728
729 if ((!genshift[v]) && (f->size()-multis>3))
730 upperBound[backAdjCor[adj->twin()]] =
731 max(1, lowerBound[backAdjCor[adj->twin()]]);
732 else upperBound[backAdjCor[adj->twin()]] =
733 max(2, lowerBound[backAdjCor[adj->twin()]]);
734
735 }
736 }
737 }
738 }
739
740 // Node w is in Network
741 node w = networkNode[adj->twinNode()];
742
743 #if 0
744 if (w && !(m_traditional && m_fourPlanar && (w->degree() != 4)))
745 #endif
746 {
747 //should be: inner face angles set to 180
748 for(adjEntry adjW : w->adjEntries) {
749 edge e = adjW->theEdge();
750 if (e->target() == F[f]) {
751 setBoundsEqually(e, piAngleFlow, piAngleFlow);
752 }
753 }
754 }
755 }
756
757 // In case a face splitter was used, we need to update the
758 // second face of the cage.
759 if (splitter)
760 {
761 // Get the corresponding face in the original embedding.
762 face f2 = adjF[splitter->twin()];
763
764 for(adjEntry adj : f2->entries)
765 {
766 if (adj == splitter->twin())
767 continue;
768
769 if (m_traditional)
770 upperBound[backAdjCor[adj->twin()]] = 0;
771 else //progressive bends are in opposite direction
772 upperBound[backAdjCor[adj]] = 0;
773
774 // Node w is in Network
775 node w = networkNode[adj->twinNode()];
776 #if 0
777 if (w && !(m_traditional && m_fourPlanar && (w->degree() != 4)))
778 #endif
779 {
780 for(adjEntry adjW : w->adjEntries) {
781 edge e = adjW->theEdge();
782 if (e->target() == F[f2]) {
783 setBoundsEqually(e, piAngleFlow, piAngleFlow);
784 }
785 }
786 }
787 }
788 }
789 }
790 } else {
791 //non-expanded (low degree) nodes
792 //check for alignment and for multi edges
793
794 if (PG.isVertex(v))
795 {
796 node w = networkNode[v];
797 if ((nodeTypeArray[w] != n_type::low) || (w->degree()<2)) continue;
798
799 //check for multi edges and decrease lowerbound if align
800 //int lowerb = 0;
801
802 bool allMulti = true;
803 for(adjEntry adj : w->adjEntries) {
804 edge e = adj->theEdge();
805 //lowerb += max(lowerBound[e], 0);
806
807 OGDF_ASSERT((!m_traditional) || (e->source() == w));
808 if (m_traditional && (e->source() != w)) OGDF_THROW(AlgorithmFailureException);
809 if (e->source() != w) continue; //dont treat back angle edges
810
811 if (m_multiAlign && (v->degree()>1))
812 {
813 adjEntry srcAdj = adjCor[e];
814 adjEntry tgtAdj = adjCor[e]->faceCyclePred();
815
816 //check if the nodes are expanded
817 node vt1, vt2;
818 if (PG.expandedNode(srcAdj->twinNode()))
819 vt1 = PG.expandedNode(srcAdj->twinNode());
820 else vt1 = srcAdj->twinNode();
821
822 if (PG.expandedNode(tgtAdj->theNode()))
823 vt2 = PG.expandedNode(tgtAdj->theNode());
824 else vt2 = tgtAdj->theNode();
825
826 if (vt1 == vt2)
827 {
828
829 fixedVal[w] = true;
830
831 // we forbid bends between incident multi edges
832 // or is it angle?
833 setBoundsEqually(e, zeroAngleFlow, zeroBackAngleFlow);
834 } else {
835 //CHECK
836 //to be done: only if multiedges
837 if (!genshift[v]) upperBound[e] = upperAngleFlow;
838 allMulti = false;
839 }
840 }
841 }
842
843 if (m_multiAlign && allMulti && (v->degree()>1))
844 {
845 fixedVal[w] = true;
846
847 //find an edge that allows 360 degree without bends
848 bool twoNodeCC = true;
849 for(adjEntry adj : w->adjEntries) {
850 edge e = adj->theEdge();
851 //now check for expanded nodes
852 adjEntry runAdj = adjCor[e];
853 node vOpp = runAdj->twinNode();
854 node vStop;
855 vStop = vOpp;
856 runAdj = runAdj->faceCycleSucc();
857 if (PG.expandedNode(vStop))
858 {
859
860 //does not end on self loops
861 vStop = PG.expandedNode(vStop);
862 while (PG.expandedNode(runAdj->twinNode()) == vStop)
863 //we are still on vOpps cage
864 runAdj = runAdj->faceCycleSucc();
865 }
866 //adjEntry testadj = adjCor[e]->faceCycleSucc()->twin();
867 adjEntry testAdj = runAdj->twin();
868 node vBack = testAdj->theNode();
869
870 if (vBack != v) //not same node
871 {
872 if (PG.expandedNode(vBack))
873 {
874 vBack = PG.expandedNode(vBack);
875 }
876 if (vBack != vStop) //vstop !=0, not inner face in 2nodeCC
877 {
878 //CHECK: 4? upper
879 OGDF_ASSERT(!PG.expandedNode(v)); //otherwise not angle flow
880 if (m_traditional) {
881 // dont use iteration result, set firstedge!
882 upperBound[e] = maxAngleFlow;
883 } else {
884 setProgressiveBoundsEqually(e, lowerAngleFlow, maxBackFlow);
885 }
886 twoNodeCC = false;
887 break;
888 }
889 }
890 }
891 //if only two nodes with multiedges are in current CC,
892 //assign 360 degree to first edge
893 if (twoNodeCC)
894 {
895 //it would be difficult to guarantee that the networkedge
896 //on the other side of the face would get the 360, so alllow
897 //360 for all edges or search for external face
898 for(adjEntry adj : w->adjEntries) {
899 edge e = adj->theEdge();
900 adjEntry adje = adjCor[e];
901 if (adjF[adje] == E.externalFace())
902 {
903 //CHECK: 4? upper
904 OGDF_ASSERT(!PG.expandedNode(v)); //otherwise not angle flow
905 if (m_traditional) {
906 upperBound[e] = maxAngleFlow;//upperAngleFlow;
907 } else {
908 setProgressiveBoundsEqually(e, lowerAngleFlow, maxBackFlow);
909 }
910 break;
911 }
912 }
913 }
914 }
915 }
916
917 }
918 }
919
920 //int flowSum = 0;
921
922 //To Be done: hier multiedges testen
923 for(node tv : Network.nodes)
924 {
925 //flowSum += supply[tv];
926
927 //only check representants of original nodes, not faces
928 if ( nodeTypeArray[tv] == n_type::low || nodeTypeArray[tv] == n_type::high )
929 {
930 //if node representant with degree 4, set angles preliminary
931 //degree four nodes with two gens are expanded in PlanRepUML
932 //all others are allowed to change the edge positions
933 if ( (m_traditional && (tv->degree() == 4)) ||
934 ((tv->degree() == 8) && !m_traditional) )
935 {
936 //three types: degree4 original nodes and facesplitter end nodes,
937 //maybe crossings
938 //fixassignment tells us that low degree nodes are not allowed to
939 //have zero degree and special nodes are already assigned
940 bool fixAssignment = true;
941
942 //check if free assignment is possible for degree 4
943 if (m_deg4free)
944 {
945 fixAssignment = false;
946 for(adjEntry adj : tv->adjEntries) {
947 edge te = adj->theEdge();
948 if (te->source() == tv)
949 {
950 adjEntry pgEntry = adjCor[te];
951 node pgNode = pgEntry->theNode();
952
953 if ((PG.expandedNode(pgNode))
954 //|| (PG.faceSplitter(adjCor[te]->theEdge()))
955 || (PG.typeOf(pgNode) == Graph::NodeType::dummy) //test crossings
956 )
957 {
958 fixAssignment = true;
959 break;
960 }
961 }
962 }
963 }
964
965 //CHECK
966 //now set the angles at degree 4 nodes to distribute edges
967 for(adjEntry adj : tv->adjEntries) {
968 edge te = adj->theEdge();
969
970 if (te->source() == tv)
971 {
972 if (fixedVal[tv]) continue; //if already special values set
973
974 if (!fixAssignment)
975 {
976 lowerBound[te] = 0; //lowerAngleFlow maybe 1;//0;
977 upperBound[te] = upperAngleFlow;//4;
978 }
979 else
980 {
981 //only allow 90 degree arc value
982 lowerBound[te] = halfPiAngleFlow;
983 upperBound[te] = halfPiAngleFlow;
984 }
985 } else {
986 if (fixedVal[tv]) continue; //if already special values set
987
988 if (!fixAssignment)
989 {
990 OGDF_ASSERT(lowerAngleFlow == 0); //should only be in progressive mode
991 lowerBound[te] = lowerAngleFlow;
992 upperBound[te] = upperBackAngleFlow;
993 }
994 else
995 {
996 //only allow 0-180 degree back arc value
997 lowerBound[te] = 0; //1
998 upperBound[te] = 0; //halfPiAngleFlow; //1
999 }
1000 }
1001 }
1002 }
1003 int lowsum = 0, upsum = 0;
1004 for(adjEntry adj : tv->adjEntries) {
1005 edge te = adj->theEdge();
1006 OGDF_ASSERT(lowerBound[te] <= upperBound[te]);
1007 if (noBendEdge[te]) lowerBound[te] = 0;
1008 lowsum += lowerBound[te];
1009 upsum += upperBound[te];
1010 }
1011 if (m_traditional) {
1012 OGDF_ASSERT(lowsum <= supply[tv]);
1013 OGDF_ASSERT(upsum >= supply[tv]);
1014 }
1015 }
1016 }
1017 for(node tv : Network.nodes)
1018 {
1019 for(adjEntry adj : tv->adjEntries) {
1020 edge te = adj->theEdge();
1021 if (noBendEdge[te]) lowerBound[te] = 0;
1022 }
1023 }
1024
1025
1026 bool isFlow = false;
1027 SList<edge> capacityBoundedEdges;
1028 EdgeArray<int> flow(Network,0);
1029
1030 // Set upper Bound to current upper bound.
1031 // Some edges are no longer capacitybounded, therefore save their status
1032 EdgeArray<bool> isBounded(Network, false);
1033
1034 for(edge e : Network.edges)
1035 {
1036 if (upperBound[e] == infinity)
1037 {
1038 capacityBoundedEdges.pushBack(e);
1039 isBounded[e] = true;
1040 }
1041 }
1042
1043 int currentUpperBound;
1044 if (startBoundBendsPerEdge > 0)
1045 currentUpperBound = startBoundBendsPerEdge;
1046 else
1047 currentUpperBound = 4*PG.numberOfEdges();
1048
1049
1050 while ( (!isFlow) && (currentUpperBound <= 4*PG.numberOfEdges()) )
1051 {
1052 for (edge e : capacityBoundedEdges)
1053 upperBound[e] = currentUpperBound;
1054
1055 isFlow = flowModule.call(Network,lowerBound,upperBound,cost,supply,flow);
1056
1057 #if 0
1058 if (isFlow)
1059 {
1060 for(edge e : Network.edges) {
1061 fout << "e = " << e << " flow = " << flow[e];
1062 if(nodeCor[e] == 0 && adjCor[e])
1063 fout << " real edge = " << adjCor[e]->theEdge();
1064 fout << std::endl;
1065 }
1066 for(edge e : Network.edges) {
1067 if(nodeCor[e] == 0 && adjCor[e] != 0 && flow[e] > 0) {
1068 fout << "Bends " << flow[e] << " on edge "
1069 << adjCor[e]->theEdge()
1070 << " between faces " << adjF[adjCor[e]]->index() << " - "
1071 << adjF[adjCor[e]->twin()]->index() << std::endl;
1072 }
1073 }
1074 for(edge e : Network.edges) {
1075 if(nodeCor[e] != 0 && faceCor[e] != 0) {
1076 fout << "Angle " << (flow[e])*90 << "\tdegree on node "
1077 << nodeCor[e] << " at face " << faceCor[e]->index()
1078 << "\tbetween edge " << adjCor[e]->faceCyclePred()
1079 << "\tand " << adjCor[e] << std::endl;
1080 }
1081 }
1082 if (startBoundBendsPerEdge> 0) {
1083 fout << "Minimizing edge bends for upper bound "
1084 << currentUpperBound;
1085 if(isFlow)
1086 fout << " ... Successful";
1087 fout << std::endl;
1088 }
1089 }
1090 #endif
1091
1092 OGDF_ASSERT(startBoundBendsPerEdge >= 1 || isFlow);
1093
1094 currentUpperBound++;
1095 }
1096
1097 if (startBoundBendsPerEdge && !isFlow)
1098 {
1099 // couldn't compute reasonable shape
1100 OGDF_THROW_PARAM(AlgorithmFailureException, AlgorithmFailureCode::NoFlow);
1101 }
1102
1103
1104 int totalNumBends = 0;
1105
1106
1107 for(edge e : Network.edges)
1108 {
1109
1110 if (nodeCor[e] == nullptr && adjCor[e] != nullptr && (flow[e] > 0) &&
1111 (angleTwin[e] == nullptr) ) //no angle edges
1112 {
1113 OGDF_ASSERT(OR.bend(adjCor[e]).size() == 0);
1114
1115 char zeroChar = (m_traditional ? '0' : '1');
1116 char oneChar = (m_traditional ? '1' : '0');
1117 //we depend on the property that there is no flow
1118 //in opposite direction due to the cost
1119 OR.bend(adjCor[e]).set(zeroChar,flow[e]);
1120 OR.bend(adjCor[e]->twin()).set(oneChar,flow[e]);
1121
1122 totalNumBends += flow[e];
1123
1124 //check if bends fit bounds
1125 if (isBounded[e])
1126 {
1127 OGDF_ASSERT((int)OR.bend(adjCor[e]).size() <= currentUpperBound);
1128 OGDF_ASSERT((int)OR.bend(adjCor[e]->twin()).size() <= currentUpperBound);
1129 }
1130 }
1131 else if (nodeCor[e] != nullptr && faceCor[e] != nullptr)
1132 {
1133 if (m_traditional) OR.angle(adjCor[e]) = (flow[e]);
1134 else
1135 {
1136 OGDF_ASSERT(angleTwin[e]);
1137 OGDF_ASSERT(flow[e] >= 0);
1138 OGDF_ASSERT(flow[e] <= 2);
1139
1140 const int twinFlow = flow[angleTwin[e]];
1141
1142 if (flow[e] == 0) {
1143 OGDF_ASSERT(twinFlow >= 0);
1144 OGDF_ASSERT(twinFlow <= 2);
1145
1146 OR.angle(adjCor[e]) = 2 + twinFlow;
1147 } else {
1148 OGDF_ASSERT(twinFlow == 0);
1149 OR.angle(adjCor[e]) = 2 - flow[e];
1150 }
1151 }
1152 }
1153 }
1154
1155
1156 #ifdef OGDF_HEAVY_DEBUG
1157 Logger::slout() << "\n\nTotal Number of Bends : "<< totalNumBends << std::endl << std::endl;
1158 #endif
1159
1160 #ifdef OGDF_DEBUG
1161 string error;
1162 if (!OR.check(error)) {
1163 Logger::slout() << error << std::endl;
1164 OGDF_ASSERT(false);
1165 }
1166 #endif
1167
1168 }
1169
1170 }
1171