void ComponentSplitterLayout::call(GraphAttributes &GA) { // Only do preparations and call if layout is valid if (m_secondaryLayout.valid()) { //first we split the graph into its components const Graph& G = GA.constGraph(); NodeArray<int> componentNumber(G); m_numberOfComponents = connectedComponents(G, componentNumber); if (m_numberOfComponents == 0) { return; } //std::vector< std::vector<node> > componentArray; //componentArray.resize(numComponents); //Array<GraphAttributes *> components(numComponents); // // intialize the array of lists of nodes contained in a CC nodesInCC.init(m_numberOfComponents); node v; forall_nodes(v,G) nodesInCC[componentNumber[v]].pushBack(v); // Create copies of the connected components and corresponding // GraphAttributes GraphCopy GC; GC.createEmpty(G); EdgeArray<edge> auxCopy(G); for (int i = 0; i < m_numberOfComponents; i++) { GC.initByNodes(nodesInCC[i],auxCopy); GraphAttributes cGA(GC); //copy information into copy GA forall_nodes(v, GC) { cGA.width(v) = GA.width(GC.original(v)); cGA.height(v) = GA.height(GC.original(v)); cGA.x(v) = GA.x(GC.original(v)); cGA.y(v) = GA.y(GC.original(v)); } m_secondaryLayout.get().call(cGA); //copy layout information back into GA forall_nodes(v, GC) { node w = GC.original(v); if (w != 0) GA.x(w) = cGA.x(v); GA.y(w) = cGA.y(v); } }
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 ComponentSplitterLayout::call(GraphAttributes &GA) { // Only do preparations and call if layout is valid if (m_secondaryLayout.valid()) { //first we split the graph into its components const Graph& G = GA.constGraph(); NodeArray<int> componentNumber(G); int numberOfComponents = connectedComponents(G, componentNumber); if (numberOfComponents == 0) { return; } // intialize the array of lists of nodes contained in a CC Array<List<node> > nodesInCC(numberOfComponents); for(node v : G.nodes) nodesInCC[componentNumber[v]].pushBack(v); // Create copies of the connected components and corresponding // GraphAttributes GraphCopy GC; GC.createEmpty(G); EdgeArray<edge> auxCopy(G); for (int i = 0; i < numberOfComponents; i++) { GC.initByNodes(nodesInCC[i],auxCopy); GraphAttributes cGA(GC, GA.attributes()); //copy information into copy GA for(node v : GC.nodes) { cGA.width(v) = GA.width(GC.original(v)); cGA.height(v) = GA.height(GC.original(v)); cGA.x(v) = GA.x(GC.original(v)); cGA.y(v) = GA.y(GC.original(v)); } // copy information on edges if (GA.attributes() & GraphAttributes::edgeDoubleWeight) { for (edge e : GC.edges) { cGA.doubleWeight(e) = GA.doubleWeight(GC.original(e)); } } m_secondaryLayout.get().call(cGA); //copy layout information back into GA for(node v : GC.nodes) { node w = GC.original(v); if (w != nullptr) { GA.x(w) = cGA.x(v); GA.y(w) = cGA.y(v); if (GA.attributes() & GraphAttributes::threeD) { GA.z(w) = cGA.z(v); } } } } // rotate component drawings and call the packer reassembleDrawings(GA, nodesInCC); }//if valid }
void SpringEmbedderFR::call(GraphAttributes &AG) { const Graph &G = AG.constGraph(); if(G.empty()) return; // all edges straight-line AG.clearAllBends(); 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); node v; forall_nodes(v,G) nodesInCC[component[v]].pushBack(v); EdgeArray<edge> auxCopy(G); Array<DPoint> boundingBox(numCC); int i; for(i = 0; i < numCC; ++i) { GC.initByNodes(nodesInCC[i],auxCopy); GraphCopyAttributes AGC(GC,AG); node vCopy; forall_nodes(vCopy, GC) { node vOrig = GC.original(vCopy); AGC.x(vCopy) = AG.x(vOrig); AGC.y(vCopy) = AG.y(vOrig); } // original if (initialize(GC, AGC) == true) { for(int i = 1; i <= m_iterations; i++) mainStep(GC, AGC); } cleanup(); // end original node vFirst = GC.firstNode(); double minX = AGC.x(vFirst), maxX = AGC.x(vFirst), minY = AGC.y(vFirst), maxY = AGC.y(vFirst); forall_nodes(vCopy,GC) { node v = GC.original(vCopy); AG.x(v) = AGC.x(vCopy); AG.y(v) = AGC.y(vCopy); if(AG.x(v)-AG.width (v)/2 < minX) minX = AG.x(v)-AG.width(v) /2; if(AG.x(v)+AG.width (v)/2 > maxX) maxX = AG.x(v)+AG.width(v) /2; if(AG.y(v)-AG.height(v)/2 < minY) minY = AG.y(v)-AG.height(v)/2; if(AG.y(v)+AG.height(v)/2 > maxY) maxY = AG.y(v)+AG.height(v)/2; }
void GEMLayout::call(GraphAttributes &AG) { const Graph &G = AG.constGraph(); if(G.empty()) return; OGDF_ASSERT(m_numberOfRounds >= 0); OGDF_ASSERT(DIsGreaterEqual(m_minimalTemperature,0)); OGDF_ASSERT(DIsGreaterEqual(m_initialTemperature,m_minimalTemperature)); OGDF_ASSERT(DIsGreaterEqual(m_gravitationalConstant,0)); OGDF_ASSERT(DIsGreaterEqual(m_desiredLength,0)); OGDF_ASSERT(DIsGreaterEqual(m_maximalDisturbance,0)); OGDF_ASSERT(DIsGreaterEqual(m_rotationAngle,0)); OGDF_ASSERT(DIsLessEqual(m_rotationAngle,pi / 2)); OGDF_ASSERT(DIsGreaterEqual(m_oscillationAngle,0)); OGDF_ASSERT(DIsLessEqual(m_oscillationAngle,pi / 2)); OGDF_ASSERT(DIsGreaterEqual(m_rotationSensitivity,0)); OGDF_ASSERT(DIsLessEqual(m_rotationSensitivity,1)); OGDF_ASSERT(DIsGreaterEqual(m_oscillationSensitivity,0)); OGDF_ASSERT(DIsLessEqual(m_oscillationSensitivity,1)); OGDF_ASSERT(m_attractionFormula == 1 || m_attractionFormula == 2); // all edges straight-line AG.clearAllBends(); 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); node v; forall_nodes(v,G) nodesInCC[component[v]].pushBack(v); EdgeArray<edge> auxCopy(G); Array<DPoint> boundingBox(numCC); int i; for(i = 0; i < numCC; ++i) { GC.initByNodes(nodesInCC[i],auxCopy); GraphCopyAttributes AGC(GC,AG); node vCopy; forall_nodes(vCopy, GC) { node vOrig = GC.original(vCopy); AGC.x(vCopy) = AG.x(vOrig); AGC.y(vCopy) = AG.y(vOrig); } SList<node> permutation; node v; // initialize node data m_impulseX.init(GC,0); m_impulseY.init(GC,0); m_skewGauge.init(GC,0); m_localTemperature.init(GC,m_initialTemperature); // initialize other data m_globalTemperature = m_initialTemperature; m_barycenterX = 0; m_barycenterY = 0; forall_nodes(v,GC) { m_barycenterX += weight(v) * AGC.x(v); m_barycenterY += weight(v) * AGC.y(v); }
void SpringEmbedderFRExact::call(GraphAttributes &AG) { const Graph &G = AG.constGraph(); if(G.empty()) return; // all edges straight-line AG.clearAllBends(); ArrayGraph component(AG); component.m_useNodeWeight = m_useNodeWeight; EdgeArray<edge> auxCopy(G); Array<DPoint> boundingBox(component.numberOfCCs()); int i; for(i = 0; i < component.numberOfCCs(); ++i) { component.initCC(i); if (component.numberOfNodes() >= 2) { initialize(component); #ifdef OGDF_SSE3_EXTENSIONS if(System::cpuSupports(cpufSSE3)) mainStep_sse3(component); else #endif mainStep(component); } double minX, maxX, minY, maxY; minX = maxX = component.m_x[0]; minY = maxY = component.m_y[0]; for(int vCopy = 0; vCopy < component.numberOfNodes(); ++vCopy) { node v = component.original(vCopy); AG.x(v) = component.m_x[vCopy]; AG.y(v) = component.m_y[vCopy]; if(AG.x(v)-AG.width (v)/2 < minX) minX = AG.x(v)-AG.width(v) /2; if(AG.x(v)+AG.width (v)/2 > maxX) maxX = AG.x(v)+AG.width(v) /2; if(AG.y(v)-AG.height(v)/2 < minY) minY = AG.y(v)-AG.height(v)/2; if(AG.y(v)+AG.height(v)/2 > maxY) maxY = AG.y(v)+AG.height(v)/2; } minX -= m_minDistCC; minY -= m_minDistCC; for(int vCopy = 0; vCopy < component.numberOfNodes(); ++vCopy) { node v = component.original(vCopy); AG.x(v) -= minX; AG.y(v) -= minY; } boundingBox[i] = DPoint(maxX - minX, maxY - minY); } Array<DPoint> offset(component.numberOfCCs()); TileToRowsCCPacker packer; packer.call(boundingBox,offset,m_pageRatio); // The arrangement is given by offset to the origin of the coordinate // system. We still have to shift each node and edge by the offset // of its connected component. for(i = 0; i < component.numberOfCCs(); ++i) { const SList<node> &nodes = component.nodesInCC(i); const double dx = offset[i].m_x; const double dy = offset[i].m_y; // iterate over all nodes in ith CC for(node v : nodes) { AG.x(v) += dx; AG.y(v) += dy; } } }
void GEMLayout::call(GraphAttributes &AG) { const Graph &G = AG.constGraph(); if(G.empty()) return; // all edges straight-line AG.clearAllBends(); 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); Array<DPoint> boundingBox(numCC); int i; for(i = 0; i < numCC; ++i) { GC.initByNodes(nodesInCC[i],auxCopy); GraphCopyAttributes AGC(GC,AG); for(node vCopy : GC.nodes) { node vOrig = GC.original(vCopy); AGC.x(vCopy) = AG.x(vOrig); AGC.y(vCopy) = AG.y(vOrig); } SList<node> permutation; // initialize node data m_impulseX.init(GC,0); m_impulseY.init(GC,0); m_skewGauge.init(GC,0); m_localTemperature.init(GC,m_initialTemperature); // initialize other data m_globalTemperature = m_initialTemperature; m_barycenterX = 0; m_barycenterY = 0; for(node v : GC.nodes) { m_barycenterX += weight(v) * AGC.x(v); m_barycenterY += weight(v) * AGC.y(v); } m_cos = cos(m_oscillationAngle / 2.0); m_sin = sin(Math::pi / 2 + m_rotationAngle / 2.0); // main loop int counter = m_numberOfRounds; while(OGDF_GEOM_ET.greater(m_globalTemperature,m_minimalTemperature) && counter--) { // choose nodes by random permutations if(permutation.empty()) { for(node v : GC.nodes) permutation.pushBack(v); permutation.permute(m_rng); } node v = permutation.popFrontRet(); // compute the impulse of node v computeImpulse(GC,AGC,v); // update node v updateNode(GC,AGC,v); } node vFirst = GC.firstNode(); double minX = AGC.x(vFirst), maxX = AGC.x(vFirst), minY = AGC.y(vFirst), maxY = AGC.y(vFirst); for(node vCopy : GC.nodes) { node v = GC.original(vCopy); AG.x(v) = AGC.x(vCopy); AG.y(v) = AGC.y(vCopy); if(AG.x(v)-AG.width (v)/2 < minX) minX = AG.x(v)-AG.width(v) /2; if(AG.x(v)+AG.width (v)/2 > maxX) maxX = AG.x(v)+AG.width(v) /2; if(AG.y(v)-AG.height(v)/2 < minY) minY = AG.y(v)-AG.height(v)/2; if(AG.y(v)+AG.height(v)/2 > maxY) maxY = AG.y(v)+AG.height(v)/2; } minX -= m_minDistCC; minY -= m_minDistCC; for(node vCopy : GC.nodes) { node v = GC.original(vCopy); AG.x(v) -= minX; AG.y(v) -= minY; } boundingBox[i] = DPoint(maxX - minX, maxY - minY); } Array<DPoint> offset(numCC); TileToRowsCCPacker packer; packer.call(boundingBox,offset,m_pageRatio); // The arrangement is given by offset to the origin of the coordinate // system. We still have to shift each node and edge by the offset // of its connected component. for(i = 0; i < numCC; ++i) { const List<node> &nodes = nodesInCC[i]; const double dx = offset[i].m_x; const double dy = offset[i].m_y; // iterate over all nodes in ith CC ListConstIterator<node> it; for(node v : nodes) { AG.x(v) += dx; AG.y(v) += dy; } } // free node data m_impulseX.init(); m_impulseY.init(); m_skewGauge.init(); m_localTemperature.init(); }