6 * $Date: 2012-07-07 23:10:08 +0200 (Sa, 07. Jul 2012) $
7 ***************************************************************/
10 * \brief Computes the Orthogonal Representation of a Planar
11 * Representation of a UML Graph.
13 * \author Karsten Klein
16 * This file is part of the Open Graph Drawing Framework (OGDF).
20 * See README.txt in the root directory of the OGDF installation for details.
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * Version 2 or 3 as published by the Free Software Foundation;
26 * see the file LICENSE.txt included in the packaging of this file
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
36 * You should have received a copy of the GNU General Public
37 * License along with this program; if not, write to the Free
38 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
39 * Boston, MA 02110-1301, USA.
41 * \see http://www.gnu.org/copyleft/gpl.html
42 ***************************************************************/
45 #include <ogdf/cluster/ClusterOrthoShaper.h>
46 #include <ogdf/basic/FaceArray.h>
48 #include <ogdf/graphalg/MinCostFlowReinelt.h>
51 const int flowBound
= 4; //No more than 4 bends in cage boundary,
52 //and no more than 360 degrees at vertices
54 enum netArcType
{defaultArc
, angle
, backAngle
, bend
};
59 //*************************************************************
60 //call function: compute a flow in a dual network and interpret
61 //result as bends and angles (representation shape)
62 void ClusterOrthoShaper::call(ClusterPlanRep
&PG
,
63 CombinatorialEmbedding
&E
,
65 int startBoundBendsPerEdge
,
69 if (PG
.numberOfEdges() == 0)
72 m_fourPlanar
= fourPlanar
;
74 // the min cost flow we use
75 MinCostFlowReinelt flowModule
;
76 const int infinity
= flowModule
.infinity();
78 //************************************************************
79 //fix some values depending on traditional or progressive mode
80 //************************************************************
82 //standard flow boundaries for traditional and progressive mode
83 const int upperAngleFlow
= (m_traditional
? 4 : 1); //non zero
84 const int maxAngleFlow
= (m_traditional
? 4 : 2); //use 2 for multialign zero degree
85 const int maxBackFlow
= 2; //maximal flow on back arcs in progressive mode
86 const int upperBackAngleFlow
= 2; // and 360 back (only progressive mode)
87 const int lowerAngleFlow
= (m_traditional
? 1 : 0);
88 const int piAngleFlow
= (m_traditional
? 2 : 0);
89 const int halfPiAngleFlow
= 1;
90 //const int halfPiBackAngleFlow = 0; //(only progressive mode)
91 const int zeroAngleFlow
= (m_traditional
? 0 : 2);
92 const int zeroBackAngleFlow
= 0; //(only progressive mode)
94 //in progressive mode, angles need cost to work out properly
95 //const int tradAngleCost = 0;
96 const int progAngleCost
= 1;
97 const int tradBendCost
= 1;
98 const int progBendCost
= 3*PG
.numberOfNodes(); //should use supply
99 PG
.getClusterGraph().setUpdateDepth(true);
100 const int clusterTreeDepth
= PG
.getClusterGraph().treeDepth();
104 FaceArray
<node
> F(E
);
106 OGDF_ASSERT(PG
.representsCombEmbedding())
107 OGDF_ASSERT(F
.valid())
115 Graph Network
; //the dual network
116 EdgeArray
<int> lowerBound(Network
,0); // lower bound for flow
117 EdgeArray
<int> upperBound(Network
,0); // upper bound for flow
119 EdgeArray
<int> cost(Network
,0); // cost of an edge
120 NodeArray
<int> supply(Network
,0); // supply of every node
124 NodeArray
<bool> fixedVal(Network
, false); //already set somewhere
125 EdgeArray
<bool> noBendEdge(Network
, false); //for splitter, brother edges etc.
127 //*********************************
128 //NETWORK TO PlanRep INFORMATION
130 // stores for edges of the Network the corresponding adjEntries
131 // nodes, and faces of PG
132 EdgeArray
<adjEntry
> adjCor(Network
,0);
133 EdgeArray
<node
> nodeCor(Network
,0);
134 EdgeArray
<face
> faceCor(Network
,0);
136 NodeArray
<n_type
> nodeType(Network
, low
);
138 //*********************************
139 //PlanRep TO NETWORK INFORMATION
141 //Contains for every node of PG the corresponding node in the network
142 NodeArray
<node
> networkNode(PG
,0);
143 //Contains for every adjEntry of PG the corresponding edge in the network
144 AdjEntryArray
<edge
> backAdjCor(PG
,0); //bends
145 //contains for every adjEntry of PG the corresponding angle arc in the network
146 //note: this doesn't need to correspond to resulting drawing angles
147 //bends on the boundary define angles at expanded nodes
148 AdjEntryArray
<edge
> angleArc(PG
, 0); //angle
149 //contains the corresponding back arc face to node in progressive mode
150 AdjEntryArray
<edge
> angleBackArc(PG
, 0); //angle
155 // Contains for adjacency Entry of PG the face it belongs to in PG
156 AdjEntryArray
<face
> adjF(PG
,0);
158 //Contains for angle network arc progressive mode backward arc
159 EdgeArray
<edge
> angleTwin(Network
, 0);
161 //types of network edges, to be used in flow to values
162 EdgeArray
<netArcType
> l_arcType(Network
, angle
);
164 //contains the outer face
165 //face theOuterFace = E.externalFace();
167 //*******************
168 // STANDARD VARIABLES
175 //**********************************
176 // GENERATE ALL NODES OF THE NETWORK
177 //**********************************
179 //corresponding to the graphs nodes
183 OGDF_ASSERT((!m_fourPlanar
) || (v
->degree() < 5));
185 networkNode
[v
] = Network
.newNode();
186 //maybe install a shortcut here for degree 4 nodes if not expanded
188 if (v
->degree() > 4) nodeType
[networkNode
[v
]] = high
;
189 else nodeType
[networkNode
[v
]] = low
;
191 //already set the supply
192 if (m_traditional
) supply
[networkNode
[v
]] = 4;
193 else supply
[networkNode
[v
]] = 2*v
->degree() - 4;
195 checksum
+= supply
[networkNode
[v
]];
198 //corresponding to the graphs faces
200 for (f
= E
.firstFace(); f
; f
= f
->succ())
202 F
[f
] = Network
.newNode();
204 if (f
== E
.externalFace())
206 nodeType
[F
[f
]] = outer
;
207 if (m_traditional
) supply
[F
[f
]] = - 2*f
->size() - 4;
208 else supply
[F
[f
]] = 4;
211 nodeType
[F
[f
]] = inner
;
212 if (m_traditional
) supply
[F
[f
]] = - 2*f
->size() + 4;
213 else supply
[F
[f
]] = -4;
218 //check the supply sum
220 forall_nodes(v
, Network
)
221 checksum
+= supply
[v
];
222 OGDF_ASSERT(checksum
== 0);
227 if (int(ogdf::debugLevel
) >= int(dlHeavyChecks
)) {
229 cout
<< " v = " << v
<< " corresponds to "
230 << networkNode
[v
] << endl
;
231 for (f
= E
.firstFace(); f
; f
= f
->succ()) {
232 cout
<< " face = " << f
->index() << " corresponds to " << F
[f
];
233 if (f
== E
.externalFace())
234 cout
<<" (Outer Face)";
242 //**********************************
243 // GENERATE ALL EDGES OF THE NETWORK
244 //**********************************
246 // OPTIMIZATION POTENTIAL:
247 // Do not insert edges with upper bound 0 into the network.
249 // Locate for every adjacency entry its adjacent faces.
250 for (f
= E
.firstFace(); f
; f
= f
->succ())
252 forall_face_adj(adj
,f
)
257 if(int(ogdf::debugLevel
) >= int(dlHeavyChecks
)) {
258 for(f
= E
.firstFace(); f
; f
= f
->succ()) {
259 cout
<< "Face " << f
->index() << " : ";
260 forall_face_adj(adj
,f
)
267 //*********************************************
268 // Insert for every edge the (two) network arcs
269 // entering the face nodes, flow defines bends on the edge
272 OGDF_ASSERT(adjF
[e
->adjSource()] && adjF
[e
->adjTarget()])
273 if (F
[adjF
[e
->adjSource()]] != F
[adjF
[e
->adjTarget()]])
276 edge newE
= Network
.newEdge(F
[adjF
[e
->adjSource()]],F
[adjF
[e
->adjTarget()]]);
278 l_arcType
[newE
] = bend
;
280 adjCor
[newE
] = e
->adjSource();
281 if ( (PG
.typeOf(e
) == Graph::generalization
) ||
282 (PG
.isClusterBoundary(e
) && (!m_traditional
)))
283 upperBound
[newE
] = 0;
285 upperBound
[newE
] = infinity
;
286 cost
[newE
] = (m_traditional
?
287 clusterTradBendCost(PG
.getClusterGraph().clusterDepth(PG
.clusterOfEdge(e
)), clusterTreeDepth
, tradBendCost
) :
288 clusterProgBendCost(PG
.getClusterGraph().clusterDepth(PG
.clusterOfEdge(e
)), clusterTreeDepth
, progBendCost
));
290 backAdjCor
[e
->adjSource()] = newE
;
292 newE
= Network
.newEdge(F
[adjF
[e
->adjTarget()]],F
[adjF
[e
->adjSource()]]);
294 l_arcType
[newE
] = bend
;
296 adjCor
[newE
] = e
->adjTarget();
297 if ((PG
.typeOf(e
) == Graph::generalization
) ||
298 (PG
.isClusterBoundary(e
) && (m_traditional
)))
299 upperBound
[newE
] = 0;
301 upperBound
[newE
] = infinity
;
302 cost
[newE
] = (m_traditional
?
303 clusterTradBendCost(PG
.getClusterGraph().clusterDepth(PG
.clusterOfEdge(e
)), clusterTreeDepth
, tradBendCost
) :
304 clusterProgBendCost(PG
.getClusterGraph().clusterDepth(PG
.clusterOfEdge(e
)), clusterTreeDepth
, progBendCost
));
305 backAdjCor
[e
->adjTarget()] = newE
;
310 //*****************************************************************
311 // insert for every node edges to all appearances of adjacent faces
312 // flow defines angles at nodes
313 // progressive: and vice-versa
314 //*****************************************************************
317 //************************************************************
318 // Observe that two generalizations are not allowed to bend on
319 // a node. There must be a 180 degree angle between them.
321 // assure that there is enough flow between adjacent generalizations
322 NodeArray
<bool> genshift(PG
, false);
324 //non-expanded vertex
327 //*****************************************
328 // Locate possible adjacent generalizations
332 if (PG
.typeOf(v
) != Graph::generalizationMerger
333 && PG
.typeOf(v
) != Graph::generalizationExpander
)
337 if (PG
.typeOf(adj
->theEdge()) == Graph::generalization
)
339 if (!gen1
) gen1
= adj
;
343 }// if not generalization
348 edge e2
= Network
.newEdge(networkNode
[v
],F
[adjF
[adj
]]);
350 l_arcType
[e2
] = angle
;
352 //CHECK bounded edges? and upper == 2 for zero degree
353 //progressive and traditional
354 upperBound
[e2
] = upperAngleFlow
;
357 faceCor
[e2
] = adjF
[adj
];
360 //do not allow zero degree at non-expanded vertex
363 //progressive and traditional (compatible)
364 if (m_fourPlanar
) lowerBound
[e2
] = lowerAngleFlow
; //trad 1 = 90, prog 0 = 180
366 //insert opposite arcs face to node in progressive style
370 e3
= Network
.newEdge(F
[adjF
[adj
]], networkNode
[v
]); //flow for >180 degree
372 l_arcType
[e3
] = backAngle
;
377 cost
[e2
] = progAngleCost
;
378 cost
[e3
] = progAngleCost
;
380 lowerBound
[e3
] = lowerAngleFlow
; //180 degree,check highdegree drawings
381 upperBound
[e3
] = upperBackAngleFlow
; //infinity;
382 //nodeCor [e3] = v; has no node, is face to node
384 faceCor
[e3
] = adjF
[adj
];
385 angleBackArc
[adj
] = e3
;
390 //second run to have all angleArcs already initialized
391 //set the flow boundaries
394 edge e2
= angleArc
[adj
];
396 if (!m_traditional
) e3
= angleTwin
[e2
];
398 //allow low degree node zero degree angle for non-expanded vertices
400 // if ((gen1 || gen2) && (PG.isVertex(v)))
402 // lowerBound[e2] = 0;
405 //*******************************************************************
406 //*******************************************************************
408 //hier muss man fuer die Kanten, die rechts ansetzen noch lowerbound 2 setzen
410 if (gen2
== adj
&& gen1
== adj
->cyclicSucc())
412 upperBound
[e2
] = piAngleFlow
;
413 lowerBound
[e2
] = piAngleFlow
;
414 if (e3
&& !m_traditional
)
421 else if (gen1
== adj
&& gen2
== adj
->cyclicSucc())
423 upperBound
[e2
] = piAngleFlow
;
424 lowerBound
[e2
] = piAngleFlow
;
425 if (e3
&& !m_traditional
)
436 //***************************************************
437 // Reset upper and lower Bounds for network arcs that
438 // correspond to edges of generalizationmerger faces
439 // and edges of expanded nodes.
446 adj
= PG
.expandAdj(v
);
447 // Get the corresponding face in the original embedding.
450 //***********************+
451 //expanded merger cages
452 if (PG
.typeOf(v
) == Graph::generalizationMerger
)
454 // Set upperBound to 0 for all edges.
455 forall_face_adj(adj
,f
)
457 //no bends on boundary (except special case following)
458 upperBound
[backAdjCor
[adj
]] = 0;
459 upperBound
[backAdjCor
[adj
->twin()]] = 0;
461 // Node w is in Network
462 node w
= networkNode
[adj
->twinNode()];
463 forall_adj_edges(e
,w
)
465 if (e
->target() == F
[f
])
467 //is this: 180 degree?
468 lowerBound
[e
] = piAngleFlow
; //traditional: 2 progressive: 0
469 upperBound
[e
] = piAngleFlow
;
472 edge aTwin
= angleTwin
[e
];
475 upperBound
[aTwin
] = 0;
476 lowerBound
[aTwin
] = 0;
478 }//if not traditional limit angle back arc
485 // Set the upper and lower bound for the first edge of
486 // the mergeexpander face to guarantee a 90 degree bend.
489 upperBound
[backAdjCor
[PG
.expandAdj(v
)]] = 1;
490 lowerBound
[backAdjCor
[PG
.expandAdj(v
)]]= 1;
494 //progressive mode: bends are in opposite direction
495 upperBound
[backAdjCor
[PG
.expandAdj(v
)->twin()]] = 1;
496 lowerBound
[backAdjCor
[PG
.expandAdj(v
)->twin()]]= 1;
499 // Set the upper and lower bound for the first node in
500 // clockwise order of the mergeexpander face to
501 // guaranty a 90 degree angle at the node in the interior
502 // and a 180 degree angle between the generalizations in the
506 if (F
[f
] == backAdjCor
[PG
.expandAdj(v
)]->target())
507 secFace
= backAdjCor
[PG
.expandAdj(v
)]->source();
508 else if (F
[f
] == backAdjCor
[PG
.expandAdj(v
)]->source())
509 secFace
= backAdjCor
[PG
.expandAdj(v
)]->target();
512 OGDF_ASSERT(false); // Edges in Network mixed up.
514 node w
= networkNode
[PG
.expandAdj(v
)->twinNode()];
518 if (adj
->theEdge()->target() == F
[f
])
520 lowerBound
[adj
->theEdge()] = 1;
521 upperBound
[adj
->theEdge()] = 1;
524 edge aTwin
= angleTwin
[adj
->theEdge()];
527 upperBound
[aTwin
] = 0;
528 lowerBound
[aTwin
] = 0;
530 }//if not traditional limit angle back arc
536 e
= adj
->cyclicSucc()->theEdge();
539 //we have two edges instead of one per face
540 adjEntry ae
= adj
->cyclicSucc();
542 if (e
->target() != secFace
)
543 //maybe we have to jump one step further
544 e
= ae
->cyclicSucc()->theEdge();
548 if (e
->target() == secFace
)
550 lowerBound
[e
] = piAngleFlow
;
551 upperBound
[e
] = piAngleFlow
;
554 edge aTwin
= angleTwin
[e
];
557 upperBound
[aTwin
] = piAngleFlow
;
558 lowerBound
[aTwin
] = piAngleFlow
;
560 }//if not traditional limit angle back arc
563 // Set the upper and lower bound for the last edge of
564 // the mergeexpander face to guarantee a 90 degree bend.
567 upperBound
[backAdjCor
[PG
.expandAdj(v
)->faceCyclePred()]] = 1;
568 lowerBound
[backAdjCor
[PG
.expandAdj(v
)->faceCyclePred()]] = 1;
572 //progressive mode: bends are in opposite direction
573 upperBound
[backAdjCor
[PG
.expandAdj(v
)->faceCyclePred()->twin()]] = 1;
574 lowerBound
[backAdjCor
[PG
.expandAdj(v
)->faceCyclePred()->twin()]] = 1;
578 // Set the upper and lower bound for the last node in
579 // clockwise order of the mergeexpander face to
580 // guaranty a 90 degree angle at the node in the interior
581 // and a 180 degree angle between the generalizations in the
583 if (F
[f
] == backAdjCor
[PG
.expandAdj(v
)->faceCyclePred()]->target())
584 secFace
= backAdjCor
[PG
.expandAdj(v
)->faceCyclePred()]->source();
585 else if (F
[f
] == backAdjCor
[PG
.expandAdj(v
)->faceCyclePred()]->source())
586 secFace
= backAdjCor
[PG
.expandAdj(v
)->faceCyclePred()]->target();
589 OGDF_ASSERT(false); // Edges in Network mixed up.
591 w
= networkNode
[PG
.expandAdj(v
)->faceCyclePred()->theNode()];
595 if (adj
->theEdge()->target() == F
[f
])
597 lowerBound
[adj
->theEdge()] = 1;
598 upperBound
[adj
->theEdge()] = 1;
601 edge aTwin
= angleTwin
[adj
->theEdge()];
604 upperBound
[aTwin
] = 0;
605 lowerBound
[aTwin
] = 0;
607 }//if not traditional limit angle back arc
613 e
= adj
->cyclicPred()->theEdge();
616 //we have two edges instead of one per face
617 adjEntry ae
= adj
->cyclicPred();
619 if (e
->target() != secFace
)
620 //maybe we have to jump one step further
621 e
= ae
->cyclicPred()->theEdge();
625 if (e
->target() == secFace
)
627 lowerBound
[e
] = piAngleFlow
;
628 upperBound
[e
] = piAngleFlow
;
631 edge aTwin
= angleTwin
[e
];
634 upperBound
[aTwin
] = piAngleFlow
;
635 lowerBound
[aTwin
] = piAngleFlow
;
637 }//if not traditional limit angle back arc
642 //**************************
643 //expanded high degree cages
644 else if (PG
.typeOf(v
) == Graph::highDegreeExpander
)
646 // Set upperBound to 1 for all edges, allowing maximal one
648 // Set upperBound to 0 for the corresponding entering edge
649 // allowing no 270 degree bend.
650 // Set upperbound to 1 for every edge corresponding to the
651 // angle of a vertex. This permitts 270 degree angles in
654 adjEntry splitter
= 0;
657 //assure that edges are only spread around the sides if not too
658 //many multi edges are aligned
660 //************************
661 //count multiedges at node
663 AdjEntryArray
<bool> isMulti(PG
, false);
666 //if all edges are multi edges, find a 360 degree position
667 bool allMulti
= true;
668 forall_face_adj(adj
, f
) //this double iteration slows the algorithm down
670 //no facesplitter in attributedgraph
671 //if (!PG.faceSplitter(adj->theEdge()))
673 adjEntry srcadj
= adj
->cyclicPred();
674 adjEntry tgtadj
= adj
->twin()->cyclicSucc();
675 //check if the nodes are expanded
677 if (PG
.expandedNode(srcadj
->twinNode()))
678 vt1
= PG
.expandedNode(srcadj
->twinNode());
679 else vt1
= srcadj
->twinNode();
680 if (PG
.expandedNode(tgtadj
->twinNode()))
681 vt2
= PG
.expandedNode(tgtadj
->twinNode());
682 else vt2
= tgtadj
->twinNode();
685 //we forbid bends between two incident multiedges
688 lowerBound
[backAdjCor
[adj
]] = upperBound
[backAdjCor
[adj
]] = 0;
693 lowerBound
[backAdjCor
[adj
->twin()]] =
694 lowerBound
[backAdjCor
[adj
]] =
695 upperBound
[backAdjCor
[adj
]] =
696 upperBound
[backAdjCor
[adj
->twin()]] = 0;
697 isMulti
[adj
->twin()] = true;
701 else allMulti
= false;
704 }//forallfaceadj count multis
705 //multi edge correction: only multi edges => one edge needs 360 degree
708 //find an edge that allows 360 degree without bends
709 bool twoNodeCC
= true; //no foreign non-multi edge to check for
710 forall_face_adj(adj
, f
)
712 //now check for expanded nodes
713 adjEntry adjOut
= adj
->cyclicPred(); //outgoing edge entry
714 node vOpp
= adjOut
->twinNode();
715 if (PG
.expandedNode(vOpp
))
717 adjOut
= adjOut
->faceCycleSucc(); //on expanded boundary
718 //does not end on self loops
720 if (PG
.expandedNode(vStop
)) vStop
= PG
.expandedNode(vStop
);
721 while (PG
.expandedNode(adjOut
->twinNode()) == vStop
)
722 //we are still on vOpps cage
723 adjOut
= adjOut
->faceCycleSucc();
725 //now adjOut is either a "foreign" edge or one of the
726 //original multi edges if two-node-CC
727 //adjEntry testadj = adjCor[e]->faceCycleSucc()->twin();
728 adjEntry testAdj
= adjOut
->twin();
729 node vBack
= testAdj
->theNode();
730 if (PG
.expandedNode(vBack
))
732 vBack
= PG
.expandedNode(vBack
);
734 if (vBack
!= v
) //v is expanded node
736 //dont use iteration result, set firstedge!
737 upperBound
[backAdjCor
[adj
]] = 4; //4 bends for 360
742 //if only two nodes with multiedges are in current CC,
743 //assign 360 degree to first edge
746 //it would be difficult to guarantee that the networkedge
747 //on the other side of the face would get the 360, so alllow
748 //360 for all edges or search for the outer face
750 forall_face_adj(adj
, f
)
752 adjEntry ae
= adj
->cyclicPred();
753 if (adjF
[ae
] == E
.externalFace())
755 upperBound
[backAdjCor
[adj
]] = 4; //4 bends for 360
758 }//forall expansion adj
761 //End multi edge correction
765 //**********************
766 //now set the upper Bounds
767 forall_face_adj(adj
,f
)
769 //should be: no 270 degrees
771 upperBound
[backAdjCor
[adj
->twin()]] = 0;
773 upperBound
[backAdjCor
[adj
]] = 0;
775 //if (false)//(PG.faceSplitter(adj->theEdge()))
777 // // No bends allowed on the face splitter
778 // upperBound[backAdjCor[adj]] = 0;
781 // //progressive??? sollte sein:
782 // upperBound[backAdjCor[adj->twin()]] = 0;
788 // //should be: only one bend
791 if (m_distributeEdges
)
793 //maybe we should change this to setting the lower bound too,
794 //depending on the degree (<= 4 => deg 90)
796 //check the special case degree >=4 with 2
797 // generalizations following each other if degree
798 // > 4, only 90 degree allowed, nodeType high
799 // bloed, da nicht original
800 //if (nodeType[ networkNode[adj->twinNode()] ] == high)
801 //hopefully size is original degree
804 if (!isMulti
[adj
]) //m_multiAlign???
806 //check if original node degree minus multi edges
808 //Attention: There are some lowerBounds > 1
810 int oldBound
= upperBound
[backAdjCor
[adj
]];
812 if ((!genshift
[v
]) && (f
->size()-multis
>3))
813 upperBound
[backAdjCor
[adj
]] =
814 //max(2, lowerBound[backAdjCor[adj]]);
815 //due to mincostflowreinelt errors, we are not
816 //allowed to set ub 1
817 max(1, lowerBound
[backAdjCor
[adj
]]);
818 else upperBound
[backAdjCor
[adj
]] =
819 max(2, lowerBound
[backAdjCor
[adj
]]);
820 //nur zum Testen der Faelle
821 OGDF_ASSERT(oldBound
>= upperBound
[backAdjCor
[adj
]]);
826 //preliminary set the bound in all cases
830 //Attention: There are some lowerBounds > 1
832 if ((!genshift
[v
]) && (f
->size()-multis
>3))
833 upperBound
[backAdjCor
[adj
->twin()]] =
834 max(1, lowerBound
[backAdjCor
[adj
->twin()]]);
835 else upperBound
[backAdjCor
[adj
->twin()]] =
836 max(2, lowerBound
[backAdjCor
[adj
->twin()]]);
842 }// else no face splitter
844 // Node w is in Network
845 node w
= networkNode
[adj
->twinNode()];
847 // if (w && !(m_traditional && m_fourPlanar && (w->degree() != 4)))
849 //should be: inner face angles set to 180
850 forall_adj_edges(e
,w
)
852 if (e
->target() == F
[f
])
854 upperBound
[e
] = piAngleFlow
;
855 lowerBound
[e
] = piAngleFlow
;
860 upperBound
[angleTwin
[e
]] = piAngleFlow
;
861 lowerBound
[angleTwin
[e
]] = piAngleFlow
;
863 }//if progressive mode
869 //********************************************************
870 // In case a face splitter was used, we need to update the
871 // second face of the cage.
875 adj
= splitter
->twin();
876 // Get the corresponding face in the original embedding.
879 forall_face_adj(adj
,f2
)
881 if (adj
== splitter
->twin())
885 upperBound
[backAdjCor
[adj
->twin()]] = 0;
886 else //progressive bends are in opposite direction
887 upperBound
[backAdjCor
[adj
]] = 0;
889 // Node w is in Network
890 node w
= networkNode
[adj
->twinNode()];
891 //if (w && !(m_traditional && m_fourPlanar && (w->degree() != 4)))
893 forall_adj_edges(e
,w
)
895 if (e
->target() == F
[f2
])
897 upperBound
[e
] = piAngleFlow
;
898 lowerBound
[e
] = piAngleFlow
;
903 upperBound
[angleTwin
[e
]] = piAngleFlow
;
904 lowerBound
[angleTwin
[e
]] = piAngleFlow
;
906 }//if progressive mode
908 }//forall adjacent edges
918 //*********************************************
919 //non-expanded (low degree) nodes
920 //check for alignment and for multi edges
921 //*********************************************
923 //check for multi edges and decrease lowerbound if align
928 node w
= networkNode
[v
];
929 if ((nodeType
[w
] != low
) || (w
->degree()<2)) continue;
931 bool allMulti
= true;
932 forall_adj_edges(e
,w
)
934 lowerb
+= max(lowerBound
[e
], 0);
936 OGDF_ASSERT((!m_traditional
) || (e
->source() == w
));
937 if (m_traditional
&& (e
->source() != w
)) OGDF_THROW(AlgorithmFailureException
);
938 if (e
->source() != w
) continue; //dont treat back angle edges
940 if (m_multiAlign
&& (v
->degree()>1))
942 adjEntry srcAdj
= adjCor
[e
];
943 adjEntry tgtAdj
= adjCor
[e
]->faceCyclePred();
945 //check if the nodes are expanded
947 if (PG
.expandedNode(srcAdj
->twinNode()))
948 vt1
= PG
.expandedNode(srcAdj
->twinNode());
949 else vt1
= srcAdj
->twinNode();
951 if (PG
.expandedNode(tgtAdj
->theNode()))
952 vt2
= PG
.expandedNode(tgtAdj
->theNode());
953 else vt2
= tgtAdj
->theNode();
960 //we forbid bends between incident multi edges
962 lowerBound
[e
] = upperBound
[e
] = zeroAngleFlow
;
965 lowerBound
[angleTwin
[e
]] = upperBound
[angleTwin
[e
]]
967 }//if progressive mode
973 //to be done: only if multiedges
974 if (!genshift
[v
]) upperBound
[e
] = upperAngleFlow
;
981 if (m_multiAlign
&& allMulti
&& (v
->degree()>1))
986 //find an edge that allows 360 degree without bends
987 bool twoNodeCC
= true;
988 forall_adj_edges(e
, w
)
990 //now check for expanded nodes
991 adjEntry runAdj
= adjCor
[e
];
992 node vOpp
= runAdj
->twinNode();
995 runAdj
= runAdj
->faceCycleSucc();
996 if (PG
.expandedNode(vStop
))
999 //does not end on self loops
1000 vStop
= PG
.expandedNode(vStop
);
1001 while (PG
.expandedNode(runAdj
->twinNode()) == vStop
)
1002 //we are still on vOpps cage
1003 runAdj
= runAdj
->faceCycleSucc();
1005 //adjEntry testadj = adjCor[e]->faceCycleSucc()->twin();
1006 adjEntry testAdj
= runAdj
->twin();
1007 node vBack
= testAdj
->theNode();
1009 if (vBack
!= v
) //not same node
1011 if (PG
.expandedNode(vBack
))
1013 vBack
= PG
.expandedNode(vBack
);
1015 if (vBack
!= vStop
) //vstop !=0, not inner face in 2nodeCC
1018 OGDF_ASSERT(!PG
.expandedNode(v
)); //otherwise not angle flow
1020 upperBound
[e
] = maxAngleFlow
; //dont use iteration result, set firstedge!
1023 upperBound
[e
] = lowerBound
[e
] = lowerAngleFlow
;
1026 upperBound
[angleTwin
[e
]] = maxBackFlow
;
1027 lowerBound
[angleTwin
[e
]] = maxBackFlow
;
1035 //if only two nodes with multiedges are in current CC,
1036 //assign 360 degree to first edge
1039 //it would be difficult to guarantee that the networkedge
1040 //on the other side of the face would get the 360, so alllow
1041 //360 for all edges or search for external face
1042 forall_adj_edges(e
, w
)
1044 adjEntry adje
= adjCor
[e
];
1045 if (adjF
[adje
] == E
.externalFace())
1048 OGDF_ASSERT(!PG
.expandedNode(v
)); //otherwise not angle flow
1050 upperBound
[e
] = maxAngleFlow
;//upperAngleFlow;
1053 upperBound
[e
] = lowerAngleFlow
;//upperAngleFlow;
1054 lowerBound
[e
] = lowerAngleFlow
;
1057 upperBound
[angleTwin
[e
]] = maxBackFlow
;
1058 lowerBound
[angleTwin
[e
]] = maxBackFlow
;
1071 //**********************************
1075 //To Be done: hier multiedges testen
1076 forall_nodes(tv
, Network
)
1078 //flowSum += supply[tv];
1080 //only check representants of original nodes, not faces
1081 if (((nodeType
[tv
] == low
) || (nodeType
[tv
] == high
)))
1083 //if node representant with degree 4, set angles preliminary
1084 //degree four nodes with two gens are expanded in PlanRepUML
1085 //all others are allowed to change the edge positions
1086 if ( (m_traditional
&& (tv
->degree() == 4)) ||
1087 ((tv
->degree() == 8) && !m_traditional
) )
1089 //three types: degree4 original nodes and facesplitter end nodes,
1091 //fixassignment tells us that low degree nodes are not allowed to
1092 //have zero degree and special nodes are already assigned
1093 bool fixAssignment
= true;
1095 //check if free assignment is possible for degree 4
1098 fixAssignment
= false;
1099 forall_adj_edges(te
, tv
)
1101 if (te
->source() == tv
)
1103 adjEntry pgEntry
= adjCor
[te
];
1104 node pgNode
= pgEntry
->theNode();
1106 if ((PG
.expandedNode(pgNode
))
1107 //|| (PG.faceSplitter(adjCor[te]->theEdge()))
1108 || (PG
.typeOf(pgNode
) == Graph::dummy
) //test crossings
1111 fixAssignment
= true;
1114 }//if no angle back arc in progressive mode
1119 //now set the angles at degree 4 nodes to distribute edges
1120 forall_adj_edges(te
, tv
)
1123 if (te
->source() == tv
)
1125 if (fixedVal
[tv
]) continue; //if already special values set
1129 lowerBound
[te
] = 0; //lowerAngleFlow maybe 1;//0;
1130 upperBound
[te
] = upperAngleFlow
;//4;
1134 //only allow 90 degree arc value
1135 lowerBound
[te
] = halfPiAngleFlow
;
1136 upperBound
[te
] = halfPiAngleFlow
;
1138 }//if no angle back arc in progressive mode
1141 if (fixedVal
[tv
]) continue; //if already special values set
1145 OGDF_ASSERT(lowerAngleFlow
== 0); //should only be in progressive mode
1146 lowerBound
[te
] = lowerAngleFlow
;
1147 upperBound
[te
] = upperBackAngleFlow
;
1151 //only allow 0-180 degree back arc value
1152 lowerBound
[te
] = 0; //1
1153 upperBound
[te
] = 0; //halfPiAngleFlow; //1
1158 int lowsum
= 0, upsum
= 0;
1159 forall_adj_edges(te
, tv
)
1161 OGDF_ASSERT(lowerBound
[te
] <= upperBound
[te
]);
1162 if (noBendEdge
[te
]) lowerBound
[te
] = 0;
1163 lowsum
+= lowerBound
[te
];
1164 upsum
+= upperBound
[te
];
1166 if (m_traditional
) {
1167 OGDF_ASSERT( (lowsum
<= supply
[tv
]) && (upsum
>= supply
[tv
]))
1169 }//if node, no faces
1171 //only for debugging: check faces
1172 forall_nodes(tv
, Network
)
1174 int lowsum
= 0, upsum
= 0;
1175 forall_adj_edges(te
, tv
)
1177 if (noBendEdge
[te
]) lowerBound
[te
] = 0;
1178 lowsum
+= lowerBound
[te
];
1179 upsum
+= upperBound
[te
];
1181 //OGDF_ASSERT( (lowsum <= supply[tv]) && (upsum >= supply[tv]));
1183 //OGDF_ASSERT(flowSum == 0);
1186 bool isFlow
= false;
1187 SList
<edge
> capacityBoundedEdges
;
1188 EdgeArray
<int> flow(Network
,0);
1190 // Set upper Bound to current upper bound.
1191 // Some edges are no longer capacitybounded, therefore save their status
1192 EdgeArray
<bool> isBounded(Network
, false);
1194 forall_edges(e
,Network
)
1196 if (upperBound
[e
] == infinity
)
1198 capacityBoundedEdges
.pushBack(e
);
1199 isBounded
[e
] = true;
1202 int currentUpperBound
;
1203 if (startBoundBendsPerEdge
> 0)
1204 currentUpperBound
= startBoundBendsPerEdge
;
1206 currentUpperBound
= 4*PG
.numberOfEdges();
1209 while ( (!isFlow
) && (currentUpperBound
<= 4*PG
.numberOfEdges()) )
1212 SListIterator
<edge
> it
;
1213 for (it
= capacityBoundedEdges
.begin(); it
.valid(); it
++)
1214 upperBound
[(*it
)] = currentUpperBound
;
1216 isFlow
= flowModule
.call(Network
,lowerBound
,upperBound
,cost
,supply
,flow
);
1222 // forall_edges(e,Network) {
1223 // fout << "e = " << e << " flow = " << flow[e];
1224 // if(nodeCor[e] == 0 && adjCor[e])
1225 // fout << " real edge = " << adjCor[e]->theEdge();
1228 // forall_edges(e,Network) {
1229 // if(nodeCor[e] == 0 && adjCor[e] != 0 && flow[e] > 0) {
1230 // fout << "Bends " << flow[e] << " on edge "
1231 // << adjCor[e]->theEdge()
1232 // << " between faces " << adjF[adjCor[e]]->index() << " - "
1233 // << adjF[adjCor[e]->twin()]->index() << endl;
1236 // forall_edges(e,Network) {
1237 // if(nodeCor[e] != 0 && faceCor[e] != 0) {
1238 // fout << "Angle " << (flow[e])*90 << "\tdegree on node "
1239 // << nodeCor[e] << " at face " << faceCor[e]->index()
1240 // << "\tbetween edge " << adjCor[e]->faceCyclePred()
1241 // << "\tand " << adjCor[e] << endl;
1244 // if (startBoundBendsPerEdge> 0) {
1245 // fout << "Minimizing edge bends for upper bound "
1246 // << currentUpperBound;
1248 // fout << " ... Successful";
1254 OGDF_ASSERT(startBoundBendsPerEdge
>= 1 || isFlow
);
1256 currentUpperBound
++;
1261 if (startBoundBendsPerEdge
&& !isFlow
)
1263 // couldn't compute reasonable shape
1264 OGDF_THROW_PARAM(AlgorithmFailureException
, afcNoFlow
);
1268 int totalNumBends
= 0;
1271 forall_edges(e
,Network
)
1274 if (nodeCor
[e
] == 0 && adjCor
[e
] != 0 && (flow
[e
] > 0) &&
1275 (angleTwin
[e
] == 0) ) //no angle edges
1277 OGDF_ASSERT(OR
.bend(adjCor
[e
]).size() == 0)
1279 char zeroChar
= (m_traditional
? '0' : '1');
1280 char oneChar
= (m_traditional
? '1' : '0');
1281 //we depend on the property that there is no flow
1282 //in opposite direction due to the cost
1283 OR
.bend(adjCor
[e
]).set(zeroChar
,flow
[e
]);
1284 OR
.bend(adjCor
[e
]->twin()).set(oneChar
,flow
[e
]);
1286 totalNumBends
+= flow
[e
];
1288 //check if bends fit bounds
1291 OGDF_ASSERT((int)OR
.bend(adjCor
[e
]).size() <= currentUpperBound
);
1292 OGDF_ASSERT((int)OR
.bend(adjCor
[e
]->twin()).size() <= currentUpperBound
);
1295 else if (nodeCor
[e
] != 0 && faceCor
[e
] != 0)
1297 if (m_traditional
) OR
.angle(adjCor
[e
]) = (flow
[e
]);
1300 OGDF_ASSERT(angleTwin
[e
] != 0);
1303 case 0: switch (flow
[angleTwin
[e
]])
1305 case 0: OR
.angle(adjCor
[e
]) = 2; break;
1306 case 1: OR
.angle(adjCor
[e
]) = 3; break;
1307 case 2: OR
.angle(adjCor
[e
]) = 4; break;
1311 case 1: switch (flow
[angleTwin
[e
]])
1313 case 0: OR
.angle(adjCor
[e
]) = 1; break;
1317 case 2: switch (flow
[angleTwin
[e
]])
1319 case 0: OR
.angle(adjCor
[e
]) = 0; break;
1331 if (int(ogdf::debugLevel
) >= int(dlHeavyChecks
))
1332 cout
<< "\n\nTotal Number of Bends : "<< totalNumBends
<< endl
<< endl
;
1337 if (OR
.check(error
) == false) {
1338 cout
<< error
<< endl
;
1346 } // end namespace ogdf