|
|
1.1 ! root 1: #include "draw_dag.h" ! 2: ! 3: #include <sys/types.h> ! 4: #include <sys/times.h> ! 5: #define TIC 60 ! 6: ! 7: // local storage for building splines ! 8: static const int max_cntrl_pts = 3; ! 9: static Point *Pt; ! 10: static int Pt_size; ! 11: static int N_points; ! 12: ! 13: static void addpoint(Point p) ! 14: { ! 15: if(!Pt || N_points >= Pt_size) ! 16: { ! 17: /* ! 18: extern Point *realloc(...), *malloc(...); ! 19: */ ! 20: if(Pt) ! 21: { ! 22: Pt_size += 4; ! 23: /* ! 24: Pt = realloc(Pt,Pt_size*sizeof(Pt[0])); ! 25: */ ! 26: Pt = (Point *)realloc((char *)Pt,Pt_size*sizeof(Pt[0])); ! 27: } ! 28: else ! 29: { ! 30: Pt_size = (Maxlevel+2)*max_cntrl_pts+1; ! 31: Pt = new Point[Pt_size]; ! 32: } ! 33: if(!Pt) ! 34: panic("out of memory"); ! 35: } ! 36: ! 37: Pt[N_points].x = p.x; ! 38: Pt[N_points].y = p.y; ! 39: N_points++; ! 40: } ! 41: ! 42: ! 43: // copy the contructed spline points ! 44: static Point *copypoints() ! 45: { ! 46: Point *pt = new Point[N_points]; ! 47: for(int n = 0; n < N_points; ++n) ! 48: { ! 49: pt[n].x = Pt[n].x; ! 50: pt[n].y = Pt[n].y; ! 51: } ! 52: return pt; ! 53: } ! 54: ! 55: ! 56: // see if a straight edge can be drawn for a flat edge ! 57: static int straightedge(int v, edge_t *e) ! 58: { ! 59: int w = e->node; ! 60: int left = Invert[v], right = Invert[w], node = v; ! 61: if(left > right) ! 62: { ! 63: swap(left,right); ! 64: node = w; ! 65: } ! 66: ! 67: // if the left hand side node has a self edge, it can't be done ! 68: for(edge_t *f = Noedges[node]; f; f = f->next) ! 69: if(f->node == node) ! 70: return 0; ! 71: ! 72: // if there is an intervening real node, it can't be done ! 73: int *rank = Rank[Level[v]]; ! 74: for(left += 1; left < right; ++left) ! 75: if(rank[left] < N_real_nodes) ! 76: return 0; ! 77: ! 78: // if there is not enough separation to draw an edge ! 79: if(iabs(Nodepos[v]-Nodepos[w])-(Width[v]+Width[w])/2 < ! 80: max(Levelsep/2,Levelsep-Nodesep)) ! 81: return 0; ! 82: ! 83: // see if there is an opposite edge ! 84: int has_opposite = 0; ! 85: for(f = Noedges[w]; f; f = f->next) ! 86: if(f->node == v) ! 87: { ! 88: has_opposite = 1; ! 89: break; ! 90: } ! 91: ! 92: Point p0, p1; ! 93: p0.y = p1.y = Levelpos[Level[v]]; ! 94: p0.x = Nodepos[v] + (Invert[v] < Invert[w] ? 1 : -1)*Width[v]/2; ! 95: p1.x = Nodepos[w] + (Invert[w] < Invert[v] ? 1 : -1)*Width[w]/2; ! 96: addpoint(p0); ! 97: if(has_opposite) ! 98: { ! 99: Point mid; ! 100: mid.x = (p0.x+p1.x)/2; ! 101: mid.y = p0.y + (e->weight > 0 ? -1 : 1)*(e->width+Nodesep)/2; ! 102: addpoint(mid); ! 103: } ! 104: addpoint(p1); ! 105: ! 106: p0.x = p0.y = -1; ! 107: addpoint(p0); ! 108: ! 109: e->splinept = copypoints(); ! 110: return 1; ! 111: } ! 112: ! 113: ! 114: ! 115: // make splines for flat edges. ! 116: // Here we compute a circle arc that joins v and w and has an appropriate ! 117: // height, then use a few points on it to define the spline control points. ! 118: static void flatedge(int v, edge_t *e) ! 119: { ! 120: N_points = 0; ! 121: ! 122: // see if we can draw a straight line ! 123: if(straightedge(v,e)) ! 124: return; ! 125: ! 126: // half the distance between v and w ! 127: int w = e->node; ! 128: double r = fabs((Nodepos[v]-Nodepos[w])/2.); ! 129: ! 130: // the height of the point half way between v and w ! 131: double h = Levelsep/3.; ! 132: ! 133: // the height of the point 1/4 of the way between v and w ! 134: // extern double sqrt(double); ! 135: double h4 = (h*h - r*r + sqrt((r*r + h*h)*(r*r + h*h) - r*r*h*h))/(2*h); ! 136: ! 137: int level = Level[v]; ! 138: Point p0, p1, p2, p3, p4; ! 139: p0.x = Nodepos[v]; ! 140: p1.x = (3*Nodepos[v] + Nodepos[w])/4; ! 141: p2.x = (Nodepos[v] + Nodepos[w])/2; ! 142: p3.x = (Nodepos[v] + 3*Nodepos[w])/4; ! 143: p4.x = Nodepos[w]; ! 144: if(e->weight > 0) ! 145: { ! 146: p0.y = Levelpos[level] - Height[v]/2; ! 147: p1.y = (int)(Levelpos[level] - Levelheight[level]/2. - h4); ! 148: p2.y = (int)(Levelpos[level] - Levelheight[level]/2. - h); ! 149: p3.y = p1.y; ! 150: p4.y = Levelpos[level] - Height[w]/2; ! 151: } ! 152: else ! 153: { ! 154: p0.y = Levelpos[level] + Height[v]/2; ! 155: p1.y = (int)(Levelpos[level] + Levelheight[level]/2. + h4); ! 156: p2.y = (int)(Levelpos[level] + Levelheight[level]/2. + h); ! 157: p3.y = p1.y; ! 158: p4.y = Levelpos[level] + Height[w]/2; ! 159: } ! 160: ! 161: addpoint(p0); ! 162: addpoint(p1); ! 163: addpoint(p2); ! 164: addpoint(p3); ! 165: addpoint(p4); ! 166: p0.x = p0.y = -1; ! 167: addpoint(p0); ! 168: ! 169: e->splinept = copypoints(); ! 170: } ! 171: ! 172: ! 173: ! 174: // spline for self edges ! 175: static void selfedge(int v, edge_t *e) ! 176: { ! 177: N_points = 0; ! 178: ! 179: Point p0, p1, p2, p3, p4; ! 180: p0.x = Nodepos[v]+Width[v]/2; ! 181: p0.y = Levelpos[Level[v]] - Height[v]/8; ! 182: p2.x = p0.x + Nodesep + e->width/2; ! 183: p2.y = Levelpos[Level[v]]; ! 184: p1.x = (p2.x + p0.x)/2; ! 185: p1.y = p0.y - Nodesep/4 - e->width/4; ! 186: p4.x = Nodepos[v]+Width[v]/2; ! 187: p4.y = Levelpos[Level[v]] + Height[v]/8; ! 188: p3.x = p1.x; ! 189: p3.y = p4.y + Nodesep/4 + e->width/4; ! 190: ! 191: addpoint(p0); ! 192: addpoint(p1); ! 193: addpoint(p2); ! 194: addpoint(p3); ! 195: addpoint(p4); ! 196: ! 197: p0.x = p0.y = -1; ! 198: addpoint(p0); ! 199: ! 200: e->splinept = copypoints(); ! 201: } ! 202: ! 203: ! 204: // compute a line aiming from v to w and confined to the box ! 205: // defined by 'tl' and 'br'. ! 206: // The line is guaranteed not to hit any adjacent boxes. ! 207: // Line equation is defined as x = my + b instead of y = mx + b to avoid ! 208: // the problem of infinite slopes with vertical lines. ! 209: ! 210: static int defineline(Point v, Point w, Point tl, Point br, ! 211: int thisnode, double &m, double &b) ! 212: { ! 213: // horizontal line ! 214: if(v.y == w.y) ! 215: { ! 216: m = HUGE; ! 217: return 0; ! 218: } ! 219: ! 220: // 1 if the defined ray meets w. ! 221: // -1 if ray doesnot meet w because of a parallel edge ! 222: // 0 if ray doesnot meet w because of intersection with nodes ! 223: int meet = 1; ! 224: ! 225: // the ray that aims at w ! 226: m = (v.x - w.x) / ((double)(v.y - w.y)); ! 227: b = v.x - m*v.y; ! 228: ! 229: edge_t *e = v.y < w.y ? Inedges[thisnode] : Outedges[thisnode]; ! 230: int ewidth = e->width/2; ! 231: ! 232: int dir = v.x < w.x ? -1 : 1; ! 233: int level = Level[thisnode]; ! 234: int level_y = Levelpos[level]; ! 235: int *rank = Rank[level]; ! 236: for(int i = Invert[thisnode]+dir; i >= 0 && rank[i] >= 0; i += dir) ! 237: { ! 238: if(m == 0.) ! 239: break; ! 240: ! 241: int node = rank[i]; ! 242: int x = Nodepos[node], y; ! 243: ! 244: // out of relevant bound ! 245: if((dir < 0 && x < v.x) || (dir > 0 && x > v.x)) ! 246: break; ! 247: ! 248: if(node >= N_real_nodes) ! 249: { ! 250: // see if there is a parallel edge ! 251: if(v.y < w.y) ! 252: { ! 253: int ix = Nodepos[Inedges[node]->node]; ! 254: if((ix-v.x)*(x-w.x) < 0) ! 255: continue; ! 256: } ! 257: else ! 258: { ! 259: int ox = Nodepos[Outedges[node]->node]; ! 260: if((ox-v.x)*(x-w.x) < 0) ! 261: continue; ! 262: } ! 263: } ! 264: ! 265: int height = Height[node]/2 + max(1,min(Levelsep/4,Height[node]/4)); ! 266: ! 267: x += dir < 0 ? Width[node]/2 : -Width[node]/2; ! 268: y = (int)(((x + (dir < 0 ? ewidth : -ewidth)) - b)/m); ! 269: ! 270: if((v.y < w.y && y < level_y-height) || ! 271: (v.y > w.y && y > level_y+height)) ! 272: continue; ! 273: ! 274: if(thisnode >= N_real_nodes && Outedges[thisnode]->count > 1) ! 275: { ! 276: w.y = v.y < w.y ? tl.y : br.y; ! 277: if(v.y == w.y) ! 278: break; ! 279: m = (v.x - w.x) / ((double)(v.y - w.y)); ! 280: b = v.x - m*v.y; ! 281: break; ! 282: } ! 283: ! 284: if(node >= N_real_nodes) ! 285: { ! 286: y = v.y < w.y ? level_y-height : level_y+height; ! 287: if(meet == 1) ! 288: meet = -1; ! 289: } ! 290: else ! 291: { ! 292: // the line from v to w-corner ! 293: Point p; ! 294: p.x = v.x < w.x ? tl.x : br.x; ! 295: p.y = v.y > w.y ? br.y : tl.y; ! 296: if(v.y == p.y) ! 297: break; ! 298: m = (v.x - p.x) / ((double)(v.y - p.y)); ! 299: b = v.x - m*v.y; ! 300: if(m == 0.) ! 301: break; ! 302: ! 303: y = (int)((x - b)/m); ! 304: ! 305: if(v.y > w.y) ! 306: { ! 307: int a_y = level_y+height; ! 308: y = p.y < a_y ? a_y : min(y,a_y); ! 309: } ! 310: else ! 311: { ! 312: int a_y = level_y-height; ! 313: y = p.y > a_y ? a_y : max(y,a_y); ! 314: } ! 315: ! 316: meet = 0; ! 317: } ! 318: ! 319: if(v.y == y) ! 320: break; ! 321: m = (v.x - x) / ((double)(v.y - y)); ! 322: b = v.x - m*v.y; ! 323: } ! 324: ! 325: return meet; ! 326: } ! 327: ! 328: ! 329: // compute the point where a line enters a box. ! 330: static void lineXbox(Point v,int n,double m,double b,Point tl,Point br,Point &i) ! 331: { ! 332: // center line of the box ! 333: int mid_x = Nodepos[n]; ! 334: ! 335: // try the top or bottom edge ! 336: i.y = v.y < tl.y ? tl.y : br.y; ! 337: i.x = m == HUGE ? mid_x : (int)(m*i.y + b + .5); ! 338: if(m == HUGE) ! 339: return; ! 340: ! 341: // miss the box, try the sides ! 342: if(i.x < tl.x-1 || i.x > br.x+1) ! 343: { ! 344: i.x = v.x < mid_x ? tl.x : br.x; ! 345: i.y = m == 0. ? (v.y < tl.y ? tl.y : br.y) : (int)((i.x - b)/m + .5); ! 346: } ! 347: ! 348: // still miss it ! 349: if(i.y > br.y+1 || i.y < tl.y-1 || ! 350: (v.x < mid_x-1 && i.x > mid_x+1) || ! 351: (v.x > mid_x+1 && i.x < mid_x-1)) ! 352: { ! 353: if(v.x < mid_x) ! 354: { ! 355: if(Invert[n] > 0) ! 356: { ! 357: int a = Rank[Level[n]][Invert[n]-1]; ! 358: int x = max(v.x,Nodepos[a]+Width[a]/2); ! 359: i.x = (x + tl.x + 1)/2; ! 360: } ! 361: else i.x = tl.x; ! 362: } ! 363: else ! 364: { ! 365: int a = Rank[Level[n]][Invert[n]+1]; ! 366: if(a >= 0) ! 367: { ! 368: int x = min(v.x,Nodepos[a]-Width[a]/2); ! 369: i.x = (x + br.x + 1)/2; ! 370: } ! 371: else i.x = br.x; ! 372: } ! 373: ! 374: i.y = m == 0. ? (v.y < tl.y ? tl.y : br.y) : (int)((i.x - b)/m + .5); ! 375: } ! 376: } ! 377: ! 378: ! 379: ! 380: // see if a line cross a self edge ! 381: static int lineXselfedge(int v, Point nextpt, double &m, double &b, int &right_y) ! 382: { ! 383: if(N_self_edges <= 0 || m == 0. || m == HUGE) ! 384: return 0; ! 385: for(edge_t *e = Noedges[v]; e; e = e->next) ! 386: if(e->node == v) ! 387: break; ! 388: if(!e) ! 389: return 0; ! 390: ! 391: // location of the lowest point of self-edge ! 392: int self_x = Nodepos[v] + Width[v]/2 + Nodesep/2; ! 393: if(nextpt.x <= self_x) ! 394: return 0; ! 395: int self_y = Levelpos[Level[v]]; ! 396: if(nextpt.y > self_y) ! 397: { ! 398: self_y += Height[v]/8 + Nodesep/4 + e->width/2 + Height[v]/16; ! 399: self_y = min(self_y,Levelpos[Level[v]]+Height[v]/2); ! 400: } ! 401: else ! 402: { ! 403: self_y -= Height[v]/8 + Nodesep/4 + e->width/2 + Height[v]/16; ! 404: self_y = max(self_y,Levelpos[Level[v]]-Height[v]/2); ! 405: } ! 406: ! 407: int y = (int)((self_x - b)/m); ! 408: if((nextpt.y > self_y && y >= self_y) || ! 409: (nextpt.y < self_y && y <= self_y)) ! 410: return 0; ! 411: ! 412: // compute the line that goes to self_x, self_y ! 413: m = ((double)(nextpt.x-self_x))/(nextpt.y-self_y); ! 414: b = self_x - m*self_y; ! 415: ! 416: // find where it intersects the middle of the box ! 417: y = (int)((Nodepos[v]-b)/m); ! 418: ! 419: if(nextpt.y > self_y) ! 420: right_y = max(right_y,y); ! 421: else right_y = min(right_y,y); ! 422: ! 423: return 1; ! 424: } ! 425: ! 426: ! 427: // compute the down part of a spline ! 428: static void downspline(int v, edge_t *edge, int &left_y, int &right_y) ! 429: { ! 430: N_points = 0; ! 431: ! 432: Point thispt, lastpt, nextpt, // the points to spline thru ! 433: tl, br, // box containing thispt ! 434: top_i, bot_i; // intersections with box ! 435: double m, b; // line equation coeffs ! 436: ! 437: int level = Level[v]; ! 438: edge_t *e = edge; ! 439: thispt.x = Nodepos[v]; ! 440: thispt.y = Levelpos[level]; ! 441: nextpt.x = Nodepos[e->node]; ! 442: nextpt.y = Levelpos[level+1] - Height[e->node]/2; ! 443: ! 444: // box containing v to be aimed at from below ! 445: tl.x = thispt.x - Width[v]/2; ! 446: tl.y = thispt.y - Height[v]/2; ! 447: br.x = thispt.x + Width[v]/2; ! 448: br.y = thispt.y + Height[v]/2; ! 449: ! 450: // the point to be aimed at ! 451: if(nextpt.x < thispt.x) ! 452: thispt.y = max(left_y,thispt.y); ! 453: else if(nextpt.x > thispt.x) ! 454: thispt.y = max(right_y,thispt.y); ! 455: ! 456: defineline(nextpt,thispt,tl,br,v,m,b); ! 457: if(lineXselfedge(v,nextpt,m,b,right_y)) ! 458: thispt.y = max(right_y,thispt.y); ! 459: br.y = Levelpos[level] + Height[v]/2; ! 460: lineXbox(nextpt,v,m,b,tl,br,top_i); ! 461: ! 462: // if outside of the actual bounding box of v ! 463: if(top_i.y > br.y+1) ! 464: { ! 465: thispt.y = br.y; ! 466: defineline(top_i,thispt,tl,br,v,m,b); ! 467: lineXbox(top_i,v,m,b,tl,br,thispt); ! 468: addpoint(thispt); ! 469: if(nextpt.x < thispt.x) ! 470: left_y = br.y; ! 471: else if(nextpt.x > thispt.x) ! 472: right_y = br.y; ! 473: } ! 474: else ! 475: { ! 476: // compute the intersection with the vertical line thru v ! 477: int y = m == 0. ? br.y : (int)((thispt.x - b)/m); ! 478: if(nextpt.x < thispt.x) ! 479: left_y = max(y,left_y); ! 480: else if(nextpt.x > thispt.x) ! 481: right_y = max(y,right_y); ! 482: } ! 483: ! 484: addpoint(top_i); ! 485: lastpt.x = top_i.x; ! 486: lastpt.y = top_i.y; ! 487: ! 488: // loop thru all virtual nodes ! 489: int did_virtual = 0; ! 490: for(; e->chain; e = e->chain) ! 491: { ! 492: int thisnode = e->node; ! 493: if(Deleted[thisnode]) ! 494: continue; ! 495: ! 496: level = Level[thisnode]; ! 497: thispt.x = Nodepos[thisnode]; ! 498: thispt.y = Levelpos[level]; ! 499: ! 500: for(edge_t *f = e->chain; f; f = f->chain) ! 501: if(f->node < N_real_nodes || !Deleted[f->node]) ! 502: break; ! 503: int nextnode = f->node; ! 504: nextpt.x = Nodepos[nextnode]; ! 505: nextpt.y = Levelpos[Level[nextnode]] - Height[nextnode]/2; ! 506: ! 507: // top and bottom corners of the box containing this node. ! 508: int box_h = Height[thisnode]; ! 509: int box_w = Width[thisnode] + Nodesep/2; ! 510: tl.y = thispt.y - box_h/2; ! 511: tl.x = thispt.x - box_w/2; ! 512: br.y = thispt.y + box_h/2; ! 513: br.x = thispt.x + box_w/2; ! 514: ! 515: // define the top/bot rays by aiming them at the box center. ! 516: double top_m, top_b, bot_m, bot_b; ! 517: int top_meet, bot_meet; ! 518: top_meet = defineline(lastpt,thispt,tl,br,thisnode,top_m,top_b); ! 519: bot_meet = defineline(nextpt,thispt,tl,br,thisnode,bot_m,bot_b); ! 520: ! 521: // these are identical lines! ! 522: if(top_m == bot_m && top_b == bot_b) ! 523: continue; ! 524: ! 525: // so we know that some spline points was outputed ! 526: did_virtual = 1; ! 527: ! 528: // increase box size if possible to smooth spline turns ! 529: int *rank = Rank[level]; ! 530: int i = Invert[thisnode]; ! 531: int l = i > 0 ? rank[i-1] : -1; ! 532: int r = rank[i+1]; ! 533: int lx = l >= 0 ? Nodepos[l]+Width[l]/2+Nodesep : -1; ! 534: int rx = r >= 0 ? Nodepos[r]-Width[r]/2-Nodesep : -1; ! 535: if(lastpt.x < lx && nextpt.x > rx) ! 536: tl.x = min((lx+tl.x)/2,tl.x); ! 537: if(lastpt.x > rx && nextpt.x < lx) ! 538: br.x = max((rx+br.x)/2,br.x); ! 539: ! 540: if(lx >= 0) ! 541: lx -= Nodesep; ! 542: if(rx >= 0) ! 543: rx += Nodesep; ! 544: ! 545: // points where the lines enter the box ! 546: Point mid; ! 547: lineXbox(lastpt,thisnode,top_m,top_b,tl,br,top_i); ! 548: lineXbox(nextpt,thisnode,bot_m,bot_b,tl,br,bot_i); ! 549: ! 550: // horizontal line ! 551: if(top_m == HUGE || bot_m == HUGE) ! 552: { ! 553: addpoint(top_i); ! 554: addpoint(bot_i); ! 555: continue; ! 556: } ! 557: ! 558: if(top_m != bot_m || top_m == 0. || bot_m == 0.) ! 559: { ! 560: Point line_i; ! 561: line_i.y = (int)((bot_b - top_b)/(top_m - bot_m)); ! 562: line_i.x = (int)(top_m*line_i.y + top_b); ! 563: ! 564: // see if the lines intersect inside the box ! 565: if(top_m == 0. || bot_m == 0. || ! 566: (line_i.x >= tl.x-1 && line_i.x <= br.x+1)) ! 567: { ! 568: // add spline point to avoid node intersection ! 569: mid.x = lastpt.x < thispt.x ? lx : rx; ! 570: if((!top_meet || top_i.y < tl.y-1) && ! 571: top_m != 0. && mid.x >= 0) ! 572: { ! 573: mid.y = (int)((mid.x-top_b)/top_m+.5); ! 574: addpoint(mid); ! 575: } ! 576: addpoint(top_i); ! 577: mid.y = (top_i.y+bot_i.y+1)/2; ! 578: mid.x = (top_i.x+bot_i.x+1)/2; ! 579: addpoint(mid); ! 580: addpoint(bot_i); ! 581: mid.x = nextpt.x < thispt.x ? lx : rx; ! 582: if((!bot_meet || bot_i.y > br.y+1) && ! 583: bot_m != 0. && mid.x >= 0) ! 584: { ! 585: mid.y = (int)((mid.x-bot_b)/bot_m+.5); ! 586: addpoint(mid); ! 587: bot_i.x = mid.x; ! 588: bot_i.y = mid.y; ! 589: } ! 590: ! 591: lastpt.x = bot_i.x; ! 592: lastpt.y = bot_i.y; ! 593: continue; ! 594: } ! 595: ! 596: // the intersection is outside the box. ! 597: // See if the two lines come from the same side ! 598: if((lastpt.x - thispt.x)*(nextpt.x - thispt.x) >= 0) ! 599: { ! 600: // boundaries of immediate neighbors; ! 601: // we don't want to overshoot them! ! 602: int adj, min_x, max_x; ! 603: adj = Invert[thisnode] <= 0 ? -1 : ! 604: Rank[level][Invert[thisnode]-1]; ! 605: min_x = adj < 0 ? 0 : ! 606: Nodepos[adj]+(Width[adj]+Nodesep)/2; ! 607: adj = Rank[level][Invert[thisnode]+1]; ! 608: max_x = adj < 0 ? Maxint : ! 609: Nodepos[adj]-(Width[adj]+Nodesep)/2; ! 610: ! 611: // find the points close to the intersection pt ! 612: // and use their midpoint to make the turn smooth ! 613: int x, top_y, bot_y; ! 614: if(line_i.x > min_x && line_i.x < max_x) ! 615: if(line_i.x < tl.x) ! 616: x = (line_i.x + tl.x)/2; ! 617: else x = (line_i.x + br.x)/2; ! 618: else if(line_i.x < tl.x) ! 619: x = (min_x + tl.x)/2; ! 620: else x = (max_x + br.x)/2; ! 621: ! 622: top_y = (int)((x - top_b)/top_m); ! 623: bot_y = (int)((x - bot_b)/bot_m); ! 624: ! 625: mid.x = x; ! 626: mid.y = (top_y + bot_y + 1)/2; ! 627: ! 628: addpoint(top_i); ! 629: addpoint(mid); ! 630: addpoint(bot_i); ! 631: ! 632: lastpt.x = bot_i.x; ! 633: lastpt.y = bot_i.y; ! 634: continue; ! 635: } ! 636: } ! 637: ! 638: // here we have lines that come from different sides ! 639: // of the box and intersect outside it. ! 640: // Move these lines as close to each other as possible. ! 641: int meet; ! 642: mid.x = thispt.x; ! 643: mid.y = (int)((mid.x - bot_b)/bot_m); ! 644: meet = defineline(lastpt,mid,tl,br,thisnode,top_m,top_b); ! 645: if(meet <= 0) ! 646: { ! 647: mid.y = (int)((mid.x - top_b)/top_m); ! 648: defineline(nextpt,mid,tl,br,thisnode,bot_m,bot_b); ! 649: } ! 650: lineXbox(lastpt,thisnode,top_m,top_b,tl,br,top_i); ! 651: lineXbox(nextpt,thisnode,bot_m,bot_b,tl,br,bot_i); ! 652: ! 653: addpoint(top_i); ! 654: mid.x = (top_i.x + bot_i.x + 1)/2; ! 655: mid.y = (top_i.y + bot_i.y + 1)/2; ! 656: addpoint(mid); ! 657: addpoint(bot_i); ! 658: ! 659: lastpt.x = bot_i.x; ! 660: lastpt.y = bot_i.y; ! 661: } ! 662: ! 663: // so in upspline we'll know whether a spline point was output */ ! 664: thispt.y = did_virtual; ! 665: ! 666: thispt.x = -1; ! 667: addpoint(thispt); ! 668: ! 669: edge->splinept = copypoints(); ! 670: } ! 671: ! 672: ! 673: ! 674: // now do the down end point of a spline ! 675: static void upspline(int w, edge_t *e, int &left_y, int &right_y) ! 676: { ! 677: N_points = 0; ! 678: ! 679: // find the corresponding Outedge ! 680: while(e->node >= N_real_nodes) ! 681: e = e->chain; ! 682: e = e->link; ! 683: ! 684: // current spline control points and their number ! 685: Point *spline = e->splinept; ! 686: for(int n_points = 0; spline[n_points].x >= 0; ++n_points) ! 687: ; ! 688: ! 689: Point lastpt, thispt, tl, br; ! 690: ! 691: // define the lastpt before routing to w ! 692: lastpt.y = spline[n_points-1].y; ! 693: lastpt.x = spline[n_points-1].x; ! 694: ! 695: // now define the point aiming to and the box around it ! 696: int level = Level[w]; ! 697: thispt.x = Nodepos[w]; ! 698: thispt.y = Levelpos[level]; ! 699: tl.x = thispt.x - Width[w]/2; ! 700: tl.y = thispt.y - Height[w]/2; ! 701: br.x = thispt.x + Width[w]/2; ! 702: br.y = thispt.y + Height[w]/2; ! 703: if(lastpt.x < thispt.x) ! 704: thispt.y = min(left_y,thispt.y); ! 705: else if(lastpt.x > thispt.x) ! 706: thispt.y = min(right_y,thispt.y); ! 707: ! 708: Point i; ! 709: double m, b; ! 710: defineline(lastpt,thispt,tl,br,w,m,b); ! 711: if(lineXselfedge(w,lastpt,m,b,right_y)) ! 712: thispt.y = min(right_y,thispt.y); ! 713: lineXbox(lastpt,w,m,b,tl,br,i); ! 714: ! 715: // see if a mid point is needed ! 716: // note that spline[n_points].y contains the info on ! 717: // whether a spline point had been output ! 718: if(e->count > 1 && spline[n_points].y == 0) ! 719: { ! 720: Point mid; ! 721: mid.x = (i.x+lastpt.x + 1)/2; ! 722: mid.y = (i.y+lastpt.y + 1)/2; ! 723: addpoint(mid); ! 724: } ! 725: ! 726: // the intersection is outside the bounding box ! 727: // add a few points to route it to the box ! 728: if(i.y < tl.y-1) ! 729: { ! 730: if(lastpt.x < thispt.x) ! 731: left_y = tl.y; ! 732: else if(lastpt.x > thispt.x) ! 733: right_y = tl.y; ! 734: ! 735: thispt.y = tl.y; ! 736: defineline(i,thispt,tl,br,w,m,b); ! 737: lineXbox(i,w,m,b,tl,br,thispt); ! 738: addpoint(i); ! 739: addpoint(thispt); ! 740: } ! 741: else ! 742: { ! 743: // compute the intersection with the vertical line thru w ! 744: int y = m == 0. ? thispt.y : (int)((thispt.x-b)/m); ! 745: if(lastpt.x < thispt.x) ! 746: left_y = min(y,left_y); ! 747: else if(lastpt.x > thispt.x) ! 748: right_y = min(y,right_y); ! 749: ! 750: addpoint(i); ! 751: } ! 752: ! 753: // extern Point *realloc(...); ! 754: spline = (Point *)realloc((char *)spline,(n_points+N_points+1)*sizeof(spline[0])); ! 755: ! 756: // copy new points back in ! 757: e->splinept = spline; ! 758: spline += n_points; ! 759: for(int n = 0; n < N_points; ++n, ++spline) ! 760: { ! 761: spline->x = Pt[n].x; ! 762: spline->y = Pt[n].y; ! 763: } ! 764: spline->x = spline->y = -1; ! 765: } ! 766: ! 767: ! 768: ! 769: // Given two nodes on the same rank, count how many edges ! 770: // go into the space between them. ! 771: static int between(int v, int w, edge_t **edges) ! 772: { ! 773: int *rank = Rank[Level[v]]; ! 774: if((w = Invert[w]) < (v = Invert[v])) ! 775: swap(v,w); ! 776: ! 777: int count = 0; ! 778: for(v += 1; v < w; v++) ! 779: for(edge_t *e = edges[rank[v]]; e; e = e->next) ! 780: count += e->count; ! 781: return count; ! 782: } ! 783: ! 784: ! 785: ! 786: // partition flat edges below/above the rank to avoid edge crossings ! 787: static void assignside() ! 788: { ! 789: for(int i = 0; i <= Maxlevel; ++i) ! 790: { ! 791: int side = 1; ! 792: for(int *node = Rank[i]; *node != -1; ++node) ! 793: { ! 794: int v = *node; ! 795: if(v >= N_real_nodes) ! 796: continue; ! 797: ! 798: for(edge_t *e = Noedges[v]; e; e = e->next) ! 799: { ! 800: if(e->weight != 0) ! 801: continue; ! 802: ! 803: int w = e->node; ! 804: if (w >= N_real_nodes) ! 805: continue; ! 806: ! 807: // self edge ! 808: if(v == w) ! 809: continue; ! 810: ! 811: // see if there is an opposite edge and ! 812: // process it at the same time ! 813: for(edge_t *f = Noedges[w]; f; f = f->next) ! 814: if(f->node == v) ! 815: break; ! 816: ! 817: // calculate # of intersections from top or bot ! 818: int top_i = between(v,w,Inedges); ! 819: int bot_i = between(v,w,Outedges); ! 820: if(top_i-bot_i != 0) ! 821: { ! 822: if(!f || f->count < e->count) ! 823: e->weight = top_i < bot_i ? 1 : -1; ! 824: else e->weight = top_i > bot_i ? 1 : -1; ! 825: } ! 826: else e->weight = side; ! 827: ! 828: if(f) ! 829: f->weight = -e->weight; ! 830: else side = e->weight; ! 831: } ! 832: } ! 833: } ! 834: } ! 835: ! 836: ! 837: // dag_spline itself ! 838: static int adjcmp(edge_t **e1, edge_t **e2) ! 839: { ! 840: return Invert[(*e1)->node]-Invert[(*e2)->node]; ! 841: } ! 842: ! 843: static void setmargins() { ! 844: // reset the margin ! 845: int xmax = 0, ymax = 0; ! 846: int leftmargin = 0; ! 847: int topmargin = Levelheight[0]/2; ! 848: int rightmargin, bottommargin; ! 849: int v; ! 850: for(int i = 0; i <= Maxlevel; i++) ! 851: leftmargin = max(leftmargin,Width[Rank[i][0]]); ! 852: leftmargin = (leftmargin+1)/2; ! 853: for(v = 0; v < N_nodes; ++v) ! 854: Nodepos[v] += leftmargin; ! 855: ! 856: /* here we adjust the node placement to fit user's desired aspect ratio */ ! 857: if ((Xbound > 0) && (Ybound > 0)) { ! 858: for(v = 0; v < N_nodes; ++v) { ! 859: int w2 = (Width[v] + 1) / 2; ! 860: int h2 = (Height[v] + 1) / 2; ! 861: if (xmax < Nodepos[v] + w2) { ! 862: xmax = Nodepos[v] + w2; ! 863: rightmargin = w2; ! 864: } ! 865: if (ymax < Levelpos[Level[v]] + h2) { ! 866: ymax = Levelpos[Level[v]] + h2; ! 867: bottommargin = h2; ! 868: } ! 869: } ! 870: switch ((Xbound < xmax) + 2 * (!!(Ybound < ymax))) { ! 871: case 0: ! 872: break; ! 873: case 1: ! 874: Ybound = (int)(Ybound * (double)xmax/(double)Xbound); ! 875: Xbound = xmax; ! 876: break; ! 877: case 2: ! 878: Xbound = (int)(Xbound * (double)ymax/(double)Ybound); ! 879: Ybound = ymax; ! 880: break; ! 881: case 3: ! 882: double request_ratio = (double)Xbound/ (double)Ybound; ! 883: double actual_ratio = (double)xmax/ (double)ymax; ! 884: if (actual_ratio < request_ratio) { ! 885: Ybound = ymax; ! 886: Xbound = (int)(Ybound * request_ratio); ! 887: } ! 888: else { ! 889: Xbound = xmax; ! 890: Ybound = (int)(Xbound / request_ratio); ! 891: } ! 892: break; ! 893: } ! 894: ! 895: if ((xmax < Xbound) && (xmax > (rightmargin + leftmargin))) { ! 896: double t1 = Xbound - rightmargin - leftmargin; ! 897: double t2 = xmax - rightmargin - leftmargin; ! 898: double xstretch = t1 / t2; ! 899: for (int v = 0; v < N_nodes; ++v) ! 900: Nodepos[v] = (int)(leftmargin + (Nodepos[v] - leftmargin) * xstretch); ! 901: } ! 902: if ((ymax < Ybound) && (Maxlevel > 1)) { ! 903: double ystretch = ((double)Ybound - topmargin - bottommargin)/((double)ymax - topmargin - bottommargin); ! 904: for (int lev = 1; lev <= Maxlevel; lev++) ! 905: Levelpos[lev] = (int)(topmargin + ((Levelpos[lev] - topmargin) * ystretch)); ! 906: } ! 907: } ! 908: } ! 909: ! 910: void dag_spline() ! 911: { ! 912: struct tms begtm, endtm; ! 913: if(Verbose) ! 914: { ! 915: #ifndef TIMING ! 916: fprintf(stderr,"Making splines\n"); ! 917: #endif ! 918: times(&begtm); ! 919: } ! 920: ! 921: // reset margins, scale picture ! 922: setmargins(); ! 923: ! 924: // make splines for flat and self edges ! 925: if(Noedges) ! 926: { ! 927: assignside(); ! 928: ! 929: for(int v = 0; v < N_real_nodes; ++v) ! 930: for(edge_t *e = Noedges[v]; e; e = e->next) ! 931: if(e->node == v) ! 932: selfedge(v,e); ! 933: else flatedge(v,e); ! 934: } ! 935: ! 936: // space to sort edges ! 937: edge_t **edges = new edge_t*[N_nodes]; ! 938: ! 939: // compute splines for cross-level edges ! 940: for(int v = 0; v < N_real_nodes; v++) ! 941: { ! 942: // these tell where we can aim without causing crossings ! 943: int left_y = Levelpos[Level[v]], right_y = left_y; ! 944: ! 945: // make a sorted list of adjacent forward edges ! 946: int n_forward = 0; ! 947: for(edge_t *e = Outedges[v]; e; e = e->next) ! 948: edges[n_forward++] = e; ! 949: if(n_forward >= 2) ! 950: qsort((char*)edges,n_forward,sizeof(edges[0]),(qsortcmpfun)adjcmp); ! 951: ! 952: // initialize the places in v that we can aim at ! 953: left_y = Levelpos[Level[v]]; ! 954: right_y = left_y; ! 955: ! 956: for(int n = 0, m = n_forward-1; n <= m;) ! 957: { ! 958: if(Nodepos[edges[n]->node] <= Nodepos[v]) ! 959: downspline(v,edges[n++],left_y,right_y); ! 960: if(m >= n && Nodepos[edges[m]->node] > Nodepos[v]) ! 961: downspline(v,edges[m--],left_y,right_y); ! 962: } ! 963: } ! 964: ! 965: // fix up the down end-points of edges so they won't intersect ! 966: for(v = 0; v < N_real_nodes; ++v) ! 967: { ! 968: int n_forward = 0; ! 969: for(edge_t *e = Inedges[v]; e; e = e->next) ! 970: edges[n_forward++] = e; ! 971: if(n_forward >= 2) ! 972: qsort((char*)edges,n_forward,sizeof(edges[0]),(qsortcmpfun)adjcmp); ! 973: ! 974: // initialize the places in v that we can aim at ! 975: int left_y = Levelpos[Level[v]], right_y; ! 976: right_y = left_y; ! 977: ! 978: for(int n = 0, m = n_forward-1; n <= m;) ! 979: { ! 980: if(Nodepos[edges[n]->node] <= Nodepos[v]) ! 981: upspline(v,edges[n++],left_y,right_y); ! 982: if(m >= n && Nodepos[edges[m]->node] > Nodepos[v]) ! 983: upspline(v,edges[m--],left_y,right_y); ! 984: } ! 985: } ! 986: delete edges; ! 987: ! 988: if(Verbose) ! 989: { ! 990: times(&endtm); ! 991: int total = (endtm.tms_utime-begtm.tms_utime) + ! 992: (endtm.tms_stime-begtm.tms_stime); ! 993: int percent = (total - (total/TIC)*TIC)*100/TIC; ! 994: #ifdef TIMING ! 995: fprintf(stderr,"%d.%02d\t",total/TIC,percent); ! 996: #else ! 997: fprintf(stderr,"Time in making splines: %d.%02ds\n", ! 998: total/TIC, percent); ! 999: #endif ! 1000: } ! 1001: } ! 1002:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.