/**--------------------------------------------------- calling function taking the planar representation, the external face (adjentry), the layout to be filled, a list of non-planar edges, a list of inserted edges and the original graph as input */ void ClusterOrthoLayout::call(ClusterPlanRep &PG, adjEntry adjExternal, Layout &drawing, List<NodePair>& npEdges, List<edge>& newEdges, Graph& originalGraph) { // We don't care about UML hierarchies and therefore do not allow alignment OGDF_ASSERT(!m_align); // if we have only one vertex in PG ... if(PG.numberOfNodes() == 1) { node v1 = PG.firstNode(); node vOrig = PG.original(v1); double w = PG.widthOrig(vOrig); double h = PG.heightOrig(vOrig); drawing.x(v1) = m_margin + w/2; drawing.y(v1) = m_margin + h/2; m_boundingBox = DPoint(w + 2*m_margin, h + 2*m_margin); return; } OGDF_ASSERT(PG.representsCombEmbedding()) //------------------------- // insert cluster boundaries PG.ModelBoundaries(); OGDF_ASSERT(PG.representsCombEmbedding()) //-------------------------- // insert non-planar edges CombinatorialEmbedding* CE = new CombinatorialEmbedding(PG); if (!npEdges.empty()) { CPlanarEdgeInserter CEI; CEI.call(PG, *CE, originalGraph, npEdges, newEdges); }//if //------------------------------------------------------------ // now we set the external face, currently to the largest face adjEntry extAdj = 0; int maximum = 0; edge e, eSucc; for(e = PG.firstEdge(); e; e = eSucc) { eSucc = e->succ(); if ( PG.clusterOfEdge(e) == PG.getClusterGraph().rootCluster() ) { int asSize = CE->rightFace(e->adjSource())->size(); if ( asSize > maximum) { maximum = asSize; extAdj = e->adjSource(); } int atSize = CE->rightFace(e->adjTarget())->size(); if ( atSize > maximum) { maximum = atSize; extAdj = e->adjTarget(); } }//if root edge }//for delete CE; //returns adjEntry in rootcluster adjExternal = extAdj; OGDF_ASSERT(adjExternal != 0); //---------------------------------------------------------- //Compaction scaling: help node cages to pass by each other: //First, the layout is blown up and then shrunk again in several steps //We change the separation value and save the original value. double l_orsep = m_separation; if (m_useScalingCompaction) { double scaleFactor = double(int(1 << m_scalingSteps)); m_separation = scaleFactor*m_separation; //reduce this step by step in compaction }//if scaling //*********************************** // PHASE 1: determine orthogonal shape //------------------------------------------------------- // expand high-degree vertices and generalization mergers PG.expand(); // get combinatorial embedding CombinatorialEmbedding E(PG); E.setExternalFace(E.rightFace(adjExternal)); // orthogonal shape representation OrthoRep OR; ClusterOrthoShaper COF; //set some options COF.align(false); //cannot be used yet with clusters COF.traditional(m_orthoStyle > 0 ? false : true); //prefer 90/270 degree angles over 180/180 //bend cost depends on cluster depths avoiding unnecessary "inner" bends COF.bendCostTopDown(ClusterOrthoShaper::topDownCost); // New Call //COF.call(PG,E,OR,2); // Original call without bend bounds(still valid) COF.call(PG, E, OR); String msg; OGDF_ASSERT(OR.check(msg)) //****************************************************************** // PHASE 2: construction of a feasible drawing of the expanded graph //--------------------------- // expand low degree vertices PG.expandLowDegreeVertices(OR); OGDF_ASSERT(PG.representsCombEmbedding()); //------------------ // restore embedding E.computeFaces(); E.setExternalFace(E.rightFace(adjExternal)); OGDF_ASSERT(OR.check(msg)) //---------- //COMPACTION //-------------------------- // apply constructive compaction heuristics OR.normalize(); OR.dissect(); OR.orientate(PG,m_preferedDir); OGDF_ASSERT(OR.check(msg)) // compute cage information and routing channels OR.computeCageInfoUML(PG); //temporary grid layout GridLayoutMapped gridDrawing(PG,OR,m_separation,m_cOverhang,4); RoutingChannel<int> rcGrid(PG,gridDrawing.toGrid(m_separation),m_cOverhang); rcGrid.computeRoutingChannels(OR, m_align); node v; const OrthoRep::VertexInfoUML *pInfoExp; forall_nodes(v,PG) { pInfoExp = OR.cageInfo(v); if (pInfoExp) break; }
void OrthoLayoutUML::call(PlanRepUML &PG, adjEntry adjExternal, Layout &drawing) { // if we have only one vertex in PG ... if(PG.numberOfNodes() == 1) { node v1 = PG.firstNode(); node vOrig = PG.original(v1); double w = PG.widthOrig(vOrig); double h = PG.heightOrig(vOrig); drawing.x(v1) = m_margin + w/2; drawing.y(v1) = m_margin + h/2; m_boundingBox = DPoint(w + 2*m_margin, h + 2*m_margin); return; } //classify brother-to-brother hierarchy edges to allow alignment if (m_align) { classifyEdges(PG, adjExternal); }//if align //compaction with scaling: help node cages to pass by each other double l_orsep = m_separation; if (m_useScalingCompaction) { m_scalingSteps = 6; double scaleFactor = double(int(1 << m_scalingSteps)); m_separation = scaleFactor*m_separation; //reduce this step by step in compaction }//if scaling //*********************************** // PHASE 1: determine orthogonal shape // expand high-degree vertices and generalization mergers PG.expand(); //check preconditions, currently not necessary //assureDrawability(PG); // get combinatorial embedding CombinatorialEmbedding E(PG); E.setExternalFace(E.rightFace(adjExternal)); // determine orthogonal shape OrthoRep OR; //OrthoFormerUML OF; OrthoShaper OFG; //set some options OFG.align(m_align); //align brother objects on hierarchy levels OFG.traditional(m_orthoStyle > 0 ? false : true); //prefer 90/270 degree angles over 180/180 // New Call OFG.setBendBound(m_bendBound); OFG.call(PG,E,OR); // remove face splitter edge e, eSucc; for(e = PG.firstEdge(); e; e = eSucc) { eSucc = e->succ(); if(PG.faceSplitter(e)) { OR.angle(e->adjSource()->cyclicPred()) = 2; OR.angle(e->adjTarget()->cyclicPred()) = 2; PG.delEdge(e); } } //****************************************************************** // PHASE 2: construction of a feasible drawing of the expanded graph // expand low degree vertices PG.expandLowDegreeVertices(OR); OGDF_ASSERT(PG.representsCombEmbedding()); // restore embedding E.computeFaces(); E.setExternalFace(E.rightFace(adjExternal)); // apply constructive compaction heuristics OR.normalize(); OR.dissect2(&PG); //OR.dissect(); OR.orientate(PG,m_preferedDir); // compute cage information and routing channels OR.computeCageInfoUML(PG); // adjust value of cOverhang if(m_cOverhang < 0.05) m_cOverhang = 0.0; if(m_cOverhang > 0.5) m_cOverhang = 0.5; //temporary grid layout GridLayoutMapped gridDrawing(PG,OR,m_separation,m_cOverhang,2); RoutingChannel<int> rcGrid(PG,gridDrawing.toGrid(m_separation),m_cOverhang); rcGrid.computeRoutingChannels(OR, m_align); node v; const OrthoRep::VertexInfoUML *pInfoExp; forall_nodes(v, PG) { pInfoExp = OR.cageInfo(v); if (pInfoExp) break; }