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