void GEMLayout::updateNode(GraphCopy &G, GraphCopyAttributes &AG,node v) { //const Graph &G = AG.constGraph(); int n = G.numberOfNodes(); double impulseLength; impulseLength = length(m_newImpulseX,m_newImpulseY); if(OGDF_GEOM_ET.greater(impulseLength,0.0)) { // scale impulse by node temperature m_newImpulseX *= m_localTemperature[v] / impulseLength; m_newImpulseY *= m_localTemperature[v] / impulseLength; // move node AG.x(v) += m_newImpulseX; AG.y(v) += m_newImpulseY; // adjust barycenter m_barycenterX += weight(v) * m_newImpulseX; m_barycenterY += weight(v) * m_newImpulseY; impulseLength = length(m_newImpulseX,m_newImpulseY) * length(m_impulseX[v],m_impulseY[v]); if(OGDF_GEOM_ET.greater(impulseLength,0.0)) { m_globalTemperature -= m_localTemperature[v] / n; // compute sine and cosine of angle between old and new impulse double sinBeta,cosBeta; sinBeta = (m_newImpulseX * m_impulseX[v] - m_newImpulseY * m_impulseY[v]) / impulseLength; cosBeta = (m_newImpulseX * m_impulseX[v] + m_newImpulseY * m_impulseY[v]) / impulseLength; // check for rotation if(OGDF_GEOM_ET.greater(sinBeta,m_sin)) m_skewGauge[v] += m_rotationSensitivity; // check for oscillation if(OGDF_GEOM_ET.greater(length(cosBeta),m_cos)) m_localTemperature[v] *= (1 + cosBeta * m_oscillationSensitivity); // cool down according to skew gauge m_localTemperature[v] *= (1.0 - length(m_skewGauge[v])); if(OGDF_GEOM_ET.geq(m_localTemperature[v],m_initialTemperature)) m_localTemperature[v] = m_initialTemperature; // adjust global temperature m_globalTemperature += m_localTemperature[v] / n; } // save impulse m_impulseX[v] = m_newImpulseX; m_impulseY[v] = m_newImpulseY; } }
void GEMLayout::computeImpulse(GraphCopy &G, GraphCopyAttributes &AG,node v) { //const Graph &G = AG.constGraph(); int n = G.numberOfNodes(); double deltaX,deltaY,delta,deltaSqu; double desiredLength,desiredSqu; // add double node radius to desired edge length desiredLength = m_desiredLength + length(AG.getHeight(v),AG.getWidth(v)); desiredSqu = desiredLength * desiredLength; // compute attraction to center of gravity m_newImpulseX = (m_barycenterX / n - AG.x(v)) * m_gravitationalConstant; m_newImpulseY = (m_barycenterY / n - AG.y(v)) * m_gravitationalConstant; // disturb randomly int maxIntDisturbance = (int)(m_maximalDisturbance * 10000); std::uniform_int_distribution<> dist(-maxIntDisturbance,maxIntDisturbance); m_newImpulseX += (dist(m_rng) / 10000.0); m_newImpulseY += (dist(m_rng) / 10000.0); // compute repulsive forces for(node u : G.nodes) if(u != v ) { deltaX = AG.x(v) - AG.x(u); deltaY = AG.y(v) - AG.y(u); delta = length(deltaX,deltaY); if(OGDF_GEOM_ET.greater(delta,0.0)) { deltaSqu = delta * delta; m_newImpulseX += deltaX * desiredSqu / deltaSqu; m_newImpulseY += deltaY * desiredSqu / deltaSqu; } } // compute attractive forces for(adjEntry adj : v->adjEntries) { node u = adj->twinNode(); deltaX = AG.x(v) - AG.x(u); deltaY = AG.y(v) - AG.y(u); delta = length(deltaX,deltaY); if(m_attractionFormula == 1) { m_newImpulseX -= deltaX * delta / (desiredLength * weight(v)); m_newImpulseY -= deltaY * delta / (desiredLength * weight(v)); } else { deltaSqu = delta * delta; m_newImpulseX -= deltaX * deltaSqu / (desiredSqu * weight(v)); m_newImpulseY -= deltaY * deltaSqu / (desiredSqu * weight(v)); } } }
void FPPLayout::computeCoordinates(const GraphCopy &G, IPoint &boundingBox, GridLayout &gridLayout, NodeArray<int> &num, NodeArray<adjEntry> &e_wp, NodeArray<adjEntry> &e_wq) { NodeArray<int> &x = gridLayout.x(); NodeArray<int> &y = gridLayout.y(); const int n = G.numberOfNodes(); NodeArray<int> x_rel(G); NodeArray<node> upper(G); NodeArray<node> next(G); Array<node, int> v(1, n); node w, vk, wp, wq; int k, xq, dx; forall_nodes(w, G) { v[num[w]] = (node) w; }
void FUPSSimple::getSpanTree(GraphCopy &GC, List<edge> &delEdges, bool random) { if (GC.numberOfNodes() == 1) return; // nothing to do node s; hasSingleSource(GC, s); NodeArray<bool> visited(GC, false); EdgeArray<bool> isTreeEdge(GC,false); List<node> toDo; //mark the incident edges e1..e_i of super source s and the incident edges of the target node of the edge e1.._e_i as tree edge. visited[s] = true; for(adjEntry adj : s->adjEdges) { isTreeEdge[adj] = true; visited[adj->theEdge()->target()]; for(adjEntry adjTmp : adj->theEdge()->target()->adjEdges) { isTreeEdge[adjTmp] = true; node tgt = adjTmp->theEdge()->target(); if (!visited[tgt]) { toDo.pushBack(tgt); visited[tgt] = true; } } } //traversing with dfs for(node start : toDo) { for(adjEntry adj : start->adjEdges) { node v = adj->theEdge()->target(); if (!visited[v]) dfs_visit(GC, adj->theEdge(), visited, isTreeEdge, random); } } // delete all non tree edgesEdges to obtain a span tree List<edge> l; for(edge e : GC.edges) { if (!isTreeEdge[e]) l.pushBack(e); } while (!l.empty()) { edge e = l.popFrontRet(); delEdges.pushBack(GC.original(e)); GC.delEdge(e); } }
void FeasibleUpwardPlanarSubgraph::getSpanTree(GraphCopy &GC, List<edge> &delEdges, bool random, bool multisource) { delEdges.clear(); if (GC.numberOfNodes() == 1) return; // nothing to do node s; hasSingleSource(GC, s); NodeArray<bool> visited(GC, false); EdgeArray<bool> isTreeEdge(GC,false); List<node> toDo; // the original graph is a multisource graph. The sources are connected with the super source s. // so do not delete the incident edges of s if (multisource){ // put all incident edges of the source to treeEdges for(adjEntry adj : s->adjEdges) { isTreeEdge[adj->theEdge()] = true; visited[adj->theEdge()->target()]; toDo.pushBack(adj->theEdge()->target()); } } else toDo.pushBack(s); //traversing with dfs for(node start : toDo) { for(adjEntry adj : start->adjEdges) { node v = adj->theEdge()->target(); if (!visited[v]) dfs_visit(GC, adj->theEdge(), visited, isTreeEdge, random); } } // delete all non tree edgesEdges to obtain a span tree List<edge> l; for(edge e : GC.edges) { if (!isTreeEdge[e]) l.pushBack(e); } while (!l.empty()) { edge e = l.popFrontRet(); delEdges.pushBack(GC.original(e)); GC.delEdge(e); } }
void FeasibleUpwardPlanarSubgraph::getSpanTree(GraphCopy &GC, List<edge> &delEdges, bool random, bool multisource) { delEdges.clear(); if (GC.numberOfNodes() == 1) return; // nothing to do node s; hasSingleSource(GC, s); NodeArray<bool> visited(GC, false); EdgeArray<bool> isTreeEdge(GC,false); List<node> toDo; // the original graph is a multisource graph. The sources are connected with the super source s. // so do not delete the incident edges of s if (multisource){ // put all incident edges of the source to treeEdges adjEntry adj; forall_adj(adj, s) { isTreeEdge[adj->theEdge()] = true; visited[adj->theEdge()->target()]; toDo.pushBack(adj->theEdge()->target()); } }
void OptimalRanking::doCall( const Graph& G, NodeArray<int> &rank, EdgeArray<bool> &reversed, const EdgeArray<int> &length, const EdgeArray<int> &costOrig) { MinCostFlowReinelt<int> mcf; // construct min-cost flow problem GraphCopy GC; GC.createEmpty(G); // compute connected component of G NodeArray<int> component(G); int numCC = connectedComponents(G,component); // intialize the array of lists of nodes contained in a CC Array<List<node> > nodesInCC(numCC); for(node v : G.nodes) nodesInCC[component[v]].pushBack(v); EdgeArray<edge> auxCopy(G); rank.init(G); for(int i = 0; i < numCC; ++i) { GC.initByNodes(nodesInCC[i], auxCopy); makeLoopFree(GC); for(edge e : GC.edges) if(reversed[GC.original(e)]) GC.reverseEdge(e); // special cases: if(GC.numberOfNodes() == 1) { rank[GC.original(GC.firstNode())] = 0; continue; } else if(GC.numberOfEdges() == 1) { edge e = GC.original(GC.firstEdge()); rank[e->source()] = 0; rank[e->target()] = length[e]; continue; } EdgeArray<int> lowerBound(GC,0); EdgeArray<int> upperBound(GC,mcf.infinity()); EdgeArray<int> cost(GC); NodeArray<int> supply(GC); for(edge e : GC.edges) cost[e] = -length[GC.original(e)]; for(node v : GC.nodes) { int s = 0; edge e; forall_adj_edges(e,v) { if(v == e->source()) s += costOrig[GC.original(e)]; else s -= costOrig[GC.original(e)]; } supply[v] = s; } OGDF_ASSERT(isAcyclic(GC) == true); // find min-cost flow EdgeArray<int> flow(GC); NodeArray<int> dual(GC); #ifdef OGDF_DEBUG bool feasible = #endif mcf.call(GC, lowerBound, upperBound, cost, supply, flow, dual); OGDF_ASSERT(feasible); for(node v : GC.nodes) rank[GC.original(v)] = dual[v]; } }
void FPPLayout::computeOrder( const GraphCopy &G, NodeArray<int> &num, NodeArray<adjEntry> &e_wp, NodeArray<adjEntry> &e_wq, adjEntry e_12, adjEntry e_2n, adjEntry e_n1) { NodeArray<int> num_diag(G, 0); // number of chords // link[v] = Iterator in possible, that points to v (if diag[v] = 0 and outer[v] = TRUE) NodeArray<ListIterator<node> > link(G, 0); // outer[v] = TRUE <=> v is a node of the actual outer face NodeArray<bool> outer(G, false); // List of all nodes v with outer[v] = TRUE and diag[v] = 0 List<node> possible; // nodes of the outer triangle (v_1,v_2,v_n) node v_1 = e_12->theNode(); node v_2 = e_2n->theNode(); node v_n = e_n1->theNode(); node v_k, wp, wq, u; adjEntry e, e2; int k; // initialization: beginn with outer face (v_1,v_2,v_n) // v_n is the only possible node num[v_1] = 1; num[v_2] = 2; outer[v_1] = true; outer[v_2] = true; outer[v_n] = true; link[v_n] = possible.pushBack(v_n); e_wq[v_1] = e_n1->twin(); e_wp[v_2] = e_2n; e_wq[v_n] = e_2n->twin(); e_wp[v_n] = e_n1; // select next v_k and delete it for (k = G.numberOfNodes(); k >= 3; k--) { v_k = possible.popFrontRet(); // select arbitrary node from possible as v_k num[v_k] = k; // predecessor wp and successor wq from vk in C_k (actual outer face) wq = (e_wq [v_k])->twinNode(); wp = (e_wp [v_k])->twinNode(); // v_k not in C_k-1 anymore outer[v_k] = false; // shortfall of a chord? if (e_wq[wp]->cyclicSucc()->twinNode() == wq) { // wp, wq is the only successor of vk in G_k // wp, wq loose a chord if (--num_diag[wp] == 0) { link[wp] = possible.pushBack(wp); } if (--num_diag[wq] == 0) { link[wq] = possible.pushBack(wq); } } // update or initialize e_wq, e_wp e_wq[wp] = e_wq[wp]->cyclicSucc(); e_wp[wq] = e_wp[wq]->cyclicPred(); e = e_wq[wp]; for (u = e->twinNode(); u != wq; u = e->twinNode()) { outer[u] = true; e_wp[u] = e->twin(); e = e_wq[u] = e_wp[u]->cyclicSucc()->cyclicSucc(); // search for new chords for (e2 = e_wp[u]->cyclicPred(); e2 != e_wq[u]; e2 = e2->cyclicPred()) { node w = e2->twinNode(); if (outer[w] == true) { ++num_diag[u]; if (w != v_1 && w != v_2) if (++num_diag[w] == 1) possible.del(link[w]); } } if (num_diag[u] == 0) { link[u] = possible.pushBack(u); } } } }