adjEntry UpwardPlanRep::getAdjEntry(const CombinatorialEmbedding &Gamma, node v, face f) const { adjEntry adjFound = nullptr; for(adjEntry adj : v->adjEntries) { if (Gamma.rightFace(adj) == f) { adjFound = adj; break; } } OGDF_ASSERT(adjFound != nullptr); OGDF_ASSERT(Gamma.rightFace(adjFound) == f); return adjFound; }
void FixEdgeInserterCore::removeEdge(CombinatorialEmbedding &E, edge eOrig) { const List<edge> &path = m_pr.chain(eOrig); for(edge e : path) { adjEntry adj = e->adjSource(); m_delFaces->insert(E.leftFace (adj)); m_delFaces->insert(E.rightFace (adj)); } // delete all corresponding nodes in dual for(face f : m_delFaces->faces()) m_dual.delNode(m_nodeOf[f]); m_delFaces->clear(); // remove edge path from PG m_pr.removeEdgePathEmbedded(E,eOrig,*m_newFaces); // update dual // insert new nodes for(face f : m_newFaces->faces()) { m_nodeOf[f] = m_dual.newNode(); } // insert new edges into dual for(face f : m_newFaces->faces()) insertEdgesIntoDualAfterRemove(E, f); m_newFaces->clear(); }
//--------------------------------------------------------- // construct dual graph, marks dual edges corresponding to generalization // in m_primalIsGen // assumes that m_pDual, m_primalAdj and m_nodeOf are already constructed // void FixEdgeInserterUMLCore::constructDual(const CombinatorialEmbedding &E) { // insert a node in the dual graph for each face in E for(face f : E.faces) m_nodeOf[f] = m_dual.newNode(); // Insert an edge into the dual graph for each adjacency entry in E. // The edges are directed from the left face to the right face. for(node v : m_pr.nodes) { for(adjEntry adj : v->adjEdges) { node vLeft = m_nodeOf[E.leftFace (adj)]; node vRight = m_nodeOf[E.rightFace(adj)]; edge e = m_dual.newEdge(vLeft,vRight); m_primalAdj[e] = adj; // mark dual edges corresponding to generalizations if (m_pr.typeOf(adj->theEdge()) == Graph::generalization) m_primalIsGen[e] = true; } } // Augment the dual graph by two new vertices. These are used temporarily // when searching for a shortest path in the dual graph. m_vS = m_dual.newNode(); m_vT = m_dual.newNode(); }
//--------------------------------------------------------- // construct dual graph // assumes that m_pDual, m_primalAdj and m_nodeOf are already constructed // void FixEdgeInserterCore::constructDual(const CombinatorialEmbedding &E) { // insert a node in the dual graph for each face in E for(face f : E.faces) m_nodeOf[f] = m_dual.newNode(); // Insert an edge into the dual graph for each adjacency entry in E. // The edges are directed from the left face to the right face. for(node v : m_pr.nodes) { for(adjEntry adj : v->adjEdges) { // Do not insert edges into dual if crossing the original edge // is forbidden if(m_pForbidden && (*m_pForbidden)[m_pr.original(adj->theEdge())] == true) continue; node vLeft = m_nodeOf[E.leftFace (adj)]; node vRight = m_nodeOf[E.rightFace(adj)]; m_primalAdj[m_dual.newEdge(vLeft,vRight)] = adj; } } // Augment the dual graph by two new vertices. These are used temporarily // when searching for a shortest path in the dual graph. m_vS = m_dual.newNode(); m_vT = m_dual.newNode(); }
void CPlanarEdgeInserter::constructDualGraph(ClusterPlanRep& CPR, CombinatorialEmbedding& E, EdgeArray<edge>& arcRightToLeft, EdgeArray<edge>& arcLeftToRight, FaceArray<node>& nodeOfFace, //NodeArray<face>&, faceOfNode, EdgeArray<edge>& arcTwin) { //dual graph gets two arcs for each edge (in both directions) //these arcs get their status (usable for path) depending on //the edge to be reinserted m_dualGraph.clear(); //faceOfNode.init(m_dualGraph, 0); //********************************* //construct nodes //corresponding to the graphs faces face f; for (f = E.firstFace(); f; f = f->succ()) { node v = m_dualGraph.newNode(); nodeOfFace[f] = v; //faceOfNode[v] = f; } //********************************* // edge e; forall_edges(e, CPR) { edge arc1 = m_dualGraph.newEdge( nodeOfFace[E.rightFace(e->adjTarget())], nodeOfFace[E.rightFace(e->adjSource())] ); arcLeftToRight[e] = arc1; edge arc2 = m_dualGraph.newEdge( nodeOfFace[E.rightFace(e->adjSource())], nodeOfFace[E.rightFace(e->adjTarget())] ); arcRightToLeft[e] = arc2; arcTwin[arc1] = arc2; arcTwin[arc2] = arc1; m_arcOrig[arc1] = e->adjSource();//e->adjTarget(); m_arcOrig[arc2] = e->adjTarget();//e->adjSource(); }
face SimpleEmbedder::findBestExternalFace( const PlanRep& PG, const CombinatorialEmbedding& E) { FaceArray<int> weight(E); for(face f : E.faces) weight[f] = f->size(); for(node v : PG.nodes) { if(PG.typeOf(v) != Graph::generalizationMerger) continue; adjEntry adjFound = nullptr; for(adjEntry adj : v->adjEdges) { if (adj->theEdge()->source() == v) { adjFound = adj; break; } } OGDF_ASSERT(adjFound->theEdge()->source() == v); node w = adjFound->theEdge()->target(); bool isBase = true; for(adjEntry adj : w->adjEdges) { edge e = adj->theEdge(); if(e->target() != w && PG.typeOf(e) == Graph::generalization) { isBase = false; break; } } if(isBase == false) continue; face f1 = E.leftFace(adjFound); face f2 = E.rightFace(adjFound); weight[f1] += v->indeg(); if(f2 != f1) weight[f2] += v->indeg(); } face fBest = E.firstFace(); for(face f : E.faces) if(weight[f] > weight[fBest]) fBest = f; return fBest; }
void FixEdgeInserterUMLCore::insertEdgesIntoDual(const CombinatorialEmbedding &E, adjEntry adjSrc) { face f = E.rightFace(adjSrc); node vRight = m_nodeOf[f]; adjEntry adj1 = f->firstAdj(), adj = adj1; do { node vLeft = m_nodeOf[E.leftFace(adj)]; edge eLR = m_dual.newEdge(vLeft,vRight); m_primalAdj[eLR] = adj; edge eRL = m_dual.newEdge(vRight,vLeft); m_primalAdj[eRL] = adj->twin(); if(m_pr.typeOf(adj->theEdge()) == Graph::generalization) m_primalIsGen[eLR] = m_primalIsGen[eRL] = true; } while((adj = adj->faceCycleSucc()) != adj1); // the other face adjacent to *itEdge ... f = E.rightFace(adjSrc->twin()); vRight = m_nodeOf[f]; adj1 = f->firstAdj(); adj = adj1; do { node vLeft = m_nodeOf[E.leftFace(adj)]; edge eLR = m_dual.newEdge(vLeft,vRight); m_primalAdj[eLR] = adj; edge eRL = m_dual.newEdge(vRight,vLeft); m_primalAdj[eRL] = adj->twin(); if(m_pr.typeOf(adj->theEdge()) == Graph::generalization) m_primalIsGen[eLR] = m_primalIsGen[eRL] = true; } while((adj = adj->faceCycleSucc()) != adj1); }
void FixEdgeInserterCore::insertEdgesIntoDual(const CombinatorialEmbedding &E, adjEntry adjSrc) { face f = E.rightFace(adjSrc); node vRight = m_nodeOf[f]; adjEntry adj1 = f->firstAdj(), adj = adj1; do { if(m_pForbidden && (*m_pForbidden)[m_pr.original(adj->theEdge())] == true) continue; node vLeft = m_nodeOf[E.leftFace(adj)]; edge eLR = m_dual.newEdge(vLeft,vRight); m_primalAdj[eLR] = adj; edge eRL = m_dual.newEdge(vRight,vLeft); m_primalAdj[eRL] = adj->twin(); } while((adj = adj->faceCycleSucc()) != adj1); // the other face adjacent to *itEdge ... f = E.rightFace(adjSrc->twin()); vRight = m_nodeOf[f]; adj1 = f->firstAdj(); adj = adj1; do { if(m_pForbidden && (*m_pForbidden)[m_pr.original(adj->theEdge())] == true) continue; node vLeft = m_nodeOf[E.leftFace(adj)]; edge eLR = m_dual.newEdge(vLeft,vRight); m_primalAdj[eLR] = adj; edge eRL = m_dual.newEdge(vRight,vLeft); m_primalAdj[eRL] = adj->twin(); } while((adj = adj->faceCycleSucc()) != adj1); }
void FixEdgeInserterCore::insertEdge(CombinatorialEmbedding &E, edge eOrig, const SList<adjEntry> &crossed) { // remove dual nodes on insertion path SListConstIterator<adjEntry> it; for(it = crossed.begin(); it != crossed.rbegin(); ++it) { m_dual.delNode(m_nodeOf[E.rightFace(*it)]); } // update primal m_pr.insertEdgePathEmbedded(eOrig,E,crossed); // insert new face nodes into dual const List<edge> &path = m_pr.chain(eOrig); for(edge e : path) { adjEntry adj = e->adjSource(); m_nodeOf[E.leftFace (adj)] = m_dual.newNode(); m_nodeOf[E.rightFace(adj)] = m_dual.newNode(); } // insert new edges into dual for(edge e : path) insertEdgesIntoDual(E, e->adjSource()); }
face SimpleEmbedder::findBestExternalFace(const PlanRep& PG, const CombinatorialEmbedding& E) { FaceArray<int> weight(E); face f; forall_faces(f,E) weight[f] = f->size(); node v; forall_nodes(v,PG) { if(PG.typeOf(v) != Graph::generalizationMerger) continue; adjEntry adj; forall_adj(adj,v) { if(adj->theEdge()->source() == v) break; } OGDF_ASSERT(adj->theEdge()->source() == v); node w = adj->theEdge()->target(); bool isBase = true; adjEntry adj2; forall_adj(adj2, w) { edge e = adj2->theEdge(); if(e->target() != w && PG.typeOf(e) == Graph::generalization) { isBase = false; break; } } if(isBase == false) continue; face f1 = E.leftFace(adj); face f2 = E.rightFace(adj); weight[f1] += v->indeg(); if(f2 != f1) weight[f2] += v->indeg(); }
/**--------------------------------------------------- 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 FixEdgeInserterCore::findWeightedShortestPath(const CombinatorialEmbedding &E, edge eOrig, SList<adjEntry> &crossed) { node s = m_pr.copy(eOrig->source()); node t = m_pr.copy(eOrig->target()); OGDF_ASSERT(s != t); int eSubgraph = (m_pSubgraph != nullptr) ? (*m_pSubgraph)[eOrig] : 0; EdgeArray<int> costDual(m_dual, 0); int maxCost = 0; for(edge eDual : m_dual.edges) { int c = getCost(m_primalAdj[eDual]->theEdge(), eSubgraph); costDual[eDual] = c; if (c > maxCost) maxCost = c; } ++maxCost; Array<SListPure<edge> > nodesAtDist(maxCost); NodeArray<edge> spPred(m_dual,nullptr); int oldIdCount = m_dual.maxEdgeIndex(); // augment dual by edges from s to all adjacent faces of s ... for(adjEntry adj : s->adjEdges) { // starting edges of bfs-search are all edges leaving s edge eDual = m_dual.newEdge(m_vS, m_nodeOf[E.rightFace(adj)]); m_primalAdj[eDual] = adj; nodesAtDist[0].pushBack(eDual); } // ... and from all adjacent faces of t to t for(adjEntry adj : t->adjEdges) { edge eDual = m_dual.newEdge(m_nodeOf[E.rightFace(adj)], m_vT); m_primalAdj[eDual] = adj; } // actual search (using extended bfs on directed dual) int currentDist = 0; for( ; ; ) { // next candidate edge while(nodesAtDist[currentDist % maxCost].empty()) ++currentDist; edge eCand = nodesAtDist[currentDist % maxCost].popFrontRet(); node v = eCand->target(); // leads to an unvisited node? if (spPred[v] == nullptr) { // yes, then we set v's predecessor in search tree spPred[v] = eCand; // have we reached t ... if (v == m_vT) { // ... then search is done. // constructed list of used edges (translated to crossed // adjacency entries in PG) from t back to s (including first // and last!) do { edge eDual = spPred[v]; crossed.pushFront(m_primalAdj[eDual]); v = eDual->source(); } while(v != m_vS); break; } // append next candidate edges to queue (all edges leaving v) appendCandidates(nodesAtDist, costDual, maxCost, v, currentDist); } } // remove augmented edges again adjEntry adj; while ((adj = m_vS->firstAdj()) != nullptr) m_dual.delEdge(adj->theEdge()); while ((adj = m_vT->firstAdj()) != nullptr) m_dual.delEdge(adj->theEdge()); m_dual.resetEdgeIdCount(oldIdCount); }
void FixEdgeInserterCore::findShortestPath(const CombinatorialEmbedding &E, edge eOrig, SList<adjEntry> &crossed) { node s = m_pr.copy(eOrig->source()); node t = m_pr.copy(eOrig->target()); OGDF_ASSERT(s != t); NodeArray<edge> spPred(m_dual,nullptr); QueuePure<edge> queue; int oldIdCount = m_dual.maxEdgeIndex(); // augment dual by edges from s to all adjacent faces of s ... for(adjEntry adj : s->adjEdges) { // starting edges of bfs-search are all edges leaving s edge eDual = m_dual.newEdge(m_vS, m_nodeOf[E.rightFace(adj)]); m_primalAdj[eDual] = adj; queue.append(eDual); } // ... and from all adjacent faces of t to t for(adjEntry adj : t->adjEdges) { edge eDual = m_dual.newEdge(m_nodeOf[E.rightFace(adj)], m_vT); m_primalAdj[eDual] = adj; } // actual search (using bfs on directed dual) for( ; ;) { // next candidate edge edge eCand = queue.pop(); node v = eCand->target(); // leads to an unvisited node? if (spPred[v] == nullptr) { // yes, then we set v's predecessor in search tree spPred[v] = eCand; // have we reached t ... if (v == m_vT) { // ... then search is done. // constructed list of used edges (translated to crossed // adjacency entries in PG) from t back to s (including first // and last!) do { edge eDual = spPred[v]; crossed.pushFront(m_primalAdj[eDual]); v = eDual->source(); } while(v != m_vS); break; } // append next candidate edges to queue (all edges leaving v) appendCandidates(queue, v); } } // remove augmented edges again adjEntry adj; while ((adj = m_vS->firstAdj()) != nullptr) m_dual.delEdge(adj->theEdge()); while ((adj = m_vT->firstAdj()) != nullptr) m_dual.delEdge(adj->theEdge()); m_dual.resetEdgeIdCount(oldIdCount); }