//--------------------------------------------------------- // Compute x-coordinates (LP-based approach) (for graphs) //--------------------------------------------------------- void OptimalHierarchyLayout::computeXCoordinates( const Hierarchy& H, GraphCopyAttributes &AGC) { const GraphCopy &GC = H; const int k = H.size(); // // preprocessing: determine nodes that are considered as virtual // NodeArray<bool> isVirtual(GC); int i; for(i = 0; i < k; ++i) { const Level &L = H[i]; int last = -1; for(int j = 0; j < L.size(); ++j) { node v = L[j]; if(H.isLongEdgeDummy(v) == true) { isVirtual[v] = true; node u = v->firstAdj()->theEdge()->target(); if(u == v) u = v->lastAdj()->theEdge()->target(); if(H.isLongEdgeDummy(u) == true) { int down = H.pos(u); if(last != -1 && last > down) { isVirtual[v] = false; } else { last = down; } } } else isVirtual[v] = false; } } // // determine variables of LP // int nSegments = 0; // number of vertical segments int nRealVertices = 0; // number of real vertices int nEdges = 0; // number of edges not in vertical segments int nBalanced = 0; // number of real vertices with deg > 1 for which // balancing constraints may be applied NodeArray<int> vIndex(GC,-1); // for real node: index of x[v] // for dummy: index of corresponding segment NodeArray<int> bIndex(GC,-1); // (relative) index of b[v] EdgeArray<int> eIndex(GC,-1); // for edge not in vertical segment: // its index Array<int> count(GC.numberOfEdges()); // counts the number of dummy vertices // in corresponding segment that are not at // position 0 for(i = 0; i < k; ++i) { const Level &L = H[i]; for(int j = 0; j < L.size(); ++j) { node v = L[j]; if(isVirtual[v] == true) continue; // we've found a real vertex vIndex[v] = nRealVertices++; if(v->degree() > 1) bIndex[v] = nBalanced++; // consider all outgoing edges edge e; forall_adj_edges(e,v) { node w = e->target(); if(w == v) continue; // we've found an edge not belonging to a vetical segment eIndex[e] = nEdges++; if(isVirtual[w] == false) continue; // we've found a vertical segment count[nSegments] = 0; do { vIndex[w] = nSegments; const int high = H[H.rank(w)].high(); if(high > 0) { if (H.pos(w) == 0 || H.pos(w) == high) ++count[nSegments]; else count[nSegments] += 2; } // next edge / dummy in segment e = e->adjTarget()->cyclicSucc()->theEdge(); w = e->target(); } while(isVirtual[w]); // edge following vertical segment eIndex[e] = nEdges++; ++nSegments; } } }
//--------------------------------------------------------- // Compute x-coordinates (LP-based approach) (for cluster graphs) //--------------------------------------------------------- void OptimalHierarchyClusterLayout::computeXCoordinates( const ExtendedNestingGraph& H, ClusterGraphCopyAttributes &AGC) { const ClusterGraphCopy &CG = H.getClusterGraph(); const int k = H.numberOfLayers(); // // preprocessing: determine nodes that are considered as virtual // m_isVirtual.init(H); int i; for(i = 0; i < k; ++i) { int last = -1; // Process nodes on layer i from left to right Stack<const LHTreeNode*> S; S.push(H.layerHierarchyTree(i)); while(!S.empty()) { const LHTreeNode *vNode = S.pop(); if(vNode->isCompound()) { for(int j = vNode->numberOfChildren()-1; j >= 0; --j) S.push(vNode->child(j)); } else { node v = vNode->getNode(); if(H.isLongEdgeDummy(v) == true) { m_isVirtual[v] = true; edge e = v->firstAdj()->theEdge(); if(e->target() == v) e = v->lastAdj()->theEdge(); node u = e->target(); if(H.verticalSegment(e) == false) continue; if(H.isLongEdgeDummy(u) == true) { int down = H.pos(u); if(last != -1 && last > down) { m_isVirtual[v] = false; } else { last = down; } } } else { m_isVirtual[v] = false; } } } } // // determine variables of LP // int nSegments = 0; // number of vertical segments int nRealVertices = 0; // number of real vertices int nEdges = 0; // number of edges not in vertical segments int nBalanced = 0; // number of real vertices with deg > 1 for which balancing constraints may be applied m_vIndex.init(H,-1); // for real node: index of x[v] for dummy: index of corresponding segment NodeArray<int> bIndex(H,-1); // (relative) index of b[v] EdgeArray<int> eIndex(H,-1); // for edge not in vertical segment: its index Array<int> count(H.numberOfEdges()); // counts the number of dummy vertices // in corresponding segment that are not at // position 0 int nSpacingConstraints = 0; for(i = 0; i < k; ++i) { Stack<const LHTreeNode*> S; S.push(H.layerHierarchyTree(i)); while(!S.empty()) { const LHTreeNode *vNode = S.pop(); if(vNode->isCompound()) { cluster c = vNode->originalCluster(); if(H.isVirtual(c) == false) nSpacingConstraints += (c == CG.rootCluster()) ? 1 : 2; for(int j = vNode->numberOfChildren()-1; j >= 0; --j) S.push(vNode->child(j)); } else { node v = vNode->getNode(); // ignore dummy nodes and nodes representing cluster // (top or bottom) border if(H.type(v) == ExtendedNestingGraph::ntClusterBottom || H.type(v) == ExtendedNestingGraph::ntClusterTop) continue; ++nSpacingConstraints; // ignore dummy nodes if(m_isVirtual[v] == true) continue; // we've found a real vertex m_vIndex[v] = nRealVertices++; if(v->degree() > 1) bIndex[v] = nBalanced++; // consider all outgoing edges edge e; forall_adj_edges(e,v) { node w = e->target(); if(w == v) continue; // we've found an edge not belonging to a vetical segment eIndex[e] = nEdges++; if(m_isVirtual[w] == false) continue; do { // we've found a vertical segment count[nSegments] = 0; do { m_vIndex[w] = nSegments; count[nSegments] += 2; // next edge / dummy in segment e = e->adjTarget()->cyclicSucc()->theEdge(); w = e->target(); } while(m_isVirtual[w] && H.verticalSegment(e)); ++nSegments; // edge following vertical segment eIndex[e] = nEdges++; } while(m_isVirtual[w]); } } } }