#include "draw_dag.h" #include <sys/types.h> #include <sys/times.h> #define TIC 60 // local storage for building splines static const int max_cntrl_pts = 3; static Point *Pt; static int Pt_size; static int N_points; static void addpoint(Point p) { if(!Pt || N_points >= Pt_size) { /* extern Point *realloc(...), *malloc(...); */ if(Pt) { Pt_size += 4; /* Pt = realloc(Pt,Pt_size*sizeof(Pt[0])); */ Pt = (Point *)realloc((char *)Pt,Pt_size*sizeof(Pt[0])); } else { Pt_size = (Maxlevel+2)*max_cntrl_pts+1; Pt = new Point[Pt_size]; } if(!Pt) panic("out of memory"); } Pt[N_points].x = p.x; Pt[N_points].y = p.y; N_points++; } // copy the contructed spline points static Point *copypoints() { Point *pt = new Point[N_points]; for(int n = 0; n < N_points; ++n) { pt[n].x = Pt[n].x; pt[n].y = Pt[n].y; } return pt; } // see if a straight edge can be drawn for a flat edge static int straightedge(int v, edge_t *e) { int w = e->node; int left = Invert[v], right = Invert[w], node = v; if(left > right) { swap(left,right); node = w; } // if the left hand side node has a self edge, it can't be done for(edge_t *f = Noedges[node]; f; f = f->next) if(f->node == node) return 0; // if there is an intervening real node, it can't be done int *rank = Rank[Level[v]]; for(left += 1; left < right; ++left) if(rank[left] < N_real_nodes) return 0; // if there is not enough separation to draw an edge if(iabs(Nodepos[v]-Nodepos[w])-(Width[v]+Width[w])/2 < max(Levelsep/2,Levelsep-Nodesep)) return 0; // see if there is an opposite edge int has_opposite = 0; for(f = Noedges[w]; f; f = f->next) if(f->node == v) { has_opposite = 1; break; } Point p0, p1; p0.y = p1.y = Levelpos[Level[v]]; p0.x = Nodepos[v] + (Invert[v] < Invert[w] ? 1 : -1)*Width[v]/2; p1.x = Nodepos[w] + (Invert[w] < Invert[v] ? 1 : -1)*Width[w]/2; addpoint(p0); if(has_opposite) { Point mid; mid.x = (p0.x+p1.x)/2; mid.y = p0.y + (e->weight > 0 ? -1 : 1)*(e->width+Nodesep)/2; addpoint(mid); } addpoint(p1); p0.x = p0.y = -1; addpoint(p0); e->splinept = copypoints(); return 1; } // make splines for flat edges. // Here we compute a circle arc that joins v and w and has an appropriate // height, then use a few points on it to define the spline control points. static void flatedge(int v, edge_t *e) { N_points = 0; // see if we can draw a straight line if(straightedge(v,e)) return; // half the distance between v and w int w = e->node; double r = fabs((Nodepos[v]-Nodepos[w])/2.); // the height of the point half way between v and w double h = Levelsep/3.; // the height of the point 1/4 of the way between v and w // extern double sqrt(double); double h4 = (h*h - r*r + sqrt((r*r + h*h)*(r*r + h*h) - r*r*h*h))/(2*h); int level = Level[v]; Point p0, p1, p2, p3, p4; p0.x = Nodepos[v]; p1.x = (3*Nodepos[v] + Nodepos[w])/4; p2.x = (Nodepos[v] + Nodepos[w])/2; p3.x = (Nodepos[v] + 3*Nodepos[w])/4; p4.x = Nodepos[w]; if(e->weight > 0) { p0.y = Levelpos[level] - Height[v]/2; p1.y = (int)(Levelpos[level] - Levelheight[level]/2. - h4); p2.y = (int)(Levelpos[level] - Levelheight[level]/2. - h); p3.y = p1.y; p4.y = Levelpos[level] - Height[w]/2; } else { p0.y = Levelpos[level] + Height[v]/2; p1.y = (int)(Levelpos[level] + Levelheight[level]/2. + h4); p2.y = (int)(Levelpos[level] + Levelheight[level]/2. + h); p3.y = p1.y; p4.y = Levelpos[level] + Height[w]/2; } addpoint(p0); addpoint(p1); addpoint(p2); addpoint(p3); addpoint(p4); p0.x = p0.y = -1; addpoint(p0); e->splinept = copypoints(); } // spline for self edges static void selfedge(int v, edge_t *e) { N_points = 0; Point p0, p1, p2, p3, p4; p0.x = Nodepos[v]+Width[v]/2; p0.y = Levelpos[Level[v]] - Height[v]/8; p2.x = p0.x + Nodesep + e->width/2; p2.y = Levelpos[Level[v]]; p1.x = (p2.x + p0.x)/2; p1.y = p0.y - Nodesep/4 - e->width/4; p4.x = Nodepos[v]+Width[v]/2; p4.y = Levelpos[Level[v]] + Height[v]/8; p3.x = p1.x; p3.y = p4.y + Nodesep/4 + e->width/4; addpoint(p0); addpoint(p1); addpoint(p2); addpoint(p3); addpoint(p4); p0.x = p0.y = -1; addpoint(p0); e->splinept = copypoints(); } // compute a line aiming from v to w and confined to the box // defined by 'tl' and 'br'. // The line is guaranteed not to hit any adjacent boxes. // Line equation is defined as x = my + b instead of y = mx + b to avoid // the problem of infinite slopes with vertical lines. static int defineline(Point v, Point w, Point tl, Point br, int thisnode, double &m, double &b) { // horizontal line if(v.y == w.y) { m = HUGE; return 0; } // 1 if the defined ray meets w. // -1 if ray doesnot meet w because of a parallel edge // 0 if ray doesnot meet w because of intersection with nodes int meet = 1; // the ray that aims at w m = (v.x - w.x) / ((double)(v.y - w.y)); b = v.x - m*v.y; edge_t *e = v.y < w.y ? Inedges[thisnode] : Outedges[thisnode]; int ewidth = e->width/2; int dir = v.x < w.x ? -1 : 1; int level = Level[thisnode]; int level_y = Levelpos[level]; int *rank = Rank[level]; for(int i = Invert[thisnode]+dir; i >= 0 && rank[i] >= 0; i += dir) { if(m == 0.) break; int node = rank[i]; int x = Nodepos[node], y; // out of relevant bound if((dir < 0 && x < v.x) || (dir > 0 && x > v.x)) break; if(node >= N_real_nodes) { // see if there is a parallel edge if(v.y < w.y) { int ix = Nodepos[Inedges[node]->node]; if((ix-v.x)*(x-w.x) < 0) continue; } else { int ox = Nodepos[Outedges[node]->node]; if((ox-v.x)*(x-w.x) < 0) continue; } } int height = Height[node]/2 + max(1,min(Levelsep/4,Height[node]/4)); x += dir < 0 ? Width[node]/2 : -Width[node]/2; y = (int)(((x + (dir < 0 ? ewidth : -ewidth)) - b)/m); if((v.y < w.y && y < level_y-height) || (v.y > w.y && y > level_y+height)) continue; if(thisnode >= N_real_nodes && Outedges[thisnode]->count > 1) { w.y = v.y < w.y ? tl.y : br.y; if(v.y == w.y) break; m = (v.x - w.x) / ((double)(v.y - w.y)); b = v.x - m*v.y; break; } if(node >= N_real_nodes) { y = v.y < w.y ? level_y-height : level_y+height; if(meet == 1) meet = -1; } else { // the line from v to w-corner Point p; p.x = v.x < w.x ? tl.x : br.x; p.y = v.y > w.y ? br.y : tl.y; if(v.y == p.y) break; m = (v.x - p.x) / ((double)(v.y - p.y)); b = v.x - m*v.y; if(m == 0.) break; y = (int)((x - b)/m); if(v.y > w.y) { int a_y = level_y+height; y = p.y < a_y ? a_y : min(y,a_y); } else { int a_y = level_y-height; y = p.y > a_y ? a_y : max(y,a_y); } meet = 0; } if(v.y == y) break; m = (v.x - x) / ((double)(v.y - y)); b = v.x - m*v.y; } return meet; } // compute the point where a line enters a box. static void lineXbox(Point v,int n,double m,double b,Point tl,Point br,Point &i) { // center line of the box int mid_x = Nodepos[n]; // try the top or bottom edge i.y = v.y < tl.y ? tl.y : br.y; i.x = m == HUGE ? mid_x : (int)(m*i.y + b + .5); if(m == HUGE) return; // miss the box, try the sides if(i.x < tl.x-1 || i.x > br.x+1) { i.x = v.x < mid_x ? tl.x : br.x; i.y = m == 0. ? (v.y < tl.y ? tl.y : br.y) : (int)((i.x - b)/m + .5); } // still miss it if(i.y > br.y+1 || i.y < tl.y-1 || (v.x < mid_x-1 && i.x > mid_x+1) || (v.x > mid_x+1 && i.x < mid_x-1)) { if(v.x < mid_x) { if(Invert[n] > 0) { int a = Rank[Level[n]][Invert[n]-1]; int x = max(v.x,Nodepos[a]+Width[a]/2); i.x = (x + tl.x + 1)/2; } else i.x = tl.x; } else { int a = Rank[Level[n]][Invert[n]+1]; if(a >= 0) { int x = min(v.x,Nodepos[a]-Width[a]/2); i.x = (x + br.x + 1)/2; } else i.x = br.x; } i.y = m == 0. ? (v.y < tl.y ? tl.y : br.y) : (int)((i.x - b)/m + .5); } } // see if a line cross a self edge static int lineXselfedge(int v, Point nextpt, double &m, double &b, int &right_y) { if(N_self_edges <= 0 || m == 0. || m == HUGE) return 0; for(edge_t *e = Noedges[v]; e; e = e->next) if(e->node == v) break; if(!e) return 0; // location of the lowest point of self-edge int self_x = Nodepos[v] + Width[v]/2 + Nodesep/2; if(nextpt.x <= self_x) return 0; int self_y = Levelpos[Level[v]]; if(nextpt.y > self_y) { self_y += Height[v]/8 + Nodesep/4 + e->width/2 + Height[v]/16; self_y = min(self_y,Levelpos[Level[v]]+Height[v]/2); } else { self_y -= Height[v]/8 + Nodesep/4 + e->width/2 + Height[v]/16; self_y = max(self_y,Levelpos[Level[v]]-Height[v]/2); } int y = (int)((self_x - b)/m); if((nextpt.y > self_y && y >= self_y) || (nextpt.y < self_y && y <= self_y)) return 0; // compute the line that goes to self_x, self_y m = ((double)(nextpt.x-self_x))/(nextpt.y-self_y); b = self_x - m*self_y; // find where it intersects the middle of the box y = (int)((Nodepos[v]-b)/m); if(nextpt.y > self_y) right_y = max(right_y,y); else right_y = min(right_y,y); return 1; } // compute the down part of a spline static void downspline(int v, edge_t *edge, int &left_y, int &right_y) { N_points = 0; Point thispt, lastpt, nextpt, // the points to spline thru tl, br, // box containing thispt top_i, bot_i; // intersections with box double m, b; // line equation coeffs int level = Level[v]; edge_t *e = edge; thispt.x = Nodepos[v]; thispt.y = Levelpos[level]; nextpt.x = Nodepos[e->node]; nextpt.y = Levelpos[level+1] - Height[e->node]/2; // box containing v to be aimed at from below tl.x = thispt.x - Width[v]/2; tl.y = thispt.y - Height[v]/2; br.x = thispt.x + Width[v]/2; br.y = thispt.y + Height[v]/2; // the point to be aimed at if(nextpt.x < thispt.x) thispt.y = max(left_y,thispt.y); else if(nextpt.x > thispt.x) thispt.y = max(right_y,thispt.y); defineline(nextpt,thispt,tl,br,v,m,b); if(lineXselfedge(v,nextpt,m,b,right_y)) thispt.y = max(right_y,thispt.y); br.y = Levelpos[level] + Height[v]/2; lineXbox(nextpt,v,m,b,tl,br,top_i); // if outside of the actual bounding box of v if(top_i.y > br.y+1) { thispt.y = br.y; defineline(top_i,thispt,tl,br,v,m,b); lineXbox(top_i,v,m,b,tl,br,thispt); addpoint(thispt); if(nextpt.x < thispt.x) left_y = br.y; else if(nextpt.x > thispt.x) right_y = br.y; } else { // compute the intersection with the vertical line thru v int y = m == 0. ? br.y : (int)((thispt.x - b)/m); if(nextpt.x < thispt.x) left_y = max(y,left_y); else if(nextpt.x > thispt.x) right_y = max(y,right_y); } addpoint(top_i); lastpt.x = top_i.x; lastpt.y = top_i.y; // loop thru all virtual nodes int did_virtual = 0; for(; e->chain; e = e->chain) { int thisnode = e->node; if(Deleted[thisnode]) continue; level = Level[thisnode]; thispt.x = Nodepos[thisnode]; thispt.y = Levelpos[level]; for(edge_t *f = e->chain; f; f = f->chain) if(f->node < N_real_nodes || !Deleted[f->node]) break; int nextnode = f->node; nextpt.x = Nodepos[nextnode]; nextpt.y = Levelpos[Level[nextnode]] - Height[nextnode]/2; // top and bottom corners of the box containing this node. int box_h = Height[thisnode]; int box_w = Width[thisnode] + Nodesep/2; tl.y = thispt.y - box_h/2; tl.x = thispt.x - box_w/2; br.y = thispt.y + box_h/2; br.x = thispt.x + box_w/2; // define the top/bot rays by aiming them at the box center. double top_m, top_b, bot_m, bot_b; int top_meet, bot_meet; top_meet = defineline(lastpt,thispt,tl,br,thisnode,top_m,top_b); bot_meet = defineline(nextpt,thispt,tl,br,thisnode,bot_m,bot_b); // these are identical lines! if(top_m == bot_m && top_b == bot_b) continue; // so we know that some spline points was outputed did_virtual = 1; // increase box size if possible to smooth spline turns int *rank = Rank[level]; int i = Invert[thisnode]; int l = i > 0 ? rank[i-1] : -1; int r = rank[i+1]; int lx = l >= 0 ? Nodepos[l]+Width[l]/2+Nodesep : -1; int rx = r >= 0 ? Nodepos[r]-Width[r]/2-Nodesep : -1; if(lastpt.x < lx && nextpt.x > rx) tl.x = min((lx+tl.x)/2,tl.x); if(lastpt.x > rx && nextpt.x < lx) br.x = max((rx+br.x)/2,br.x); if(lx >= 0) lx -= Nodesep; if(rx >= 0) rx += Nodesep; // points where the lines enter the box Point mid; lineXbox(lastpt,thisnode,top_m,top_b,tl,br,top_i); lineXbox(nextpt,thisnode,bot_m,bot_b,tl,br,bot_i); // horizontal line if(top_m == HUGE || bot_m == HUGE) { addpoint(top_i); addpoint(bot_i); continue; } if(top_m != bot_m || top_m == 0. || bot_m == 0.) { Point line_i; line_i.y = (int)((bot_b - top_b)/(top_m - bot_m)); line_i.x = (int)(top_m*line_i.y + top_b); // see if the lines intersect inside the box if(top_m == 0. || bot_m == 0. || (line_i.x >= tl.x-1 && line_i.x <= br.x+1)) { // add spline point to avoid node intersection mid.x = lastpt.x < thispt.x ? lx : rx; if((!top_meet || top_i.y < tl.y-1) && top_m != 0. && mid.x >= 0) { mid.y = (int)((mid.x-top_b)/top_m+.5); addpoint(mid); } addpoint(top_i); mid.y = (top_i.y+bot_i.y+1)/2; mid.x = (top_i.x+bot_i.x+1)/2; addpoint(mid); addpoint(bot_i); mid.x = nextpt.x < thispt.x ? lx : rx; if((!bot_meet || bot_i.y > br.y+1) && bot_m != 0. && mid.x >= 0) { mid.y = (int)((mid.x-bot_b)/bot_m+.5); addpoint(mid); bot_i.x = mid.x; bot_i.y = mid.y; } lastpt.x = bot_i.x; lastpt.y = bot_i.y; continue; } // the intersection is outside the box. // See if the two lines come from the same side if((lastpt.x - thispt.x)*(nextpt.x - thispt.x) >= 0) { // boundaries of immediate neighbors; // we don't want to overshoot them! int adj, min_x, max_x; adj = Invert[thisnode] <= 0 ? -1 : Rank[level][Invert[thisnode]-1]; min_x = adj < 0 ? 0 : Nodepos[adj]+(Width[adj]+Nodesep)/2; adj = Rank[level][Invert[thisnode]+1]; max_x = adj < 0 ? Maxint : Nodepos[adj]-(Width[adj]+Nodesep)/2; // find the points close to the intersection pt // and use their midpoint to make the turn smooth int x, top_y, bot_y; if(line_i.x > min_x && line_i.x < max_x) if(line_i.x < tl.x) x = (line_i.x + tl.x)/2; else x = (line_i.x + br.x)/2; else if(line_i.x < tl.x) x = (min_x + tl.x)/2; else x = (max_x + br.x)/2; top_y = (int)((x - top_b)/top_m); bot_y = (int)((x - bot_b)/bot_m); mid.x = x; mid.y = (top_y + bot_y + 1)/2; addpoint(top_i); addpoint(mid); addpoint(bot_i); lastpt.x = bot_i.x; lastpt.y = bot_i.y; continue; } } // here we have lines that come from different sides // of the box and intersect outside it. // Move these lines as close to each other as possible. int meet; mid.x = thispt.x; mid.y = (int)((mid.x - bot_b)/bot_m); meet = defineline(lastpt,mid,tl,br,thisnode,top_m,top_b); if(meet <= 0) { mid.y = (int)((mid.x - top_b)/top_m); defineline(nextpt,mid,tl,br,thisnode,bot_m,bot_b); } lineXbox(lastpt,thisnode,top_m,top_b,tl,br,top_i); lineXbox(nextpt,thisnode,bot_m,bot_b,tl,br,bot_i); addpoint(top_i); mid.x = (top_i.x + bot_i.x + 1)/2; mid.y = (top_i.y + bot_i.y + 1)/2; addpoint(mid); addpoint(bot_i); lastpt.x = bot_i.x; lastpt.y = bot_i.y; } // so in upspline we'll know whether a spline point was output */ thispt.y = did_virtual; thispt.x = -1; addpoint(thispt); edge->splinept = copypoints(); } // now do the down end point of a spline static void upspline(int w, edge_t *e, int &left_y, int &right_y) { N_points = 0; // find the corresponding Outedge while(e->node >= N_real_nodes) e = e->chain; e = e->link; // current spline control points and their number Point *spline = e->splinept; for(int n_points = 0; spline[n_points].x >= 0; ++n_points) ; Point lastpt, thispt, tl, br; // define the lastpt before routing to w lastpt.y = spline[n_points-1].y; lastpt.x = spline[n_points-1].x; // now define the point aiming to and the box around it int level = Level[w]; thispt.x = Nodepos[w]; thispt.y = Levelpos[level]; tl.x = thispt.x - Width[w]/2; tl.y = thispt.y - Height[w]/2; br.x = thispt.x + Width[w]/2; br.y = thispt.y + Height[w]/2; if(lastpt.x < thispt.x) thispt.y = min(left_y,thispt.y); else if(lastpt.x > thispt.x) thispt.y = min(right_y,thispt.y); Point i; double m, b; defineline(lastpt,thispt,tl,br,w,m,b); if(lineXselfedge(w,lastpt,m,b,right_y)) thispt.y = min(right_y,thispt.y); lineXbox(lastpt,w,m,b,tl,br,i); // see if a mid point is needed // note that spline[n_points].y contains the info on // whether a spline point had been output if(e->count > 1 && spline[n_points].y == 0) { Point mid; mid.x = (i.x+lastpt.x + 1)/2; mid.y = (i.y+lastpt.y + 1)/2; addpoint(mid); } // the intersection is outside the bounding box // add a few points to route it to the box if(i.y < tl.y-1) { if(lastpt.x < thispt.x) left_y = tl.y; else if(lastpt.x > thispt.x) right_y = tl.y; thispt.y = tl.y; defineline(i,thispt,tl,br,w,m,b); lineXbox(i,w,m,b,tl,br,thispt); addpoint(i); addpoint(thispt); } else { // compute the intersection with the vertical line thru w int y = m == 0. ? thispt.y : (int)((thispt.x-b)/m); if(lastpt.x < thispt.x) left_y = min(y,left_y); else if(lastpt.x > thispt.x) right_y = min(y,right_y); addpoint(i); } // extern Point *realloc(...); spline = (Point *)realloc((char *)spline,(n_points+N_points+1)*sizeof(spline[0])); // copy new points back in e->splinept = spline; spline += n_points; for(int n = 0; n < N_points; ++n, ++spline) { spline->x = Pt[n].x; spline->y = Pt[n].y; } spline->x = spline->y = -1; } // Given two nodes on the same rank, count how many edges // go into the space between them. static int between(int v, int w, edge_t **edges) { int *rank = Rank[Level[v]]; if((w = Invert[w]) < (v = Invert[v])) swap(v,w); int count = 0; for(v += 1; v < w; v++) for(edge_t *e = edges[rank[v]]; e; e = e->next) count += e->count; return count; } // partition flat edges below/above the rank to avoid edge crossings static void assignside() { for(int i = 0; i <= Maxlevel; ++i) { int side = 1; for(int *node = Rank[i]; *node != -1; ++node) { int v = *node; if(v >= N_real_nodes) continue; for(edge_t *e = Noedges[v]; e; e = e->next) { if(e->weight != 0) continue; int w = e->node; if (w >= N_real_nodes) continue; // self edge if(v == w) continue; // see if there is an opposite edge and // process it at the same time for(edge_t *f = Noedges[w]; f; f = f->next) if(f->node == v) break; // calculate # of intersections from top or bot int top_i = between(v,w,Inedges); int bot_i = between(v,w,Outedges); if(top_i-bot_i != 0) { if(!f || f->count < e->count) e->weight = top_i < bot_i ? 1 : -1; else e->weight = top_i > bot_i ? 1 : -1; } else e->weight = side; if(f) f->weight = -e->weight; else side = e->weight; } } } } // dag_spline itself static int adjcmp(edge_t **e1, edge_t **e2) { return Invert[(*e1)->node]-Invert[(*e2)->node]; } static void setmargins() { // reset the margin int xmax = 0, ymax = 0; int leftmargin = 0; int topmargin = Levelheight[0]/2; int rightmargin, bottommargin; int v; for(int i = 0; i <= Maxlevel; i++) leftmargin = max(leftmargin,Width[Rank[i][0]]); leftmargin = (leftmargin+1)/2; for(v = 0; v < N_nodes; ++v) Nodepos[v] += leftmargin; /* here we adjust the node placement to fit user's desired aspect ratio */ if ((Xbound > 0) && (Ybound > 0)) { for(v = 0; v < N_nodes; ++v) { int w2 = (Width[v] + 1) / 2; int h2 = (Height[v] + 1) / 2; if (xmax < Nodepos[v] + w2) { xmax = Nodepos[v] + w2; rightmargin = w2; } if (ymax < Levelpos[Level[v]] + h2) { ymax = Levelpos[Level[v]] + h2; bottommargin = h2; } } switch ((Xbound < xmax) + 2 * (!!(Ybound < ymax))) { case 0: break; case 1: Ybound = (int)(Ybound * (double)xmax/(double)Xbound); Xbound = xmax; break; case 2: Xbound = (int)(Xbound * (double)ymax/(double)Ybound); Ybound = ymax; break; case 3: double request_ratio = (double)Xbound/ (double)Ybound; double actual_ratio = (double)xmax/ (double)ymax; if (actual_ratio < request_ratio) { Ybound = ymax; Xbound = (int)(Ybound * request_ratio); } else { Xbound = xmax; Ybound = (int)(Xbound / request_ratio); } break; } if ((xmax < Xbound) && (xmax > (rightmargin + leftmargin))) { double t1 = Xbound - rightmargin - leftmargin; double t2 = xmax - rightmargin - leftmargin; double xstretch = t1 / t2; for (int v = 0; v < N_nodes; ++v) Nodepos[v] = (int)(leftmargin + (Nodepos[v] - leftmargin) * xstretch); } if ((ymax < Ybound) && (Maxlevel > 1)) { double ystretch = ((double)Ybound - topmargin - bottommargin)/((double)ymax - topmargin - bottommargin); for (int lev = 1; lev <= Maxlevel; lev++) Levelpos[lev] = (int)(topmargin + ((Levelpos[lev] - topmargin) * ystretch)); } } } void dag_spline() { struct tms begtm, endtm; if(Verbose) { #ifndef TIMING fprintf(stderr,"Making splines\n"); #endif times(&begtm); } // reset margins, scale picture setmargins(); // make splines for flat and self edges if(Noedges) { assignside(); for(int v = 0; v < N_real_nodes; ++v) for(edge_t *e = Noedges[v]; e; e = e->next) if(e->node == v) selfedge(v,e); else flatedge(v,e); } // space to sort edges edge_t **edges = new edge_t*[N_nodes]; // compute splines for cross-level edges for(int v = 0; v < N_real_nodes; v++) { // these tell where we can aim without causing crossings int left_y = Levelpos[Level[v]], right_y = left_y; // make a sorted list of adjacent forward edges int n_forward = 0; for(edge_t *e = Outedges[v]; e; e = e->next) edges[n_forward++] = e; if(n_forward >= 2) qsort((char*)edges,n_forward,sizeof(edges[0]),(qsortcmpfun)adjcmp); // initialize the places in v that we can aim at left_y = Levelpos[Level[v]]; right_y = left_y; for(int n = 0, m = n_forward-1; n <= m;) { if(Nodepos[edges[n]->node] <= Nodepos[v]) downspline(v,edges[n++],left_y,right_y); if(m >= n && Nodepos[edges[m]->node] > Nodepos[v]) downspline(v,edges[m--],left_y,right_y); } } // fix up the down end-points of edges so they won't intersect for(v = 0; v < N_real_nodes; ++v) { int n_forward = 0; for(edge_t *e = Inedges[v]; e; e = e->next) edges[n_forward++] = e; if(n_forward >= 2) qsort((char*)edges,n_forward,sizeof(edges[0]),(qsortcmpfun)adjcmp); // initialize the places in v that we can aim at int left_y = Levelpos[Level[v]], right_y; right_y = left_y; for(int n = 0, m = n_forward-1; n <= m;) { if(Nodepos[edges[n]->node] <= Nodepos[v]) upspline(v,edges[n++],left_y,right_y); if(m >= n && Nodepos[edges[m]->node] > Nodepos[v]) upspline(v,edges[m--],left_y,right_y); } } delete edges; if(Verbose) { times(&endtm); int total = (endtm.tms_utime-begtm.tms_utime) + (endtm.tms_stime-begtm.tms_stime); int percent = (total - (total/TIC)*TIC)*100/TIC; #ifdef TIMING fprintf(stderr,"%d.%02d\t",total/TIC,percent); #else fprintf(stderr,"Time in making splines: %d.%02ds\n", total/TIC, percent); #endif } }