bool FeasibleUpwardPlanarSubgraph::constructMergeGraph( GraphCopy &M, adjEntry adj_orig, const List<edge> &orig_edges) { CombinatorialEmbedding Beta(M); //set ext. face of Beta adjEntry ext_adj = M.copy(adj_orig->theEdge())->adjSource(); Beta.setExternalFace(Beta.rightFace(ext_adj)); FaceSinkGraph fsg(Beta, M.copy(adj_orig->theNode())); SList<node> aug_nodes; SList<edge> aug_edges; SList<face> fList; fsg.possibleExternalFaces(fList); // use this method to call the methode checkForest() node v_ext = fsg.faceNodeOf(Beta.externalFace()); OGDF_ASSERT(v_ext != 0); fsg.stAugmentation(v_ext, M, aug_nodes, aug_edges); //add the deleted edges for(edge eOrig: orig_edges) { node a = M.copy(eOrig->source()); node b = M.copy(eOrig->target()); M.newEdge(a, b); } return (isAcyclic(M)); }
void UpwardPlanRep::initMe() { m_Gamma.init(*this); isAugmented = false; FaceSinkGraph fsg(m_Gamma, s_hat); SList<face> extFaces; fsg.possibleExternalFaces(extFaces); OGDF_ASSERT(!extFaces.empty()); face f_ext = nullptr; for(face f : extFaces) { if (f_ext == nullptr) f_ext = f; else { if (f_ext->size() < f->size()) f_ext = f; } } m_Gamma.setExternalFace(f_ext); for(adjEntry adj : s_hat->adjEntries) { if (m_Gamma.rightFace(adj) == m_Gamma.externalFace()) { extFaceHandle = adj; break; } } computeSinkSwitches(); }
Module::ReturnType FeasibleUpwardPlanarSubgraph::call( const Graph &G, GraphCopy &FUPS, adjEntry &extFaceHandle, List<edge> &delEdges, bool multisources) { FUPS = GraphCopy(G); delEdges.clear(); node s_orig; hasSingleSource(G, s_orig); List<edge> nonTreeEdges_orig; getSpanTree(FUPS, nonTreeEdges_orig, true, multisources); CombinatorialEmbedding Gamma(FUPS); nonTreeEdges_orig.permute(); // random order //insert nonTreeEdges while (!nonTreeEdges_orig.empty()) { // make identical copy GC of Fups //and insert e_orig in GC GraphCopy GC = FUPS; edge e_orig = nonTreeEdges_orig.popFrontRet(); //node a = GC.copy(e_orig->source()); //node b = GC.copy(e_orig->target()); GC.newEdge(e_orig); if (UpwardPlanarity::upwardPlanarEmbed_singleSource(GC)) { //upward embedded the fups and check feasibility CombinatorialEmbedding Beta(GC); //choose a arbitrary feasibel ext. face FaceSinkGraph fsg(Beta, GC.copy(s_orig)); SList<face> ext_faces; fsg.possibleExternalFaces(ext_faces); OGDF_ASSERT(!ext_faces.empty()); Beta.setExternalFace(ext_faces.front()); GraphCopy M = GC; // use a identical copy of GC to constrcut the merge graph of GC adjEntry extFaceHandle_cur = getAdjEntry(Beta, GC.copy(s_orig), Beta.externalFace()); adjEntry adj_orig = GC.original(extFaceHandle_cur->theEdge())->adjSource(); if (constructMergeGraph(M, adj_orig, nonTreeEdges_orig)) { FUPS = GC; extFaceHandle = FUPS.copy(GC.original(extFaceHandle_cur->theEdge()))->adjSource(); continue; } else { //Beta is not feasible delEdges.pushBack(e_orig); } } else { // not ok, GC is not feasible delEdges.pushBack(e_orig); } } return Module::retFeasible; }
void UpwardPlanRep::computeSinkSwitches() { OGDF_ASSERT(m_Gamma.externalFace() != nullptr); if (s_hat == nullptr) hasSingleSource(*this, s_hat); FaceSinkGraph fsg(m_Gamma, s_hat); List<adjEntry> dummyList; FaceArray< List<adjEntry> > sinkSwitches(m_Gamma, dummyList); fsg.sinkSwitches(sinkSwitches); m_sinkSwitchOf.init(*this, nullptr); for(face f : m_Gamma.faces) { List<adjEntry> switches = sinkSwitches[f]; ListIterator<adjEntry> it = switches.begin(); for (it = it.succ(); it.valid(); ++it) { m_sinkSwitchOf[(*it)->theNode()] = (*it); } } }
void FUPSSimple::computeFUPS(UpwardPlanRep &UPR, List<edge> &delEdges) { const Graph &G = UPR.original(); GraphCopy FUPS(G); node s_orig; hasSingleSource(G, s_orig); List<edge> nonTreeEdges_orig; bool random = (m_nRuns != 0); getSpanTree(FUPS, nonTreeEdges_orig, random); CombinatorialEmbedding Gamma(FUPS); if (random) nonTreeEdges_orig.permute(); // random order adjEntry extFaceHandle = nullptr; //insert nonTreeEdges while (!nonTreeEdges_orig.empty()) { /* //------------------------------------debug GraphAttributes AG(FUPS, GraphAttributes::nodeGraphics| GraphAttributes::edgeGraphics| GraphAttributes::nodeColor| GraphAttributes::edgeColor| GraphAttributes::nodeLabel| GraphAttributes::edgeLabel ); // label the nodes with their index for(node v : AG.constGraph().nodes) { AG.label(v) = to_string(v->index()); } AG.writeGML("c:/temp/spannTree.gml"); */ // make identical copy FUPSCopy of FUPS //and insert e_orig in FUPSCopy GraphCopy FUPSCopy((const GraphCopy &) FUPS); edge e_orig = nonTreeEdges_orig.popFrontRet(); FUPSCopy.newEdge(e_orig); if (UpwardPlanarity::upwardPlanarEmbed_singleSource(FUPSCopy)) { //upward embedded the fups and check feasibility CombinatorialEmbedding Beta(FUPSCopy); //choose a arbitrary feasibel ext. face FaceSinkGraph fsg(Beta, FUPSCopy.copy(s_orig)); SList<face> ext_faces; fsg.possibleExternalFaces(ext_faces); OGDF_ASSERT(!ext_faces.empty()); Beta.setExternalFace(ext_faces.front()); #if 0 //*************************** debug ******************************** cout << endl << "FUPS : " << endl; for(face ff : Beta.faces) { cout << "face " << ff->index() << ": "; adjEntry adjNext = ff->firstAdj(); do { cout << adjNext->theEdge() << "; "; adjNext = adjNext->faceCycleSucc(); } while(adjNext != ff->firstAdj()); cout << endl; } if (Beta.externalFace() != 0) cout << "ext. face of the graph is: " << Beta.externalFace()->index() << endl; else cout << "no ext. face set." << endl; #endif GraphCopy M((const GraphCopy &) FUPSCopy); // use a identical copy of FUPSCopy to construct the merge graph of FUPSCopy adjEntry extFaceHandle_cur = getAdjEntry(Beta, FUPSCopy.copy(s_orig), Beta.externalFace()); adjEntry adj_orig = FUPSCopy.original(extFaceHandle_cur->theEdge())->adjSource(); List<edge> missingEdges = nonTreeEdges_orig, listTmp = delEdges; missingEdges.conc(listTmp); if (constructMergeGraph(M, adj_orig, missingEdges)) { FUPS = FUPSCopy; extFaceHandle = FUPS.copy(FUPSCopy.original(extFaceHandle_cur->theEdge()))->adjSource(); continue; } else { //Beta is not feasible delEdges.pushBack(e_orig); } } else { // not ok, GC is not feasible delEdges.pushBack(e_orig); } } UpwardPlanRep fups_tmp (FUPS, extFaceHandle); UPR = fups_tmp; }
bool FUPSSimple::constructMergeGraph(GraphCopy &M, adjEntry adj_orig, const List<edge> &orig_edges) { CombinatorialEmbedding Beta(M); //set ext. face of Beta adjEntry ext_adj = M.copy(adj_orig->theEdge())->adjSource(); Beta.setExternalFace(Beta.rightFace(ext_adj)); //*************************** debug ******************************** /* cout << endl << "FUPS : " << endl; for(face ff : Beta.faces) { cout << "face " << ff->index() << ": "; adjEntry adjNext = ff->firstAdj(); do { cout << adjNext->theEdge() << "; "; adjNext = adjNext->faceCycleSucc(); } while(adjNext != ff->firstAdj()); cout << endl; } if (Beta.externalFace() != 0) cout << "ext. face of the graph is: " << Beta.externalFace()->index() << endl; else cout << "no ext. face set." << endl; */ FaceSinkGraph fsg(Beta, M.copy(adj_orig->theNode())); SList<node> aug_nodes; SList<edge> aug_edges; SList<face> fList; fsg.possibleExternalFaces(fList); // use this method to call the methode checkForest() node v_ext = fsg.faceNodeOf(Beta.externalFace()); OGDF_ASSERT(v_ext != 0); fsg.stAugmentation(v_ext, M, aug_nodes, aug_edges); /* //------------------------------------debug GraphAttributes AG(M, GraphAttributes::nodeGraphics| GraphAttributes::edgeGraphics| GraphAttributes::nodeColor| GraphAttributes::edgeColor| GraphAttributes::nodeLabel| GraphAttributes::edgeLabel ); // label the nodes with their index for(node v : AG.constGraph().nodes) { AG.label(v) = to_string(v->index()); } AG.writeGML("c:/temp/MergeFUPS.gml"); */ OGDF_ASSERT(isStGraph(M)); //add the deleted edges for(edge eOrig : orig_edges) { node a = M.copy(eOrig->source()); node b = M.copy(eOrig->target()); M.newEdge(a, b); } return (isAcyclic(M)); }
Module::ReturnType SubgraphUpwardPlanarizer::doCall(UpwardPlanRep &UPR, const EdgeArray<int> &cost, const EdgeArray<bool> &forbid) { const Graph &G = UPR.original(); GraphCopy GC(G); //reverse some edges in order to obtain a DAG List<edge> feedBackArcSet; m_acyclicMod.get().call(GC, feedBackArcSet); for(edge e : feedBackArcSet) { GC.reverseEdge(e); } OGDF_ASSERT(isSimple(G)); //mapping cost EdgeArray<int> cost_GC(GC); for(edge e : GC.edges) { if (forbid[GC.original(e)]) cost_GC[e] = numeric_limits<int>::max(); else cost_GC[e] = cost[GC.original(e)]; } // tranform to single source graph by adding a super source s_hat and connect it with the other sources EdgeArray<bool> sourceArcs(GC, false); node s_hat = GC.newNode(); for(node v : GC.nodes) { if (v->indeg() == 0 && v != s_hat) { edge e_tmp = GC.newEdge(s_hat, v); cost_GC[e_tmp] = 0; // crossings source arcs cause not cost sourceArcs[e_tmp] = true; } } /* //------------------------------------------------debug GraphAttributes AG_GC(GC, GraphAttributes::nodeGraphics| GraphAttributes::edgeGraphics| GraphAttributes::nodeColor| GraphAttributes::edgeColor| GraphAttributes::nodeLabel| GraphAttributes::edgeLabel ); AG_GC.setAllHeight(30.0); AG_GC.setAllWidth(30.0); for(node z : AG_GC.constGraph().nodes) { AG_GC.label(z) = to_string(z->index()); } AG_GC.writeGML("c:/temp/GC.gml"); // --------------------------------------------end debug */ BCTree BC(GC); const Graph &bcTree = BC.bcTree(); GraphCopy G_dummy; G_dummy.createEmpty(G); NodeArray<GraphCopy> biComps(bcTree, G_dummy); // bicomps of G; init with an empty graph UpwardPlanRep UPR_dummy; UPR_dummy.createEmpty(G); NodeArray<UpwardPlanRep> uprs(bcTree, UPR_dummy); // the upward planarized representation of the bicomps; init with an empty UpwarPlanRep constructComponentGraphs(BC, biComps); for(node v : bcTree.nodes) { if (BC.typeOfBNode(v) == BCTree::CComp) continue; GraphCopy &block = biComps[v]; OGDF_ASSERT(m_subgraph.valid()); // construct a super source for this block node s, s_block; hasSingleSource(block, s); s_block = block.newNode(); block.newEdge(s_block, s); //connect s UpwardPlanRep bestUPR; //upward planarize if not upward planar if (!UpwardPlanarity::upwardPlanarEmbed_singleSource(block)) { for (int i = 0; i < m_runs; i++) {// i multistarts UpwardPlanRep UPR_tmp; UPR_tmp.createEmpty(block); List<edge> delEdges; m_subgraph.get().call(UPR_tmp, delEdges); OGDF_ASSERT( isSimple(UPR_tmp) ); UPR_tmp.augment(); //mark the source arcs of block UPR_tmp.m_isSourceArc[UPR_tmp.copy(s_block->firstAdj()->theEdge())] = true; for (adjEntry adj_tmp : UPR_tmp.copy(s_block->firstAdj()->theEdge()->target())->adjEntries) { edge e_tmp = UPR_tmp.original(adj_tmp->theEdge()); if (e_tmp != nullptr && block.original(e_tmp) != nullptr && sourceArcs[block.original(e_tmp)]) UPR_tmp.m_isSourceArc[adj_tmp->theEdge()] = true; } //assign "crossing cost" EdgeArray<int> cost_Block(block); for (edge e : block.edges) { if (block.original(e) == nullptr || GC.original(block.original(e)) == nullptr) cost_Block[e] = 0; else cost_Block[e] = cost_GC[block.original(e)]; } /* if (false) { //---------------------------------------------------debug LayerBasedUPRLayout uprLayout; UpwardPlanRep upr_bug(UPR_tmp.getEmbedding()); adjEntry adj_bug = upr_bug.getAdjEntry(upr_bug.getEmbedding(), upr_bug.getSuperSource(), upr_bug.getEmbedding().externalFace()); node s_upr_bug = upr_bug.newNode(); upr_bug.getEmbedding().splitFace(s_upr_bug, adj_bug); upr_bug.m_isSourceArc.init(upr_bug, false); upr_bug.m_isSourceArc[s_upr_bug->firstAdj()->theEdge()] = true; upr_bug.s_hat = s_upr_bug; upr_bug.augment(); GraphAttributes GA_UPR_tmp(UPR_tmp, GraphAttributes::nodeGraphics| GraphAttributes::edgeGraphics| GraphAttributes::nodeColor| GraphAttributes::edgeColor| GraphAttributes::nodeLabel| GraphAttributes::edgeLabel ); GA_UPR_tmp.setAllHeight(30.0); GA_UPR_tmp.setAllWidth(30.0); uprLayout.call(upr_bug, GA_UPR_tmp); // label the nodes with their index for(node z : GA_UPR_tmp.constGraph().nodes) { GA_UPR_tmp.label(z) = to_string(z->index()); GA_UPR_tmp.y(z)=-GA_UPR_tmp.y(z); GA_UPR_tmp.x(z)=-GA_UPR_tmp.x(z); } for(edge eee : GA_UPR_tmp.constGraph().edges) { DPolyline &line = GA_UPR_tmp.bends(eee); ListIterator<DPoint> it; for(it = line.begin(); it.valid(); it++) { (*it).m_y = -(*it).m_y; (*it).m_x = -(*it).m_x; } } GA_UPR_tmp.writeGML("c:/temp/UPR_tmp_fups.gml"); cout << "UPR_tmp/fups faces:"; UPR_tmp.outputFaces(UPR_tmp.getEmbedding()); //end -----------------------------------------------debug } */ delEdges.permute(); m_inserter.get().call(UPR_tmp, cost_Block, delEdges); if (i != 0) { if (UPR_tmp.numberOfCrossings() < bestUPR.numberOfCrossings()) { //cout << endl << "new cr_nr:" << UPR_tmp.numberOfCrossings() << " old cr_nr : " << bestUPR.numberOfCrossings() << endl; bestUPR = UPR_tmp; } } else bestUPR = UPR_tmp; }//for } else { //block is upward planar CombinatorialEmbedding Gamma(block); FaceSinkGraph fsg((const CombinatorialEmbedding &) Gamma, s_block); SList<face> faceList; fsg.possibleExternalFaces(faceList); Gamma.setExternalFace(faceList.front()); UpwardPlanRep UPR_tmp(Gamma); UPR_tmp.augment(); //mark the source arcs of block UPR_tmp.m_isSourceArc[UPR_tmp.copy(s->firstAdj()->theEdge())] = true; for (adjEntry adj_tmp : UPR_tmp.copy(s->firstAdj()->theEdge()->target())->adjEntries) { edge e_tmp = UPR_tmp.original(adj_tmp->theEdge()); if (e_tmp != nullptr && block.original(e_tmp) != nullptr && sourceArcs[block.original(e_tmp)]) UPR_tmp.m_isSourceArc[adj_tmp->theEdge()] = true; } bestUPR = UPR_tmp; /* //debug //---------------------------------------------------debug GraphAttributes GA_UPR_tmp(UPR_tmp, GraphAttributes::nodeGraphics| GraphAttributes::edgeGraphics| GraphAttributes::nodeColor| GraphAttributes::edgeColor| GraphAttributes::nodeLabel| GraphAttributes::edgeLabel ); GA_UPR_tmp.setAllHeight(30.0); GA_UPR_tmp.setAllWidth(30.0); // label the nodes with their index for(node z : GA_UPR_tmp.constGraph().nodes) { GA_UPR_tmp.label(z) = to_string(z->index()); GA_UPR_tmp.y(z)=-GA_UPR_tmp.y(z); GA_UPR_tmp.x(z)=-GA_UPR_tmp.x(z); } for(edge eee : GA_UPR_tmp.constGraph().edges) { DPolyline &line = GA_UPR_tmp.bends(eee); ListIterator<DPoint> it; for(it = line.begin(); it.valid(); it++) { (*it).m_y = -(*it).m_y; (*it).m_x = -(*it).m_x; } } GA_UPR_tmp.writeGML("c:/temp/UPR_tmp_fups.gml"); cout << "UPR_tmp/fups faces:"; UPR_tmp.outputFaces(UPR_tmp.getEmbedding()); //end -----------------------------------------------debug */ } uprs[v] = bestUPR; } // compute the number of crossings int nr_cr = 0; for(node v : bcTree.nodes) { if (BC.typeOfBNode(v) != BCTree::CComp) nr_cr = nr_cr + uprs[v].numberOfCrossings(); } //merge all component to a graph node parent_BC = BC.bcproper(s_hat); NodeArray<bool> nodesDone(bcTree, false); dfsMerge(GC, BC, biComps, uprs, UPR, nullptr, parent_BC, nodesDone); // start with the component which contains the super source s_hat //augment to single sink graph UPR.augment(); //set crossings UPR.crossings = nr_cr; //------------------------------------------------debug /* LayerBasedUPRLayout uprLayout; UpwardPlanRep upr_bug(UPR.getEmbedding()); adjEntry adj_bug = upr_bug.getAdjEntry(upr_bug.getEmbedding(), upr_bug.getSuperSource(), upr_bug.getEmbedding().externalFace()); node s_upr_bug = upr_bug.newNode(); upr_bug.getEmbedding().splitFace(s_upr_bug, adj_bug); upr_bug.m_isSourceArc.init(upr_bug, false); upr_bug.m_isSourceArc[s_upr_bug->firstAdj()->theEdge()] = true; upr_bug.s_hat = s_upr_bug; upr_bug.augment(); GraphAttributes AG(UPR, GraphAttributes::nodeGraphics| GraphAttributes::edgeGraphics| GraphAttributes::nodeColor| GraphAttributes::edgeColor| GraphAttributes::nodeLabel| GraphAttributes::edgeLabel ); AG.setAllHeight(30.0); AG.setAllWidth(30.0); uprLayout.call(upr_bug, AG); for(node v : AG.constGraph().nodes) { int idx; idx = v->index(); if (UPR.original(v) != 0) idx = UPR.original(v)->index(); AG.label(v) = to_string(idx); if (UPR.isDummy(v)) AG.fillColor(v) = "#ff0000"; AG.y(v)=-AG.y(v); } // label the edges with their index for(edge e : AG.constGraph().edges) { AG.label(e) = to_string(e->index()); if (UPR.isSourceArc(e)) AG.strokeColor(e) = "#00ff00"; if (UPR.isSinkArc(e)) AG.strokeColor(e) = "#ff0000"; DPolyline &line = AG.bends(e); ListIterator<DPoint> it; for(it = line.begin(); it.valid(); it++) { (*it).m_y = -(*it).m_y; } } AG.writeGML("c:/temp/upr_res.gml"); //cout << "UPR_RES"; //UPR.outputFaces(UPR.getEmbedding()); //cout << "Mapping :" << endl; //for(node v : UPR.nodes) { // if (UPR.original(v) != 0) { // cout << "node UPR " << v << " node G " << UPR.original(v) << endl; // } //} // --------------------------------------------end debug */ OGDF_ASSERT(hasSingleSource(UPR)); OGDF_ASSERT(isSimple(UPR)); OGDF_ASSERT(isAcyclic(UPR)); OGDF_ASSERT(UpwardPlanarity::isUpwardPlanar_singleSource(UPR)); /* for(edge eee : UPR.original().edges) { if (UPR.isReversed(eee)) cout << endl << eee << endl; } */ return Module::retFeasible; }
void UpwardPlanRep::insertEdgePathEmbedded(edge eOrig, SList<adjEntry> crossedEdges, EdgeArray<int> &costOrig) { removeSinkArcs(crossedEdges); //case the copy v of eOrig->source() is a sink switch //we muss remove the sink arcs incident to v, since after inserting eOrig, v is not a sink witch node v = crossedEdges.front()->theNode(); List<edge> outEdges; if (v->outdeg() == 1) v->outEdges(outEdges); // we delete these edges later m_eCopy[eOrig].clear(); adjEntry adjSrc, adjTgt; SListConstIterator<adjEntry> it = crossedEdges.begin(); // iterate over all adjacency entries in crossedEdges except for first // and last adjSrc = *it; List<adjEntry> dirtyList; // left and right face of the element of this list are modified for(++it; it.valid() && it.succ().valid(); ++it) { adjEntry adj = *it; bool isASourceArc = false, isASinkArc = false; if (m_isSinkArc[adj->theEdge()]) isASinkArc = true; if (m_isSourceArc[adj->theEdge()]) isASourceArc = true; int c = 0; if (original(adj->theEdge()) != nullptr) c = costOrig[original(adj->theEdge())]; // split edge node u = m_Gamma.split(adj->theEdge())->source(); if (!m_isSinkArc[adj->theEdge()] && !m_isSourceArc[adj->theEdge()]) crossings = crossings + c; // crossing sink/source arcs cost nothing // determine target adjacency entry and source adjacency entry // in the next iteration step adjTgt = u->firstAdj(); adjEntry adjSrcNext = adjTgt->succ(); if (adjTgt != adj->twin()) std::swap(adjTgt, adjSrcNext); edge e_split = adjTgt->theEdge(); // the new split edge if (e_split->source() != u) e_split = adjSrcNext->theEdge(); if (isASinkArc) m_isSinkArc[e_split] = true; if (isASourceArc) m_isSourceArc[e_split] = true; // insert a new edge into the face edge eNew = m_Gamma.splitFace(adjSrc,adjTgt); m_eIterator[eNew] = GraphCopy::m_eCopy[eOrig].pushBack(eNew); m_eOrig[eNew] = eOrig; dirtyList.pushBack(eNew->adjSource()); adjSrc = adjSrcNext; } // insert last edge edge eNew = m_Gamma.splitFace(adjSrc,*it); m_eIterator[eNew] = m_eCopy[eOrig].pushBack(eNew); m_eOrig[eNew] = eOrig; dirtyList.pushBack(eNew->adjSource()); // remove the sink arc incident to v if(!outEdges.empty()) { edge e = outEdges.popFrontRet(); if (m_isSinkArc[e]) m_Gamma.joinFaces(e); } m_Gamma.setExternalFace(m_Gamma.rightFace(extFaceHandle)); //computeSinkSwitches(); FaceSinkGraph fsg(m_Gamma, s_hat); List<adjEntry> dummyList; FaceArray< List<adjEntry> > sinkSwitches(m_Gamma, dummyList); fsg.sinkSwitches(sinkSwitches); //construct sinkArc for the dirty faces for(adjEntry adj : dirtyList) { face fLeft = m_Gamma.leftFace(adj); face fRight = m_Gamma.rightFace(adj); List<adjEntry> switches = sinkSwitches[fLeft]; OGDF_ASSERT(!switches.empty()); constructSinkArcs(fLeft, switches.front()->theNode()); OGDF_ASSERT(!switches.empty()); switches = sinkSwitches[fRight]; constructSinkArcs(fRight, switches.front()->theNode()); } m_Gamma.setExternalFace(m_Gamma.rightFace(extFaceHandle)); computeSinkSwitches(); }
void UpwardPlanRep::augment() { if (isAugmented) return; OGDF_ASSERT(hasSingleSource(*this)); List<adjEntry> switches; hasSingleSource(*this, s_hat); OGDF_ASSERT(this == &m_Gamma.getGraph()); for(adjEntry adj : s_hat->adjEntries) m_isSourceArc[adj->theEdge()] = true; FaceSinkGraph fsg(m_Gamma, s_hat); List<adjEntry> dummyList; FaceArray< List<adjEntry> > sinkSwitches(m_Gamma, dummyList); fsg.sinkSwitches(sinkSwitches); m_sinkSwitchOf.init(*this, nullptr); List<Tuple2<adjEntry, adjEntry>> list; for(face f : m_Gamma.faces) { adjEntry adj_top; switches = sinkSwitches[f]; if (switches.empty() || f == m_Gamma.externalFace()) continue; else adj_top = switches.popFrontRet(); // first switch in the list is a top sink switch while (!switches.empty()) { adjEntry adj = switches.popFrontRet(); Tuple2<adjEntry, adjEntry> pair(adj, adj_top); list.pushBack(pair); } } // construct sink arcs // for the ext. face extFaceHandle = getAdjEntry(m_Gamma, s_hat, m_Gamma.externalFace()); node t = this->newNode(); switches = sinkSwitches[m_Gamma.externalFace()]; OGDF_ASSERT(!switches.empty()); while (!switches.empty()) { adjEntry adj = switches.popFrontRet(); edge e_new; if (t->degree() == 0) { e_new = m_Gamma.addEdgeToIsolatedNode(adj, t); } else { adjEntry adjTgt = getAdjEntry(m_Gamma, t, m_Gamma.rightFace(adj)); e_new = m_Gamma.splitFace(adj, adjTgt); } m_isSinkArc[e_new] = true; m_Gamma.setExternalFace(m_Gamma.rightFace(extFaceHandle)); } /* * set ext. face handle * we add a additional node t_hat and an addtional edge e=(t, t_hat) * e will never been crossed. we use e as the ext. face handle */ t_hat = this->newNode(); adjEntry adjSource = getAdjEntry(m_Gamma, t, m_Gamma.externalFace()); extFaceHandle = m_Gamma.addEdgeToIsolatedNode(adjSource, t_hat)->adjTarget(); m_isSinkArc[extFaceHandle->theEdge()] = true; // not really a sink arc !! TODO?? m_Gamma.setExternalFace(m_Gamma.rightFace(extFaceHandle)); //for int. faces while (!list.empty()) { Tuple2<adjEntry, adjEntry> pair = list.popFrontRet(); edge e_new = nullptr; if (pair.x2()->theNode()->degree() == 0 ) { e_new = m_Gamma.addEdgeToIsolatedNode(pair.x1(), pair.x2()->theNode()); } else { adjEntry adjTgt = getAdjEntry(m_Gamma, pair.x2()->theNode(), m_Gamma.rightFace(pair.x1())); if(!m_Gamma.getGraph().searchEdge(pair.x1()->theNode(),adjTgt->theNode())) // post-hoi-ming bugfix: prohibit the same edge twice... e_new = m_Gamma.splitFace(pair.x1(), adjTgt); } if(e_new!=nullptr) m_isSinkArc[e_new] = true; } isAugmented = true; OGDF_ASSERT(isSimple(*this)); computeSinkSwitches(); }