void SimpleEmbedder::call(Graph& G, adjEntry& adjExternal) { OGDF_ASSERT(isPlanar(G)); //---------------------------------------------------------- // // determine embedding of G // // We currently compute any embedding and choose the maximal face // as external face // if we use FixedEmbeddingInserterOld, we have to re-use the computed // embedding, otherwise crossing nodes can turn into "touching points" // of edges (alternatively, we could compute a new embedding and // finally "remove" such unnecessary crossings). adjExternal = nullptr; if(!G.representsCombEmbedding()) planarEmbed(G); if (G.numberOfEdges() > 0) { CombinatorialEmbedding E(G); //face fExternal = E.maximalFace(); face fExternal = findBestExternalFace(G, E); adjExternal = fExternal->firstAdj(); } }
//----------------------------------------------------------------------------- // call function: compute an UML layout for graph umlGraph //----------------------------------------------------------------------------- void PlanarizationLayoutUML::call(UMLGraph ¨Graph) { m_nCrossings = 0; if(umlGraph.constGraph().empty()) return; // check necessary preconditions preProcess(umlGraph); //--------------------------------------------------- // preprocessing: insert a merger for generalizations umlGraph.insertGenMergers(); PlanRepUML pr(umlGraph); const int numCC = pr.numberOfCCs(); // (width,height) of the layout of each connected component Array<DPoint> boundingBox(numCC); // alignment section (should not be here, because planarlayout should // not know about the meaning of layouter options and should not cope // with them), move later // we have to distinguish between cc's with and without generalizations // if the alignment option is set int l_layoutOptions = m_planarLayouter.get().getOptions(); bool l_align = ((l_layoutOptions & umlOpAlign) > 0); //end alignment section //------------------------------------------ //now planarize CCs and apply drawing module for(int i = 0; i < numCC; ++i) { //--------------------------------------- // 1. crossing minimization //--------------------------------------- // alignment: check wether gens exist, special treatment is necessary bool l_gensExist = false; // set this for all CC's, start with first gen, //this setting can be mixed among CC's without problems EdgeArray<Graph::EdgeType> savedType(pr); EdgeArray<Graph::EdgeType> savedOrigType(pr.original()); //for deleted copies EdgeArray<int> costOrig(pr.original(), 1); //edgearray for reinserter call: which edge may never be crossed? EdgeArray<bool> noCrossingEdge(pr.original(), false); edge e; forall_edges(e,pr) { edge eOrig = pr.original(e); if (pr.typeOf(e) == Graph::generalization) { if (l_align) l_gensExist = true; OGDF_ASSERT(!eOrig || !(noCrossingEdge[eOrig])); // high cost to allow alignment without crossings if (l_align && ( (eOrig && (pr.typeOf(e->target()) == Graph::generalizationMerger)) || pr.alignUpward(e->adjSource()) )) costOrig[eOrig] = 10; } } int cr; m_crossMin.get().call(pr, i, cr, &costOrig); m_nCrossings += cr; //--------------------------------------- // 2. embed resulting planar graph //--------------------------------------- // We currently compute any embedding and choose the maximal face as external face // if we use FixedEmbeddingInserter, we have to re-use the computed // embedding, otherwise crossing nodes can turn into "touching points" // of edges (alternatively, we could compute a new embedding and // finally "remove" such unnecessary crossings). if(!pr.representsCombEmbedding()) planarEmbed(pr); adjEntry adjExternal = 0; if(pr.numberOfEdges() > 0) { CombinatorialEmbedding E(pr); face fExternal = findBestExternalFace(pr,E); adjExternal = fExternal->firstAdj(); } //--------------------------------------------------------- // 3. compute layout of planarized representation //--------------------------------------------------------- Layout drawing(pr); // distinguish between CC's with/without generalizations // this changes the input layout modules options! if (l_gensExist) m_planarLayouter.get().setOptions(l_layoutOptions); else m_planarLayouter.get().setOptions((l_layoutOptions & ~umlOpAlign)); // call the Layouter for the CC's UMLGraph m_planarLayouter.get().call(pr, adjExternal, drawing); // copy layout into umlGraph // Later, we move nodes and edges in each connected component, such // that no two overlap. for(int j = pr.startNode(); j < pr.stopNode(); ++j) { node vG = pr.v(j); umlGraph.x(vG) = drawing.x(pr.copy(vG)); umlGraph.y(vG) = drawing.y(pr.copy(vG)); adjEntry adj; forall_adj(adj,vG) { if ((adj->index() & 1) == 0) continue; edge eG = adj->theEdge(); drawing.computePolylineClear(pr,eG,umlGraph.bends(eG)); } } // the width/height of the layout has been computed by the planar // layout algorithm; required as input to packing algorithm boundingBox[i] = m_planarLayouter.get().getBoundingBox(); }//for cc's