void fastgr(graph_t * g) { int i, j; node_t *n, *w; edge_t *e, *f; for (n = GD_nlist(g); n; n = ND_next(n)) { fprintf(stderr, "%s %d: (", NAME(n), ND_rank(n)); for (i = 0; e = ND_out(n).list[i]; i++) { fprintf(stderr, " %s:%d", NAME(e->head), ED_count(e)); w = e->head; if (g == g->root) { for (j = 0; f = ND_in(w).list[j]; j++) if (e == f) break; assert(f != NULL); } } fprintf(stderr, " ) ("); for (i = 0; e = ND_in(n).list[i]; i++) { fprintf(stderr, " %s:%d", NAME(e->tail), ED_count(e)); w = e->tail; if (g == g->root) { for (j = 0; f = ND_out(w).list[j]; j++) if (e == f) break; assert(f != NULL); } } fprintf(stderr, " )\n"); } }
static void unrep(edge_t * rep, edge_t * e) { ED_count(rep) -= ED_count(e); ED_xpenalty(rep) -= ED_xpenalty(e); ED_weight(rep) -= ED_weight(e); }
/* new_virtual_edge: * Create and return a new virtual edge e attached to orig. * ED_to_orig(e) = orig * ED_to_virt(orig) = e if e is the first virtual edge attached. * orig might be an input edge, reverse of an input edge, or virtual edge */ edge_t *new_virtual_edge(node_t * u, node_t * v, edge_t * orig) { edge_t *e; e = NEW(edge_t); e->tail = u; e->head = v; ED_edge_type(e) = VIRTUAL; if (orig) { e->id = orig->id; ED_count(e) = ED_count(orig); ED_xpenalty(e) = ED_xpenalty(orig); ED_weight(e) = ED_weight(orig); ED_minlen(e) = ED_minlen(orig); if (e->tail == orig->tail) ED_tail_port(e) = ED_tail_port(orig); else if (e->tail == orig->head) ED_tail_port(e) = ED_head_port(orig); if (e->head == orig->head) ED_head_port(e) = ED_head_port(orig); else if (e->head == orig->tail) ED_head_port(e) = ED_tail_port(orig); if (ED_to_virt(orig) == NULL) ED_to_virt(orig) = e; ED_to_orig(e) = orig; } else ED_minlen(e) = ED_count(e) = ED_xpenalty(e) = ED_weight(e) = 1; return e; }
void basic_merge(edge_t *e, edge_t *rep) { if (ED_minlen(rep) < ED_minlen(e)) ED_minlen(rep) = ED_minlen(e); while (rep) { ED_count(rep) += ED_count(e); ED_xpenalty(rep) += ED_xpenalty(e); ED_weight(rep) += ED_weight(e); rep = ED_to_virt(rep); } }
/* makeSelfArcs: * Generate loops. We use the library routine makeSelfEdge * which also places the labels. * We have to handle port labels here. * as well as update the bbox from edge labels. */ void makeSelfArcs(path * P, edge_t * e, int stepx) { int cnt = ED_count(e); if ((cnt == 1) || Concentrate) { edge_t *edges1[1]; edges1[0] = e; makeSelfEdge(P, edges1, 0, 1, stepx, stepx, &sinfo); if (ED_label(e)) updateBB(agraphof(agtail(e)), ED_label(e)); makePortLabels(e); } else { int i; edge_t **edges = N_GNEW(cnt, edge_t *); for (i = 0; i < cnt; i++) { edges[i] = e; e = ED_to_virt(e); } makeSelfEdge(P, edges, 0, cnt, stepx, stepx, &sinfo); for (i = 0; i < cnt; i++) { e = edges[i]; if (ED_label(e)) updateBB(agraphof(agtail(e)), ED_label(e)); makePortLabels(e); } free(edges); } }
static void dot_init_edge(edge_t * e) { char *tailgroup, *headgroup; #ifdef WITH_CGRAPH agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE); //graph custom data #endif /* WITH_CGRAPH */ common_init_edge(e); ED_weight(e) = late_double(e, E_weight, 1.0, 0.0); tailgroup = late_string(agtail(e), N_group, ""); headgroup = late_string(aghead(e), N_group, ""); ED_count(e) = ED_xpenalty(e) = 1; if (tailgroup[0] && (tailgroup == headgroup)) { ED_xpenalty(e) = CL_CROSS; ED_weight(e) *= 100; } if (nonconstraint_edge(e)) { ED_xpenalty(e) = 0; ED_weight(e) = 0; } ED_showboxes(e) = late_int(e, E_showboxes, 0, 0); ED_minlen(e) = late_int(e, E_minlen, 1, 0); }
static void *newitem(Dt_t * d, edgeitem * obj, Dtdisc_t * disc) { edgeitem *newp; NOTUSED(disc); newp = NEW(edgeitem); newp->id = obj->id; newp->e = obj->e; ED_count(newp->e) = 1; return newp; }
/* dumpE: */ void dumpE(graph_t * g, int derived) { Agnode_t *n; Agedge_t *e; Agedge_t **ep; Agedge_t *el; int i; int deg; prIndent(); fprintf(stderr, "Graph %s : %d nodes %d edges\n", g->name, agnnodes(g), agnedges(g)); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { deg = 0; for (e = agfstout(g, n); e; e = agnxtout(g, e)) { deg++; prIndent(); fprintf(stderr, " %s -- %s\n", e->tail->name, e->head->name); if (derived) { for (i = 0, ep = (Agedge_t **) ED_to_virt(e); i < ED_count(e); i++, ep++) { el = *ep; prIndent(); fprintf(stderr, " %s -- %s\n", el->tail->name, el->head->name); } } } if (deg == 0) { /* no out edges */ if (!agfstin(g, n)) /* no in edges */ fprintf(stderr, " %s\n", n->name); } } if (!derived) { bport_t *pp; if ((pp = PORTS(g))) { int sz = NPORTS(g); fprintf(stderr, " %d ports\n", sz); while (pp->e) { fprintf(stderr, " %s : %s -- %s\n", pp->n->name, pp->e->tail->name, pp->e->head->name); pp++; } } } }
void unmerge_oneway(edge_t *e) { edge_t *rep,*nextrep; for (rep = ED_to_virt(e); rep; rep = nextrep) { unrep(rep,e); nextrep = ED_to_virt(rep); if (ED_count(rep) == 0) safe_delete_fast_edge(rep); /* free(rep)? */ /* unmerge from a virtual edge chain */ while ((ED_edge_type(rep) == VIRTUAL) && (ND_node_type(rep->head) == VIRTUAL) && (ND_out(rep->head).size == 1)) { rep = ND_out(rep->head).list[0]; unrep(rep,e); } } ED_to_virt(e) = NULL; }
static void printpath(path * pp) { int bi; #ifdef NOTNOW fprintf(stderr, "edge %d from %s to %s\n", nedges, realedge->tail->name, realedge->head->name); if (ED_count(origedge) > 1) fprintf(stderr, " (it's part of a concentrator edge)\n"); #endif fprintf(stderr, "%d boxes:\n", pp->nbox); for (bi = 0; bi < pp->nbox; bi++) fprintf(stderr, "%d (%.5g, %.5g), (%.5g, %.5g)\n", bi, pp->boxes[bi].LL.x, pp->boxes[bi].LL.y, pp->boxes[bi].UR.x, pp->boxes[bi].UR.y); fprintf(stderr, "start port: (%.5g, %.5g), tangent angle: %.5g, %s\n", pp->start.p.x, pp->start.p.y, pp->start.theta, pp->start.constrained ? "constrained" : "not constrained"); fprintf(stderr, "end port: (%.5g, %.5g), tangent angle: %.5g, %s\n", pp->end.p.x, pp->end.p.y, pp->end.theta, pp->end.constrained ? "constrained" : "not constrained"); }
static void dot_init_edge(edge_t * e) { char *tailgroup, *headgroup; common_init_edge(e); ED_weight(e) = late_double(e, E_weight, 1.0, 0.0); tailgroup = late_string(e->tail, N_group, ""); headgroup = late_string(e->head, N_group, ""); ED_count(e) = ED_xpenalty(e) = 1; if (tailgroup[0] && (tailgroup == headgroup)) { ED_xpenalty(e) = CL_CROSS; ED_weight(e) *= 100; } if (nonconstraint_edge(e)) { ED_xpenalty(e) = 0; ED_weight(e) = 0; } ED_showboxes(e) = late_int(e, E_showboxes, 0, 0); ED_minlen(e) = late_int(e, E_minlen, 1, 0); }
/* makeStraightEdge: * * FIX: handle ports on boundary? */ void makeStraightEdge(graph_t * g, edge_t * e, int et, splineInfo* sinfo) { pointf dumb[4]; node_t *n = agtail(e); node_t *head = aghead(e); int e_cnt = ED_count(e); int curved = (et == ET_CURVED); pointf perp; pointf del; edge_t *e0; int i, j, xstep, dx; double l_perp; pointf dumber[4]; pointf p, q; p = dumb[1] = dumb[0] = add_pointf(ND_coord(n), ED_tail_port(e).p); q = dumb[2] = dumb[3] = add_pointf(ND_coord(head), ED_head_port(e).p); if ((e_cnt == 1) || Concentrate) { if (curved) bend(dumb,get_centroid(g)); clip_and_install(e, aghead(e), dumb, 4, sinfo); addEdgeLabels(g, e, p, q); return; } e0 = e; if (APPROXEQPT(dumb[0], dumb[3], MILLIPOINT)) { /* degenerate case */ dumb[1] = dumb[0]; dumb[2] = dumb[3]; del.x = 0; del.y = 0; } else { perp.x = dumb[0].y - dumb[3].y; perp.y = dumb[3].x - dumb[0].x; l_perp = LEN(perp.x, perp.y); xstep = GD_nodesep(g->root); dx = xstep * (e_cnt - 1) / 2; dumb[1].x = dumb[0].x + (dx * perp.x) / l_perp; dumb[1].y = dumb[0].y + (dx * perp.y) / l_perp; dumb[2].x = dumb[3].x + (dx * perp.x) / l_perp; dumb[2].y = dumb[3].y + (dx * perp.y) / l_perp; del.x = -xstep * perp.x / l_perp; del.y = -xstep * perp.y / l_perp; } for (i = 0; i < e_cnt; i++) { if (aghead(e0) == head) { p = dumb[0]; q = dumb[3]; for (j = 0; j < 4; j++) { dumber[j] = dumb[j]; } } else { p = dumb[3]; q = dumb[0]; for (j = 0; j < 4; j++) { dumber[3 - j] = dumb[j]; } } if (et == ET_PLINE) { Ppoint_t pts[4]; Ppolyline_t spl, line; line.pn = 4; line.ps = pts; for (j=0; j < 4; j++) { pts[j] = dumber[j]; } make_polyline (line, &spl); clip_and_install(e0, aghead(e0), spl.ps, spl.pn, sinfo); } else clip_and_install(e0, aghead(e0), dumber, 4, sinfo); addEdgeLabels(g, e0, p, q); e0 = ED_to_virt(e0); dumb[1].x += del.x; dumb[1].y += del.y; dumb[2].x += del.x; dumb[2].y += del.y; } }
/* this function marks every node in <g> with its top-level cluster under <g> */ void mark_clusters(graph_t * g) { int c; node_t *n, *nn, *vn; edge_t *orig, *e; graph_t *clust; /* remove sub-clusters below this level */ for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (ND_ranktype(n) == CLUSTER) UF_singleton(n); ND_clust(n) = NULL; } for (c = 1; c <= GD_n_cluster(g); c++) { clust = GD_clust(g)[c]; for (n = agfstnode(clust); n; n = nn) { nn = agnxtnode(clust,n); if (ND_ranktype(n) != NORMAL) { agerr(AGWARN, "%s was already in a rankset, deleted from cluster %s\n", agnameof(n), agnameof(g)); agdelete(clust,n); continue; } UF_setname(n, GD_leader(clust)); ND_clust(n) = clust; ND_ranktype(n) = CLUSTER; /* here we mark the vnodes of edges in the cluster */ for (orig = agfstout(clust, n); orig; orig = agnxtout(clust, orig)) { if ((e = ED_to_virt(orig))) { #ifndef WITH_CGRAPH while (e && (vn = e->head)->u.node_type == VIRTUAL) { #else /* WITH_CGRAPH */ while (e && ND_node_type(vn =aghead(e)) == VIRTUAL) { #endif /* WITH_CGRAPH */ ND_clust(vn) = clust; e = ND_out(aghead(e)).list[0]; /* trouble if concentrators and clusters are mixed */ } } } } } } void build_skeleton(graph_t * g, graph_t * subg) { int r; node_t *v, *prev, *rl; edge_t *e; prev = NULL; GD_rankleader(subg) = N_NEW(GD_maxrank(subg) + 2, node_t *); for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) { v = GD_rankleader(subg)[r] = virtual_node(g); ND_rank(v) = r; ND_ranktype(v) = CLUSTER; ND_clust(v) = subg; if (prev) { e = virtual_edge(prev, v, NULL); ED_xpenalty(e) *= CL_CROSS; } prev = v; } /* set the counts on virtual edges of the cluster skeleton */ for (v = agfstnode(subg); v; v = agnxtnode(subg, v)) { rl = GD_rankleader(subg)[ND_rank(v)]; ND_UF_size(rl)++; for (e = agfstout(subg, v); e; e = agnxtout(subg, e)) { for (r = ND_rank(agtail(e)); r < ND_rank(aghead(e)); r++) { ED_count(ND_out(rl).list[0])++; } } } for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) { rl = GD_rankleader(subg)[r]; if (ND_UF_size(rl) > 1) ND_UF_size(rl)--; } }
static void map_path(node_t * from, node_t * to, edge_t * orig, edge_t * ve, int type) { int r; node_t *u, *v; edge_t *e; assert(ND_rank(from) < ND_rank(to)); if ((agtail(ve) == from) && (aghead(ve) == to)) return; if (ED_count(ve) > 1) { ED_to_virt(orig) = NULL; if (ND_rank(to) - ND_rank(from) == 1) { if ((e = find_fast_edge(from, to)) && (ports_eq(orig, e))) { merge_oneway(orig, e); if ((ND_node_type(from) == NORMAL) && (ND_node_type(to) == NORMAL)) other_edge(orig); return; } } u = from; for (r = ND_rank(from); r < ND_rank(to); r++) { if (r < ND_rank(to) - 1) v = clone_vn(agraphof(from), aghead(ve)); else v = to; e = virtual_edge(u, v, orig); ED_edge_type(e) = type; u = v; ED_count(ve)--; ve = ND_out(aghead(ve)).list[0]; } } else { if (ND_rank(to) - ND_rank(from) == 1) { if ((ve = find_fast_edge(from, to)) && (ports_eq(orig, ve))) { /*ED_to_orig(ve) = orig; */ ED_to_virt(orig) = ve; ED_edge_type(ve) = type; ED_count(ve)++; if ((ND_node_type(from) == NORMAL) && (ND_node_type(to) == NORMAL)) other_edge(orig); } else { ED_to_virt(orig) = NULL; ve = virtual_edge(from, to, orig); ED_edge_type(ve) = type; } } if (ND_rank(to) - ND_rank(from) > 1) { e = ve; if (agtail(ve) != from) { ED_to_virt(orig) = NULL; e = ED_to_virt(orig) = virtual_edge(from, aghead(ve), orig); delete_fast_edge(ve); } else e = ve; while (ND_rank(aghead(e)) != ND_rank(to)) e = ND_out(aghead(e)).list[0]; if (aghead(e) != to) { ve = e; e = virtual_edge(agtail(e), to, orig); ED_edge_type(e) = type; delete_fast_edge(ve); } } } }
/* genroute: * Generate splines for e and cohorts. * Edges go from s to t. * Return 0 on success. */ static int genroute(graph_t* g, tripoly_t * trip, int s, int t, edge_t * e, int doPolyline) { pointf eps[2]; Pvector_t evs[2]; pointf **cpts; /* lists of control points */ Ppoly_t poly; Ppolyline_t pl, spl; int i, j; Ppolyline_t mmpl; Pedge_t *medges = N_GNEW(trip->poly.pn, Pedge_t); int pn; int mult = ED_count(e); node_t* head = aghead(e); eps[0].x = trip->poly.ps[s].x, eps[0].y = trip->poly.ps[s].y; eps[1].x = trip->poly.ps[t].x, eps[1].y = trip->poly.ps[t].y; Pshortestpath(&(trip->poly), eps, &pl); if (pl.pn == 2) { makeStraightEdge(agraphof(head), e, doPolyline); return 0; } evs[0].x = evs[0].y = 0; evs[1].x = evs[1].y = 0; if ((mult == 1) || Concentrate) { poly = trip->poly; for (j = 0; j < poly.pn; j++) { medges[j].a = poly.ps[j]; medges[j].b = poly.ps[(j + 1) % poly.pn]; } tweakPath (poly, s, t, pl); Proutespline(medges, poly.pn, pl, evs, &spl); finishEdge (g, e, spl, aghead(e) != head, eps[0], eps[1]); free(medges); return 0; } pn = 2 * (pl.pn - 1); cpts = N_NEW(pl.pn - 2, pointf *); for (i = 0; i < pl.pn - 2; i++) { cpts[i] = mkCtrlPts(t, mult+1, pl.ps[i], pl.ps[i + 1], pl.ps[i + 2], trip); if (!cpts[i]) { agerr(AGWARN, "Could not create control points for multiple spline for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e))); return 1; } } poly.ps = N_GNEW(pn, pointf); poly.pn = pn; for (i = 0; i < mult; i++) { poly.ps[0] = eps[0]; for (j = 1; j < pl.pn - 1; j++) { poly.ps[j] = cpts[j - 1][i]; } poly.ps[pl.pn - 1] = eps[1]; for (j = 1; j < pl.pn - 1; j++) { poly.ps[pn - j] = cpts[j - 1][i + 1]; } Pshortestpath(&poly, eps, &mmpl); if (doPolyline) { make_polyline (mmpl, &spl); } else { for (j = 0; j < poly.pn; j++) { medges[j].a = poly.ps[j]; medges[j].b = poly.ps[(j + 1) % poly.pn]; } tweakPath (poly, 0, pl.pn-1, mmpl); Proutespline(medges, poly.pn, mmpl, evs, &spl); } finishEdge (g, e, spl, aghead(e) != head, eps[0], eps[1]); e = ED_to_virt(e); } for (i = 0; i < pl.pn - 2; i++) free(cpts[i]); free(cpts); free(medges); free(poly.ps); return 0; }