|
|
1.1 ! root 1: #include "draw_dag.h" ! 2: ! 3: ! 4: /* ! 5: Routines to start and end draw_dag. ! 6: In the starting phase, make in/out edge lists with no self-loops, ! 7: multiple edges and cycles. This phase also makes sure that ! 8: constraints of the form 'this set of nodes must be at the same level' ! 9: can be later satisfied. ! 10: */ ! 11: static int Clean_up; // 1 if things need cleaned up before starting ! 12: ! 13: static int multiple(int, edge_t*, int), ! 14: findroot(int); ! 15: static void dfs(int, edge_t**, edge_t**, int*, int*, int**), ! 16: setunion(int*); ! 17: ! 18: ! 19: ! 20: void dag_start(int n_nodes, node_t **nodes, edge_t **outedges, options_t options) ! 21: { ! 22: // clean up previous space ! 23: if(Clean_up) ! 24: { ! 25: if(Verbose) ! 26: fprintf(stderr,"Clean up space from last call\n"); ! 27: Clean_up = 0; ! 28: ! 29: for(int v = 0; v < N_real_nodes; v++) ! 30: { ! 31: for(edge_t *e = Outedges[v]; e; e = e->next) ! 32: if(e->splinept) ! 33: delete e->splinept; ! 34: if(Noedges) ! 35: for(e = Noedges[v]; e; e = e->next) ! 36: if(e->splinept) ! 37: delete e->splinept; ! 38: } ! 39: ! 40: deledges(N_nodes,Inedges); ! 41: deledges(N_nodes,Outedges); ! 42: if(Noedges) ! 43: deledges(N_real_nodes,Noedges); ! 44: Outedges = Inedges = Noedges = NULL; ! 45: if(Istems) ! 46: { ! 47: delete Istems; ! 48: delete Ostems; ! 49: delete Stems; ! 50: Istems = Ostems = NULL; ! 51: Stems = NULL; ! 52: } ! 53: ! 54: for(v = 0; v <= Maxlevel; v++) ! 55: delete Rank[v]; ! 56: delete Rank; Rank = NULL; ! 57: ! 58: delete Root; Root = NULL; ! 59: delete Level; Level = NULL; ! 60: delete N_level; N_level = NULL; ! 61: delete Width; Width = NULL; ! 62: delete Height; Height = NULL; ! 63: delete Levelheight; Levelheight = NULL; ! 64: delete Levelpos; Levelpos = NULL; ! 65: delete Nodepos; Nodepos = NULL; ! 66: delete Deleted; Deleted = NULL; ! 67: } ! 68: ! 69: if (n_nodes <= 0) ! 70: return; ! 71: ! 72: // copy node Widths/Heights ! 73: Width = new int[n_nodes]; ! 74: Height = new int[n_nodes]; ! 75: for(int n = 0; n < n_nodes; ++n) { ! 76: Width[n] = nodes[n]->width; ! 77: Height[n] = nodes[n]->height; ! 78: } ! 79: Nodesep = options.nodesep; ! 80: Levelsep = options.ranksep; ! 81: Xbound = options.xbound; ! 82: Ybound = options.ybound; ! 83: ! 84: // construct equivalence class indices for vertices at same levels ! 85: int *srcs = options.source_nodes; ! 86: int *sinks = options.sink_nodes; ! 87: int **same = options.same_nodes; ! 88: Root = new int[n_nodes]; ! 89: for(n = 0; n < n_nodes; ++n) ! 90: Root[n] = n; ! 91: if(srcs && srcs[0] != -1) ! 92: setunion(srcs); ! 93: if(sinks && sinks[0] != -1) ! 94: setunion(sinks); ! 95: if(same) ! 96: for(n = 0; same[n]; ++n) ! 97: if(same[n][0] != -1) ! 98: setunion(same[n]); ! 99: // compress union trees ! 100: for(n = 0; n < n_nodes; ++n) ! 101: (void)findroot(n); ! 102: ! 103: // construct auxilliary lists of edges turned around by min/max nodes ! 104: int source = (srcs && srcs[0] != -1) ? Root[srcs[0]] : -1; ! 105: int sink = (sinks && sinks[0] != -1) ? Root[sinks[0]] : -1; ! 106: if(sink == source) ! 107: sink = -1; ! 108: edge_t **aux = (edge_t **)0; ! 109: if(source >= 0 || sink >= 0) ! 110: { ! 111: aux = new edge_t*[n_nodes]; ! 112: for(n = 0; n < n_nodes; ++n) ! 113: { ! 114: if(Root[n] != source) ! 115: { ! 116: for(edge_t *e = outedges[n]; e; e = e->next) ! 117: if(Root[e->node] == source) ! 118: { ! 119: aux[e->node] = new edge_t(n,e->weight, ! 120: e->width,e->minlen,aux[e->node]); ! 121: aux[e->node]->chain = e; ! 122: e->chain = aux[e->node]; ! 123: } ! 124: } ! 125: ! 126: if(Root[n] == sink) ! 127: { ! 128: for(edge_t *e = outedges[n]; e; e = e->next) ! 129: if(Root[e->node] != sink) ! 130: { ! 131: aux[e->node] = new edge_t(n,e->weight, ! 132: e->width,e->minlen,aux[e->node]); ! 133: aux[e->node]->chain = e; ! 134: e->chain = aux[e->node]; ! 135: } ! 136: } ! 137: } ! 138: } ! 139: ! 140: // make space for edges ! 141: N_edges = N_self_edges = N_repeat_edges = N_revert_edges = 0; ! 142: N_nodes = N_real_nodes = n_nodes; ! 143: Inedges = new edge_t*[n_nodes]; ! 144: Outedges = new edge_t*[n_nodes]; ! 145: ! 146: // use depth-first search to construct edge lists ! 147: int *active = new int[n_nodes]; ! 148: int *marked = new int[n_nodes]; ! 149: ! 150: // compute the squashed trees of equi-level nodes ! 151: int **sets = new int*[N_nodes]; ! 152: for(n = 0; n < N_nodes; ++n) ! 153: active[Root[n]]++; ! 154: for(n = 0; n < N_nodes; ++n) ! 155: if(active[n] > 0) { ! 156: sets[n] = new int[active[n]+1]; ! 157: sets[n][active[n]] = -1; ! 158: active[n] = 0; ! 159: } ! 160: for(n = 0; n < N_nodes; ++n) ! 161: sets[Root[n]][active[Root[n]]++] = n; ! 162: for(n = 0; n < N_nodes; ++n) ! 163: active[n] = 0; ! 164: ! 165: for(n = 0; n < n_nodes; ++n) ! 166: if(n == Root[n] && !marked[n]) ! 167: dfs(n,outedges,aux,active,marked,sets); ! 168: delete active; ! 169: delete marked; ! 170: for(n = 0; n < n_nodes; ++n) ! 171: if(sets[n]) ! 172: delete sets[n]; ! 173: delete sets; ! 174: ! 175: // restore space used by auxilliary edges ! 176: if(source >= 0 || sink >= 0) ! 177: { ! 178: for(n = 0; n < n_nodes; ++n) ! 179: { ! 180: edge_t *nexte; ! 181: for(edge_t *e = aux[n]; e; e = nexte) ! 182: { ! 183: nexte = e->next; ! 184: delete e; ! 185: } ! 186: } ! 187: delete aux; ! 188: } ! 189: ! 190: if (Verbose) ! 191: { ! 192: #ifdef TIMING ! 193: fprintf(stderr,"%d\t%d\t",N_nodes,N_edges); ! 194: #else ! 195: fprintf(stderr,"N_nodes = %d, N_edges=%d\n",N_nodes,N_edges); ! 196: fprintf(stderr,"N_self_edges = %d\n", N_self_edges); ! 197: fprintf(stderr,"N_flat_edges = %d\n", N_flat_edges); ! 198: fprintf(stderr,"N_repeat_edges = %d\n", N_repeat_edges); ! 199: fprintf(stderr,"N_revert_edges = %d\n", N_revert_edges); ! 200: #endif ! 201: } ! 202: } ! 203: ! 204: ! 205: void dag_end(node_t **nodes, edge_t **outedges) ! 206: { ! 207: // output node positions ! 208: for(int v = 0; v < N_real_nodes; v++) ! 209: { ! 210: nodes[v]->pos.x = Nodepos[v]; ! 211: nodes[v]->pos.y = Levelpos[Level[v]]; ! 212: } ! 213: ! 214: // output edge splines ! 215: for(v = 0; v < N_real_nodes; ++v) ! 216: for(edge_t *e = outedges[v]; e; e = e->next) ! 217: { ! 218: // copy the points ! 219: Point *sp = e->chain->splinept; ! 220: for(int n_points = 0; sp[n_points].x >= 0; ++n_points) ! 221: ; ! 222: ! 223: Point *pt; ! 224: if(e->chain->count > 1) ! 225: { ! 226: pt = new Point[n_points+1]; ! 227: for(int n = 0; n <= n_points; ++n) ! 228: { ! 229: pt[n].x = sp[n].x; ! 230: pt[n].y = sp[n].y; ! 231: } ! 232: } ! 233: else ! 234: { ! 235: pt = sp; ! 236: e->chain->splinept = NULL; ! 237: } ! 238: ! 239: // reverse the order of inverted edges ! 240: if(Level[v] > Level[e->node]) ! 241: { ! 242: int n = 0, m = n_points-1; ! 243: for(; n < m; ++n, --m) ! 244: { ! 245: swap(pt[n].x,pt[m].x); ! 246: swap(pt[n].y,pt[m].y); ! 247: } ! 248: } ! 249: ! 250: e->top.x = pt[1].x; ! 251: e->top.y = pt[1].y; ! 252: e->bottom.x = pt[n_points-2].x; ! 253: e->bottom.y = pt[n_points-2].y; ! 254: ! 255: // adjust for multiple edges ! 256: if(e->chain->count > 1) ! 257: { ! 258: int place = e->place; ! 259: int width = e->chain->width; ! 260: if(v == e->node) ! 261: { ! 262: place -= width/2; ! 263: pt[2].x += place; ! 264: pt[1].y -= place/2; ! 265: pt[3].y += place/2; ! 266: } ! 267: else if(Level[v] == Level[e->node]) ! 268: { ! 269: if(e->chain->weight > 0) ! 270: place = -place; ! 271: int mx = iabs(pt[n_points/2].x - pt[0].x); ! 272: for(int n = 1; n < n_points-1; ++n) ! 273: { ! 274: int d = iabs(pt[n].x - pt[0].x); ! 275: d = min(d,iabs(pt[n].x - pt[n_points-1].x)); ! 276: pt[n].y += (int)(place*(((double)d)/mx)); ! 277: } ! 278: } ! 279: else ! 280: { ! 281: place -= width/2; ! 282: for(int n = 1; n < n_points-1; ++n) ! 283: pt[n].x += place; ! 284: } ! 285: } ! 286: ! 287: e->splinept = pt; ! 288: } ! 289: ! 290: // so we'll remember to clean up next time around ! 291: Clean_up = 1; ! 292: } ! 293: ! 294: ! 295: // search for the root of the union tree containing this vertex ! 296: static int findroot(int v) ! 297: { ! 298: // if this is root, return it ! 299: if(v == Root[v]) ! 300: return v; ! 301: // search for root and compress the path ! 302: return (Root[v] = findroot(Root[v])); ! 303: } ! 304: ! 305: // union a set of nodes ! 306: static void setunion(int *set) ! 307: { ! 308: int root = findroot(set[0]); ! 309: for(int i = 0; set[i] != -1; ++i) ! 310: { ! 311: int r = findroot(set[i]); ! 312: if(r == set[i]) ! 313: Root[set[i]] = root; ! 314: else ! 315: { ! 316: Root[root] = r; ! 317: root = r; ! 318: } ! 319: } ! 320: } ! 321: ! 322: ! 323: ! 324: // check for multiple edges ! 325: static int multiple(int node, edge_t *edge, int isaux) ! 326: { ! 327: for(int dohead = 0; dohead < 2; ++dohead) ! 328: { ! 329: /* check for forward multiple edges */ ! 330: edge_t *e = dohead ? Outedges[edge->node] : Outedges[node]; ! 331: int match = dohead ? node : edge->node; ! 332: ! 333: for(; e; e = e->next) ! 334: if(e->node == match) ! 335: { ! 336: e->count += 1; ! 337: e->weight += edge->weight; ! 338: e->width += 3*Nodesep/4 + edge->width; ! 339: ! 340: // identify user's edge with our edge and set its order ! 341: if(isaux) ! 342: { ! 343: edge->chain->chain = e; ! 344: edge->chain->place = e->width - edge->width; ! 345: } ! 346: else ! 347: { ! 348: edge->chain = e; ! 349: edge->place = e->width - edge->width; ! 350: } ! 351: ! 352: // update the corresponding version in Inedges ! 353: e = e->link; ! 354: e->count += 1; ! 355: e->weight += edge->weight; ! 356: e->width += Nodesep + edge->width; ! 357: ! 358: return 1; ! 359: } ! 360: } ! 361: ! 362: return 0; ! 363: } ! 364: ! 365: ! 366: // keep track of self and flat edges for position assignment ! 367: static void noedge(int tail, edge_t *edge) ! 368: { ! 369: if(!Noedges) ! 370: Noedges = new edge_t*[N_real_nodes]; ! 371: ! 372: // check for multiple edge ! 373: for(edge_t *e = Noedges[tail]; e; e = e->next) ! 374: if(e->node == edge->node) ! 375: { ! 376: e->count += 1; ! 377: e->weight += edge->weight; ! 378: e->width += Nodesep/2 + edge->width; ! 379: edge->chain = e; ! 380: edge->place = e->width - edge->width; ! 381: return; ! 382: } ! 383: ! 384: // making a new edge ! 385: Noedges[tail] = new edge_t(edge->node,edge->weight,edge->width,0,Noedges[tail]); ! 386: edge->chain = Noedges[tail]; ! 387: } ! 388: ! 389: ! 390: ! 391: // construct new edge lists ensuring no cycles, multiple edges and self edges. ! 392: static void dfs(int node, edge_t **outedges, edge_t **auxedges, ! 393: int *active, int *marked, int **sets) ! 394: { ! 395: if(marked[node]) ! 396: return; ! 397: marked[node] = 1; ! 398: ! 399: // mark this node as being on the search stack ! 400: active[node] = 1; ! 401: ! 402: for(int *set = sets[node]; *set != -1; ++set) ! 403: { ! 404: int tail = *set; ! 405: ! 406: for(int isaux = 0; isaux < 2; ++isaux) ! 407: { ! 408: if(isaux && !auxedges) ! 409: continue; ! 410: ! 411: edge_t *e = isaux ? auxedges[tail] : outedges[tail]; ! 412: for(; e; e = e->next) ! 413: { ! 414: // there is a corresponding aux edge ! 415: if(!isaux && e->chain) ! 416: continue; ! 417: ! 418: // ignore self-edges or squashed edges ! 419: if(e->node == tail || Root[e->node] == node) ! 420: { ! 421: if(e->node == tail) ! 422: N_self_edges++; ! 423: else N_flat_edges++; ! 424: noedge(tail,e); ! 425: continue; ! 426: } ! 427: ! 428: // check for multiple edges ! 429: if(multiple(tail,e,isaux)) ! 430: { ! 431: N_repeat_edges++; ! 432: continue; ! 433: } ! 434: ! 435: // a new edge is to be constructed ! 436: N_edges++; ! 437: ! 438: // a cycle is detected, reverse the edge ! 439: if(active[Root[e->node]]) ! 440: { ! 441: N_revert_edges++; ! 442: ! 443: Outedges[e->node] = ! 444: new edge_t(tail,e->weight,e->width,e->minlen, ! 445: Outedges[e->node]); ! 446: Inedges[tail] = ! 447: new edge_t(e->node,e->weight,e->width,e->minlen, ! 448: Inedges[tail]); ! 449: Outedges[e->node]->link = Inedges[tail]; ! 450: Inedges[tail]->link = Outedges[e->node]; ! 451: ! 452: // identify user's edge with our edge ! 453: if(isaux) ! 454: { ! 455: e->chain->chain = Outedges[e->node]; ! 456: e->chain->place = 0; ! 457: } ! 458: else ! 459: { ! 460: e->chain = Outedges[e->node]; ! 461: e->place = 0; ! 462: } ! 463: ! 464: continue; ! 465: } ! 466: ! 467: // forward or cross-edges ! 468: Outedges[tail] = new edge_t(e->node,e->weight,e->width,e->minlen, ! 469: Outedges[tail]); ! 470: Inedges[e->node] = new edge_t(tail,e->weight,e->width,e->minlen, ! 471: Inedges[e->node]); ! 472: Outedges[tail]->link = Inedges[e->node]; ! 473: Inedges[e->node]->link = Outedges[tail]; ! 474: ! 475: // identify user's edge with our edge ! 476: if(isaux) ! 477: { ! 478: N_revert_edges++; ! 479: e->chain->chain = Outedges[tail]; ! 480: e->chain->place = 0; ! 481: } ! 482: else ! 483: { ! 484: e->chain = Outedges[tail]; ! 485: e->place = 0; ! 486: } ! 487: ! 488: // recursion ! 489: if(!marked[Root[e->node]]) ! 490: dfs(Root[e->node],outedges,auxedges, ! 491: active,marked,sets); ! 492: } ! 493: } ! 494: } ! 495: ! 496: // this node is now off the search stack ! 497: active[node] = 0; ! 498: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.