/* * Close a graph or subgraph, freeing its storage. */ int agclose(Agraph_t * g) { Agraph_t *subg, *next_subg, *par; Agnode_t *n, *next_n; par = agparent(g); if ((par == NILgraph) && (AGDISC(g, mem)->close)) { /* free entire heap */ agmethod_delete(g, g); /* invoke user callbacks */ agfreeid(g, AGRAPH, AGID(g)); AGDISC(g, mem)->close(AGCLOS(g, mem)); /* whoosh */ return SUCCESS; } for (subg = agfstsubg(g); subg; subg = next_subg) { next_subg = agnxtsubg(subg); agclose(subg); } for (n = agfstnode(g); n; n = next_n) { next_n = agnxtnode(g, n); agdelnode(g, n); } aginternalmapclose(g); agmethod_delete(g, g); assert(dtsize(g->n_id) == 0); agdtclose(g, g->n_id); assert(dtsize(g->n_seq) == 0); agdtclose(g, g->n_seq); assert(dtsize(g->e_id) == 0); agdtclose(g, g->e_id); assert(dtsize(g->e_seq) == 0); agdtclose(g, g->e_seq); assert(dtsize(g->g_dict) == 0); agdtclose(g, g->g_dict); if (g->desc.has_attrs) agraphattr_delete(g); agrecclose((Agobj_t *) g); agfreeid(g, AGRAPH, AGID(g)); if (par) { agdelsubg(par, g); agfree(par, g); } else { Agmemdisc_t *memdisc; void *memclos, *clos; while (g->clos->cb) agpopdisc(g, g->clos->cb->f); AGDISC(g, id)->close(AGCLOS(g, id)); agstrclose(g); memdisc = AGDISC(g, mem); memclos = AGCLOS(g, mem); clos = g->clos; (memdisc->free) (memclos, g); (memdisc->free) (memclos, clos); } return SUCCESS; }
/* scAdjust: * Scale the layout. * equal > 0 => scale uniformly in x and y to remove overlaps * equal = 0 => scale separately in x and y to remove overlaps * equal < 0 => scale down uniformly in x and y to remove excess space * The last assumes there are no overlaps at present. * Based on Marriott, Stuckey, Tam and He, * "Removing Node Overlapping in Graph Layout Using Constrained Optimization", * Constraints,8(2):143--172, 2003. */ int scAdjust(graph_t * g, int equal) { int nnodes = agnnodes(g); info *nlist = N_GNEW(nnodes, info); info *p = nlist; node_t *n; pointf s; int i; double margin; pointf *aarr; int m; margin = expFactor (g); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { double w2 = margin * ND_width(n) / 2.0; double h2 = margin * ND_height(n) / 2.0; p->pos.x = ND_pos(n)[0]; p->pos.y = ND_pos(n)[1]; p->bb.LL.x = p->pos.x - w2; p->bb.LL.y = p->pos.y - h2; p->bb.UR.x = p->pos.x + w2; p->bb.UR.y = p->pos.y + h2; p->wd2 = w2; p->ht2 = h2; p->np = n; p++; } if (equal < 0) { s.x = s.y = compress(nlist, nnodes); if (s.x == 0) { /* overlaps exist */ free(nlist); return 0; } fprintf(stderr, "compress %g \n", s.x); } else { aarr = mkOverlapSet(nlist, nnodes, &m); if (m == 0) { /* no overlaps */ free(aarr); free(nlist); return 0; } if (equal) { s.x = s.y = computeScale(aarr, m); } else { s = computeScaleXY(aarr, m); } free(aarr); } p = nlist; for (i = 0; i < nnodes; i++) { ND_pos(p->np)[0] = s.x * p->pos.x; ND_pos(p->np)[1] = s.y * p->pos.y; p++; } free(nlist); return 1; }
static void sfdpLayout(graph_t * g, spring_electrical_control ctrl, int hops, pointf pad) { real *sizes; real *pos; Agnode_t *n; int flag, i; int n_edge_label_nodes = 0, *edge_label_nodes = NULL; SparseMatrix D = NULL; SparseMatrix A; if (ctrl->method == METHOD_SPRING_MAXENT) /* maxent can work with distance matrix */ A = makeMatrix(g, Ndim, &D); else A = makeMatrix(g, Ndim, NULL); if (ctrl->overlap >= 0) { if (ctrl->edge_labeling_scheme > 0) sizes = getSizes(g, pad, &n_edge_label_nodes, &edge_label_nodes); else sizes = getSizes(g, pad, NULL, NULL); } else sizes = NULL; pos = getPos(g, ctrl); switch (ctrl->method) { case METHOD_SPRING_ELECTRICAL: case METHOD_SPRING_MAXENT: multilevel_spring_electrical_embedding(Ndim, A, D, ctrl, NULL, sizes, pos, n_edge_label_nodes, edge_label_nodes, &flag); break; case METHOD_UNIFORM_STRESS: uniform_stress(Ndim, A, pos, &flag); break; case METHOD_STRESS:{ int maxit = 200; real tol = 0.001; int weighted = TRUE; if (!D){ D = SparseMatrix_get_real_adjacency_matrix_symmetrized(A);/* all distance 1 */ weighted = FALSE; } else { D = SparseMatrix_symmetrize_nodiag(D, FALSE); weighted = TRUE; } if (hops > 0){ SparseMatrix DD; DD = SparseMatrix_distance_matrix_khops(hops, D, weighted); if (Verbose){ fprintf(stderr,"extracted a %d-neighborhood graph of %d edges from a graph of %d edges\n", hops, (DD->nz)/2, (D->nz/2)); } SparseMatrix_delete(D); D = DD; } stress_model(Ndim, A, D, &pos, TRUE, maxit, tol, &flag); } break; } for (n = agfstnode(g); n; n = agnxtnode(g, n)) { real *npos = pos + (Ndim * ND_id(n)); for (i = 0; i < Ndim; i++) { ND_pos(n)[i] = npos[i]; } } free(sizes); free(pos); SparseMatrix_delete (A); if (D) SparseMatrix_delete (D); if (edge_label_nodes) FREE(edge_label_nodes); }
/* mkConstraintG: */ static graph_t *mkConstraintG(graph_t * g, Dt_t * list, intersectfn intersect, distfn dist) { nitem *p; nitem *nxt = NULL; nitem *nxp; graph_t *cg = agopen("cg", AGDIGRAPHSTRICT); graph_t *vg; node_t *prev = NULL; node_t *root = NULL; node_t *n = NULL; edge_t *e; int lcnt, cnt; int oldval = -MAXINT; #ifdef OLD double root_val; #endif node_t *lastn = NULL; /* count distinct nodes */ cnt = 0; for (p = (nitem *) dtflatten(list); p; p = (nitem *) dtlink(list, (Dtlink_t *) p)) { if (oldval != p->val) { oldval = p->val; cnt++; } } /* construct basic chain to enforce left to right order */ oldval = -MAXINT; lcnt = 0; for (p = (nitem *) dtflatten(list); p; p = (nitem *) dtlink(list, (Dtlink_t *) p)) { if (oldval != p->val) { oldval = p->val; /* n = newNode (cg); */ n = agnode(cg, p->np->name); /* FIX */ ND_alg(n) = p; if (root) { ND_next(lastn) = n; lastn = n; } else { root = n; #ifdef OLD root_val = p->val; #endif lastn = GD_nlist(cg) = n; } alloc_elist(lcnt, ND_in(n)); if (prev) { if (prev == root) alloc_elist(2 * (cnt - 1), ND_out(prev)); else alloc_elist(cnt - lcnt - 1, ND_out(prev)); e = agedge(cg, prev, n); ED_minlen(e) = SCALE; ED_weight(e) = 1; elist_append(e, ND_out(prev)); elist_append(e, ND_in(n)); } lcnt++; prev = n; } p->cnode = n; } alloc_elist(0, ND_out(prev)); /* add immediate right neighbor constraints * Construct visibility graph, then perform transitive reduction. * Remaining outedges are immediate right neighbors. * FIX: Incremental algorithm to construct trans. reduction? */ vg = agopen("vg", AGDIGRAPHSTRICT); for (p = (nitem *) dtflatten(list); p; p = (nitem *) dtlink(list, (Dtlink_t *) p)) { n = agnode(vg, p->np->name); p->vnode = n; ND_alg(n) = p; } oldval = -MAXINT; for (p = (nitem *) dtflatten(list); p; p = (nitem *) dtlink(list, (Dtlink_t *) p)) { if (oldval != p->val) { /* new pos: reset nxt */ oldval = p->val; for (nxt = (nitem *) dtlink(link, (Dtlink_t *) p); nxt; nxt = (nitem *) dtlink(list, (Dtlink_t *) nxt)) { if (nxt->val != oldval) break; } if (!nxt) break; } for (nxp = nxt; nxp; nxp = (nitem *) dtlink(list, (Dtlink_t *) nxp)) { if (intersect(p, nxp)) agedge(vg, p->vnode, nxp->vnode); } } /* Remove redundant constraints here. However, the cost of doing this * may be a good deal more than the time saved in network simplex. Also, * if the graph is changed, the ND_in and ND_out data has to be updated. */ mapGraphs(vg, cg, dist); agclose(vg); /* add dummy constraints for absolute values and initial positions */ #ifdef OLD for (n = agfstnode(cg); n; n = agnxtnode(cg, n)) { node_t *vn; /* slack node for absolute value */ node_t *an; /* node representing original position */ p = (nitem *) ND_alg(n); if ((n == root) || (!p)) continue; vn = newNode(cg); ND_next(lastn) = vn; lastn = vn; alloc_elist(0, ND_out(vn)); alloc_elist(2, ND_in(vn)); an = newNode(cg); ND_next(lastn) = an; lastn = an; alloc_elist(1, ND_in(an)); alloc_elist(1, ND_out(an)); e = agedge(cg, root, an); ED_minlen(e) = p->val - root_val; elist_append(e, ND_out(root)); elist_append(e, ND_in(an)); e = agedge(cg, an, vn); elist_append(e, ND_out(an)); elist_append(e, ND_in(vn)); e = agedge(cg, n, vn); elist_append(e, ND_out(n)); elist_append(e, ND_in(vn)); } #endif return cg; }
/* cAdjust: * Use optimization to remove overlaps. * Modifications; * - do y;x then x;y and use the better one * - for all overlaps (or if overlap with leftmost nodes), add a constraint; * constraint could move both x and y away, or the smallest, or some * mixture. * - follow by a scale down using actual shapes * We use an optimization based on Marriott, Stuckey, Tam and He, * "Removing Node Overlapping in Graph Layout Using Constrained Optimization", * Constraints,8(2):143--172, 2003. * We solve 2 constraint problem, one in X, one in Y. In each dimension, * we require relative positions to remain the same. That is, if two nodes * have the same x originally, they have the same x at the end, and if one * node is to the left of another, it remains to the left. In addition, if * two nodes could overlap by moving their X coordinates, we insert a constraint * to keep the two nodes sufficiently apart. Similarly, for Y. * * mode = AM_ORTHOXY => first X, then Y * mode = AM_ORTHOYX => first Y, then X * mode = AM_ORTHO => first X, then Y * mode = AM_ORTHO_YX => first Y, then X * In the last 2 cases, relax the constraints as follows: during the X pass, * if two nodes actually intersect and a smaller move in the Y direction * will remove the overlap, we don't force the nodes apart in the X direction, * but leave it for the Y pass to remove any remaining overlaps. Without this, * the X pass will remove all overlaps, and the Y pass only compresses in the * Y direction, causing a skewing of the aspect ratio. * * mode = AM_ORTHOXY => first X, then Y * mode = AM_ORTHOYX => first Y, then X * mode = AM_ORTHO => first X, then Y * mode = AM_ORTHO_YX => first Y, then X */ int cAdjust(graph_t * g, int mode) { double margin; int ret, i, nnodes = agnnodes(g); nitem *nlist = N_GNEW(nnodes, nitem); nitem *p = nlist; node_t *n; margin = expFactor (g); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { initItem(n, p, margin); p++; } if (overlaps(nlist, nnodes)) { point pt; switch ((adjust_mode)mode) { case AM_ORTHOXY: constrainX(g, nlist, nnodes, intersectY, 1); constrainY(g, nlist, nnodes, intersectX, 1); break; case AM_ORTHOYX: constrainY(g, nlist, nnodes, intersectX, 1); constrainX(g, nlist, nnodes, intersectY, 1); break; case AM_ORTHO : constrainX(g, nlist, nnodes, intersectY0, 1); constrainY(g, nlist, nnodes, intersectX, 1); case AM_ORTHO_YX : constrainY(g, nlist, nnodes, intersectX0, 1); constrainX(g, nlist, nnodes, intersectY, 1); case AM_PORTHOXY: constrainX(g, nlist, nnodes, intersectY, 0); constrainY(g, nlist, nnodes, intersectX, 0); break; case AM_PORTHOYX: constrainY(g, nlist, nnodes, intersectX, 0); constrainX(g, nlist, nnodes, intersectY, 0); break; case AM_PORTHO_YX : constrainY(g, nlist, nnodes, intersectX0, 0); constrainX(g, nlist, nnodes, intersectY, 0); break; case AM_PORTHO : default : constrainX(g, nlist, nnodes, intersectY0, 0); constrainY(g, nlist, nnodes, intersectX, 0); break; } p = nlist; for (i = 0; i < nnodes; i++) { n = p->np; pt = p->pos; ND_pos(n)[0] = PS2INCH(pt.x) / SCALE; ND_pos(n)[1] = PS2INCH(pt.y) / SCALE; p++; } ret = 1; } else ret = 0; free(nlist); return ret; }
static void color(Agraph_t * g) { int nn, i, j, cnt; Agnode_t *n, *v, **nlist; Agedge_t *e; char *p; double x, y, maxrank = 0.0; double sum[NC], d, lowsat, highsat; if (agattr(g, AGNODE, "pos", 0) == NULL) { fprintf(stderr, "graph must be run through 'dot' before 'gvcolor'\n"); exit(1); } aginit(g, AGNODE, "nodeinfo", sizeof(Agnodeinfo_t), TRUE); if (agattr(g, AGNODE, "style", 0) == NULL) agattr(g, AGNODE, "style", "filled"); if ((p = agget(g, "Defcolor"))) setcolor(p, Defcolor); if ((p = agget(g, "rankdir")) && (p[0] == 'L')) LR = 1; if ((p = agget(g, "flow")) && (p[0] == 'b')) Forward = 0; if ((p = agget(g, "saturation"))) { if (sscanf(p, "%lf,%lf", &lowsat, &highsat) == 2) { MinRankSaturation = lowsat; MaxRankSaturation = highsat; AdjustSaturation = 1; } } /* assemble the sorted list of nodes and store the initial colors */ nn = agnnodes(g); nlist = (Agnode_t **) malloc(nn * sizeof(Agnode_t *)); i = 0; for (n = agfstnode(g); n; n = agnxtnode(g, n)) { nlist[i++] = n; if ((p = agget(n, "color"))) setcolor(p, ND_x(n)); p = agget(n, "pos"); sscanf(p, "%lf,%lf", &x, &y); ND_relrank(n) = (LR ? x : y); if (maxrank < ND_relrank(n)) maxrank = ND_relrank(n); } if (LR != Forward) for (i = 0; i < nn; i++) { n = nlist[i]; ND_relrank(n) = maxrank - ND_relrank(n); } qsort((void *) nlist, (size_t) nn, sizeof(Agnode_t *), (int (*)(const void *, const void *)) cmpf); /* this is the pass that pushes the colors through the edges */ for (i = 0; i < nn; i++) { n = nlist[i]; /* skip nodes that were manually colored */ cnt = 0; for (j = 0; j < NC; j++) if (ND_x(n)[j] != 0.0) cnt++; if (cnt > 0) continue; for (j = 0; j < NC; j++) sum[j] = 0.0; cnt = 0; for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) { v = aghead(e); if (v == n) v = agtail(e); d = ND_relrank(v) - ND_relrank(n) - 0.01; if (d < 0) { double t = 0.0; for (j = 0; j < NC; j++) { t += ND_x(v)[j]; sum[j] += ND_x(v)[j]; } if (t > 0.0) cnt++; } } if (cnt) for (j = 0; j < NC; j++) ND_x(n)[j] = sum[j] / cnt; } /* apply saturation adjustment and convert color to string */ for (i = 0; i < nn; i++) { double h, s, b, t; char buf[64]; n = nlist[i]; t = 0.0; for (j = 0; j < NC; j++) t += ND_x(n)[j]; if (t > 0.0) { h = ND_x(n)[0]; if (AdjustSaturation) { s = ND_relrank(n) / maxrank; if (!Forward) s = 1.0 - s; s = MinRankSaturation + s * (MaxRankSaturation - MinRankSaturation); } else s = 1.0; s = s * ND_x(n)[1]; b = ND_x(n)[2]; } else { h = Defcolor[0]; s = Defcolor[1]; b = Defcolor[2]; } sprintf(buf, "%f %f %f", h, s, b); agset(n, "color", buf); } }
/* orthoEdges: * For edges without position information, construct an orthogonal routing. * If doLbls is true, use edge label info when available to guide routing, * and set label pos for those edges for which this info is not available. */ void orthoEdges (Agraph_t* g, int doLbls) { sgraph* sg; maze* mp; int n_edges; route* route_list; int i, gstart; Agnode_t* n; Agedge_t* e; snode* sn; snode* dn; epair_t* es = N_GNEW(agnedges(g), epair_t); cell* start; cell* dest; PointSet* ps; textlabel_t* lbl; if (Concentrate) ps = newPS(); #ifdef DEBUG { char* s = agget(g, "odb"); char c; odb_flags = 0; if (s && (*s != '\0')) { while ((c = *s++)) { switch (c) { case 'c' : odb_flags |= ODB_CHANG; // emit channel graph break; case 'i' : odb_flags |= (ODB_SGRAPH|ODB_IGRAPH); // emit search graphs break; case 'm' : odb_flags |= ODB_MAZE; // emit maze break; case 'r' : odb_flags |= ODB_ROUTE; // emit routes in maze break; case 's' : odb_flags |= ODB_SGRAPH; // emit search graph break; } } } } #endif mp = mkMaze (g, doLbls); sg = mp->sg; #ifdef DEBUG if (odb_flags & ODB_SGRAPH) emitSearchGraph (stderr, sg); #endif /* store edges to be routed in es, along with their lengths */ n_edges = 0; for (n = agfstnode (g); n; n = agnxtnode(g, n)) { for (e = agfstout(g, n); e; e = agnxtout(g,e)) { if ((Nop == 2) && ED_spl(e)) continue; if (Concentrate) { int ti = AGID(agtail(e)); int hi = AGID(aghead(e)); if (ti <= hi) { if (isInPS (ps,ti,hi)) continue; else addPS (ps,ti,hi); } else { if (isInPS (ps,hi,ti)) continue; else addPS (ps,hi,ti); } } es[n_edges].e = e; es[n_edges].d = edgeLen (e); n_edges++; } } route_list = N_NEW (n_edges, route); qsort((char *)es, n_edges, sizeof(epair_t), (qsort_cmpf) edgecmp); gstart = sg->nnodes; PQgen (sg->nnodes+2); sn = &sg->nodes[gstart]; dn = &sg->nodes[gstart+1]; for (i = 0; i < n_edges; i++) { #ifdef DEBUG if ((i > 0) && (odb_flags & ODB_IGRAPH)) emitSearchGraph (stderr, sg); #endif e = es[i].e; start = CELL(agtail(e)); dest = CELL(aghead(e)); if (doLbls && (lbl = ED_label(e)) && lbl->set) { } else { if (start == dest) addLoop (sg, start, dn, sn); else { addNodeEdges (sg, dest, dn); addNodeEdges (sg, start, sn); } shortPath (sg, dn, sn); } route_list[i] = convertSPtoRoute(sg, sn, dn); reset (sg); } PQfree (); mp->hchans = extractHChans (mp); mp->vchans = extractVChans (mp); assignSegs (n_edges, route_list, mp); assignTracks (n_edges, route_list, mp); #ifdef DEBUG if (odb_flags & ODB_ROUTE) emitGraph (stderr, mp, n_edges, route_list, es); #endif attachOrthoEdges (g, mp, n_edges, route_list, &sinfo, es, doLbls); if (Concentrate) freePS (ps); for (i=0; i < n_edges; i++) free (route_list[i].segs); free (route_list); freeMaze (mp); }
void write_plainstr(graph_t* g, std::string *str) { int i; node_t *n; edge_t *e; bezier bz; char buf[SMALLBUF],buf1[SMALLBUF]; char tmpbuf[1000]; setup_graph(g); sprintf(tmpbuf, "graph %.3f", g->u.drawing->scale); str->append(tmpbuf); printptf(str, g->u.bb.UR); str->append("\n"); for (n = agfstnode(g); n; n = agnxtnode(g,n)) { str->append("node "); str->append(agstrcanon(n->name,buf)); printptf(str,n->u.coord); sprintf(tmpbuf, " %.3f", n->u.width); str->append(tmpbuf); sprintf(tmpbuf, " %.3f ", n->u.height); str->append(tmpbuf); str->append(agstrcanon(n->u.label->text,buf)); str->append(" "); str->append(late_nnstring(n,N_style,"solid")); str->append(" "); str->append(n->u.shape->name); str->append(" "); str->append(late_nnstring(n,N_color,DEFAULT_COLOR)); str->append(" "); str->append(late_nnstring(n,N_fillcolor,DEFAULT_FILL)); str->append("\n"); } for (n = agfstnode(g); n; n = agnxtnode(g,n)) { for (e = agfstout(g,n); e; e = agnxtout(g,e)) { bz = e->u.spl->list[0]; str->append("edge "); str->append(agstrcanon(e->tail->name,buf)); str->append(" "); str->append(agstrcanon(e->head->name,buf1)); str->append(" "); sprintf(tmpbuf, " %d", bz.size); str->append(tmpbuf); for (i = 0; i < bz.size; i++) printptf(str,bz.list[i]); if (e->u.label) { str->append(" "); str->append(agstrcanon(e->u.label->text,buf)); printptf(str,e->u.label->p); } str->append(" "); str->append(late_nnstring(e,E_style,"solid")); str->append(" "); str->append(late_nnstring(e,E_color,DEFAULT_COLOR)); str->append("\n"); } } str->append("stop\n"); }
static void write_subg(Agraph_t * g, FILE * fp, Agraph_t * par, int indent, printdict_t * state) { Agraph_t *subg, *meta; Agnode_t *n, *pn; Agedge_t *e, *pe; Dt_t *save_e, *save_n; if (indent) { tabover(fp, indent++); if (dtsearch(state->subgleft, g->meta_node)) { if (strncmp(g->name, "_anonymous", 10)) { agputs("subgraph ", fp); agputs(agcanonical(g->name), fp); agputs(" {\n", fp); } else { agputs("{\n", fp); /* no name printed for anonymous subg */ } write_diffattr(fp, indent, g, par, g->univ->globattr); /* The root node and edge environment use the dictionaries, * not the proto node or edge, so the next level down must * record differences with the dictionaries. */ if (par == g->root) { pn = NULL; pe = NULL; } else { pn = par->proto->n; pe = par->proto->e; } write_diffattr(fp, indent, g->proto->n, pn, g->univ->nodeattr); write_diffattr(fp, indent, g->proto->e, pe, g->univ->edgeattr); dtdelete(state->subgleft, g->meta_node); } else { agputs("subgraph ", fp); agputs(agcanonical(g->name), fp); agputs(";\n", fp); return; } } else write_diffattr(fp, ++indent, g, NULL, g->univ->globattr); save_n = state->n_insubg; save_e = state->e_insubg; meta = g->meta_node->graph; state->n_insubg = dtopen(&agNamedisc, Dtoset); state->e_insubg = dtopen(&agOutdisc, Dtoset); for (e = agfstout(meta, g->meta_node); e; e = agnxtout(meta, e)) { subg = agusergraph(e->head); write_subg(subg, fp, g, indent, state); } for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (dtsearch(state->nodesleft, n)) { agwrnode(g, fp, n, TRUE, indent); dtdelete(state->nodesleft, n); } else { if (dtsearch(state->n_insubg, n) == NULL) { agwrnode(g, fp, n, FALSE, indent); } } dtinsert(save_n, n); } dtdisc(g->outedges, &agEdgedisc, 0); /* sort by id */ for (e = (Agedge_t *) dtfirst(g->outedges); e; e = (Agedge_t *) dtnext(g->outedges, e)) { if (dtsearch(state->edgesleft, e)) { tabover(fp, indent); agwredge(g, fp, e, TRUE); dtdelete(state->edgesleft, e); } else { if (dtsearch(state->e_insubg, e) == NULL) { tabover(fp, indent); agwredge(g, fp, e, FALSE); } } dtinsert(save_e, e); } dtdisc(g->outedges, &agOutdisc, 0); /* sort by name */ dtclose(state->n_insubg); state->n_insubg = save_n; dtclose(state->e_insubg); state->e_insubg = save_e; if (indent > 1) { tabover(fp, indent - 1); agputs("}\n", fp); } }
main(int argc, char *argv[]) { Agraph_t **gs; Agraph_t **ccs; Agraph_t *g; Agraph_t *gp; char *fname; FILE *fp; int cnt; int i; init(argc, argv); if (!Files) { fprintf(stderr, "No input files given\n"); exit(1); } PSinputscale = POINTS_PER_INCH; if (doComps) { if (verbose) fprintf(stderr, "do Comps\n"); while (fname = *Files++) { fp = fopen(fname, "r"); if (!fp) { fprintf(stderr, "Could not open %s\n", fname); continue; } g = agread(fp); fclose(fp); if (!g) { fprintf(stderr, "Could not read graph\n"); continue; } printf("%s %d nodes %d edges %sconnected\n", g->name, agnnodes(g), agnedges(g), (isConnected(g) ? "" : "not ")); gs = ccomps(g, &cnt, "abc"); for (i = 0; i < cnt; i++) { gp = gs[i]; printf(" %s %d nodes %d edges\n", gp->name, agnnodes(gp), agnedges(gp)); } } } else { gs = N_GNEW(nFiles, Agraph_t *); cnt = 0; while (fname = Files[cnt]) { fp = fopen(fname, "r"); if (!fp) { fprintf(stderr, "Could not open %s\n", fname); exit(1); } g = agread(fp); fclose(fp); if (!g) { fprintf(stderr, "Could not read graph\n"); exit(1); } if (!single) { graph_init(g); ptest_initGraph(g); } initPos(g); /* if (Verbose) dumpG (g); */ gs[cnt++] = g; } if (single) { Agraph_t *root; Agnode_t *n; Agnode_t *np; Agnode_t *tp; Agnode_t *hp; Agedge_t *e; Agedge_t *ep; root = agopen("root", 0); agedgeattr(root, "pos", ""); for (i = 0; i < cnt; i++) { g = gs[i]; for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (agfindnode(root, n->name)) { fprintf(stderr, "Error: node %s in graph %d (%s) previously added\n", n->name, i, Files[i]); exit(1); } np = agnode(root, n->name); ND_pos(np)[0] = ND_pos(n)[0]; ND_pos(np)[1] = ND_pos(n)[1]; ND_coord_i(np).x = ND_coord_i(n).x; ND_coord_i(np).y = ND_coord_i(n).y; } for (n = agfstnode(g); n; n = agnxtnode(g, n)) { tp = agfindnode(root, n->name); for (e = agfstout(g, n); e; e = agnxtout(g, e)) { hp = agfindnode(root, e->head->name); ep = agedge(root, tp, hp); ED_spl(ep) = ED_spl(e); } } } graph_init(root); ptest_initGraph(root); ccs = ccomps(root, &cnt, 0); packGraphs(cnt, ccs, root, margin, doEdges); if (!doEdges) copyPos(root); else State = GVSPLINES; attach_attrs(root); for (i = 0; i < cnt; i++) { agdelete(root, ccs[i]); } agwrite(root, stdout); } else { packGraphs(cnt, gs, 0, margin, doEdges); if (doEdges) State = GVSPLINES; for (i = 0; i < cnt; i++) { if (!doEdges) copyPos(gs[i]); attach_attrs(gs[i]); agwrite(gs[i], stdout); } } } }
void attach_attrs(graph_t* g) { int i,j,sides; char buf[BUFSIZ],*p; node_t *n; edge_t *e; point pt; safe_dcl(g,g->proto->n,"pos","",agnodeattr); safe_dcl(g,g->proto->n,"rects","",agnodeattr); N_width = safe_dcl(g,g->proto->n,"width","",agnodeattr); N_height = safe_dcl(g,g->proto->n,"height","",agnodeattr); safe_dcl(g,g->proto->e,"pos","",agedgeattr); if (g->u.has_edge_labels) safe_dcl(g,g->proto->e,"lp","",agedgeattr); if (g->u.label) { safe_dcl(g,g,"lp","",agraphattr); pt = g->u.label->p; sprintf(buf,"%d,%d",pt.x,pt.y); agset(g,"lp",buf); } safe_dcl(g,g,"bb","",agraphattr); for (n = agfstnode(g); n; n = agnxtnode(g,n)) { sprintf(buf,"%d,%d",n->u.coord.x,n->u.coord.y); agset(n,"pos",buf); sprintf(buf,"%.2f",PS2INCH(n->u.ht)); agxset(n,N_height->index,buf); sprintf(buf,"%.2f",PS2INCH(n->u.lw + n->u.rw)); agxset(n,N_width->index,buf); if (strcmp (n->u.shape->name, "record") == 0) { buf[0] = '\000', rectbufp = &buf[0]; set_record_rects (n, (field_t *)(n->u.shape_info)); if (rectbufp > &buf[0]) /* get rid of last space */ *(--rectbufp) = '\000'; agset(n,"rects",buf); } else { extern void poly_init(node_t *); polygon_t *poly; int i; if (N_vertices && (n->u.shape->initfn == poly_init)) { poly = (polygon_t*) n->u.shape_info; p = buf; sides = poly->sides; if (sides < 3) { char *p = agget(n,"samplepoints"); if (p) sides = atoi(p); else sides = 8; if (sides < 3) sides = 8; } for (i = 0; i < sides; i++) { if (i > 0) {*p++ = ' ';} if (poly->sides >= 3) sprintf(p,"%.3lf %.3lf", poly->vertices[i].x,poly->vertices[i].y); else sprintf(p,"%.3lf %.3lf", n->u.width/2.0 * cos(i/(double)sides * PI * 2.0), n->u.height/2.0 * sin(i/(double)sides * PI * 2.0)); while (*p) p++; } agxset(n,N_vertices->index,buf); } } for (e = agfstout(g,n); e; e = agnxtout(g,e)) { p = buf; if (e->u.spl == NULL) {fprintf(stderr,"lost spline of %s %s\n",e->tail->name,e->head->name); continue;} for (i = 0; i < e->u.spl->size; i++) { if (i > 0) *p++ = ';'; if (e->u.spl->list[i].sflag) { sprintf (p, "s,%d,%d ",e->u.spl->list[i].sp.x,e->u.spl->list[i].sp.y); while (*p) p++; } if (e->u.spl->list[i].eflag) { sprintf (p, "e,%d,%d ",e->u.spl->list[i].ep.x,e->u.spl->list[i].ep.y); while (*p) p++; } for (j = 0; j < e->u.spl->list[i].size; j++) { if (j > 0) *p++ = ' '; pt = e->u.spl->list[i].list[j]; sprintf(p,"%d,%d",pt.x,pt.y); while (*p) p++; } *p = '\0'; } agset(e,"pos",buf); if (e->u.label) { pt = e->u.label->p; sprintf(buf,"%d,%d",pt.x,pt.y); agset(e,"lp",buf); } } } rec_attach_bb(g); }
SEXP getEdgeLocs(Agraph_t *g) { SEXP outList, curCP, curEP, pntList, pntSet, curXY, curLab; SEXP epClass, cpClass, xyClass, labClass; Agnode_t *node, *head; Agedge_t *edge; char *tmpString; bezier bez; int nodes; int i,k,l,pntLstEl; int curEle = 0; epClass = MAKE_CLASS("AgEdge"); cpClass = MAKE_CLASS("BezierCurve"); xyClass = MAKE_CLASS("xyPoint"); labClass = MAKE_CLASS("AgTextLabel"); /* tmpString is used to convert a char to a char* w/ labels */ tmpString = (char *)R_alloc(2, sizeof(char)); if (tmpString == NULL) error("Allocation error in getEdgeLocs"); PROTECT(outList = allocVector(VECSXP, agnedges(g))); nodes = agnnodes(g); node = agfstnode(g); for (i = 0; i < nodes; i++) { edge = agfstout(g, node); while (edge != NULL && edge->u.spl != NULL) { PROTECT(curEP = NEW_OBJECT(epClass)); bez = edge->u.spl->list[0]; PROTECT(pntList = allocVector(VECSXP, ((bez.size-1)/3))); pntLstEl = 0; /* There are really (bez.size-1)/3 sets of control */ /* points, with the first set containing teh first 4 */ /* points, and then every other set starting with the */ /* last point from the previous set and then the next 3 */ for (k = 1; k < bez.size; k += 3) { PROTECT(curCP = NEW_OBJECT(cpClass)); PROTECT(pntSet = allocVector(VECSXP, 4)); for (l = -1; l < 3; l++) { PROTECT(curXY = NEW_OBJECT(xyClass)); SET_SLOT(curXY, Rf_install("x"), Rf_ScalarInteger(bez.list[k+l].x)); SET_SLOT(curXY, Rf_install("y"), Rf_ScalarInteger(bez.list[k+l].y)); SET_ELEMENT(pntSet, l+1, curXY); UNPROTECT(1); } SET_SLOT(curCP, Rf_install("cPoints"), pntSet); SET_ELEMENT(pntList, pntLstEl++, curCP); UNPROTECT(2); } SET_SLOT(curEP, Rf_install("splines"), pntList); /* get the sp and ep */ PROTECT(curXY = NEW_OBJECT(xyClass)); SET_SLOT(curXY, Rf_install("x"), Rf_ScalarInteger(bez.sp.x)); SET_SLOT(curXY, Rf_install("y"), Rf_ScalarInteger(bez.sp.y)); SET_SLOT(curEP, Rf_install("sp"), curXY); UNPROTECT(1); PROTECT(curXY = NEW_OBJECT(xyClass)); SET_SLOT(curXY, Rf_install("x"), Rf_ScalarInteger(bez.ep.x)); SET_SLOT(curXY, Rf_install("y"), Rf_ScalarInteger(bez.ep.y)); SET_SLOT(curEP, Rf_install("ep"), curXY); UNPROTECT(1); SET_SLOT(curEP, Rf_install("tail"), Rgraphviz_ScalarStringOrNull(node->name)); head = edge->head; SET_SLOT(curEP, Rf_install("head"), Rgraphviz_ScalarStringOrNull(head->name)); /* TODO: clean up the use of attrs: dir, arrowhead, arrowtail. * the following are for interactive plotting in R-env, not needed * for output to files. The existing codes set "dir"-attr, but use * "arrowhead"/"arrowtail" instead. Quite confusing. */ SET_SLOT(curEP, Rf_install("dir"), Rgraphviz_ScalarStringOrNull(agget(edge, "dir"))); SET_SLOT(curEP, Rf_install("arrowhead"), Rgraphviz_ScalarStringOrNull(agget(edge, "arrowhead"))); SET_SLOT(curEP, Rf_install("arrowtail"), Rgraphviz_ScalarStringOrNull(agget(edge, "arrowtail"))); SET_SLOT(curEP, Rf_install("arrowsize"), Rgraphviz_ScalarStringOrNull(agget(edge, "arrowsize"))); SET_SLOT(curEP, Rf_install("color"), Rgraphviz_ScalarStringOrNull(agget(edge, "color"))); /* get lty/lwd info */ if ( agget(edge, "lty") ) SET_SLOT(curEP, Rf_install("lty"), Rgraphviz_ScalarStringOrNull(agget(edge, "lty"))); if ( agget(edge, "lwd") ) SET_SLOT(curEP, Rf_install("lwd"), Rgraphviz_ScalarStringOrNull(agget(edge, "lwd"))); /* Get the label information */ if (edge->u.label != NULL) { PROTECT(curLab = NEW_OBJECT(labClass)); SET_SLOT(curLab, Rf_install("labelText"), Rgraphviz_ScalarStringOrNull(ED_label(edge)->u.txt.para->str)); /* Get the X/Y location of the label */ PROTECT(curXY = NEW_OBJECT(xyClass)); #if GRAPHVIZ_MAJOR == 2 && GRAPHVIZ_MINOR > 20 SET_SLOT(curXY, Rf_install("x"), Rf_ScalarInteger(ED_label(edge)->pos.x)); SET_SLOT(curXY, Rf_install("y"), Rf_ScalarInteger(ED_label(edge)->pos.y)); #else SET_SLOT(curXY, Rf_install("x"), Rf_ScalarInteger(edge->u.label->p.x)); SET_SLOT(curXY, Rf_install("y"), Rf_ScalarInteger(edge->u.label->p.y)); #endif SET_SLOT(curLab, Rf_install("labelLoc"), curXY); UNPROTECT(1); snprintf(tmpString, 2, "%c",ED_label(edge)->u.txt.para->just); SET_SLOT(curLab, Rf_install("labelJust"), Rgraphviz_ScalarStringOrNull(tmpString)); SET_SLOT(curLab, Rf_install("labelWidth"), Rf_ScalarInteger(ED_label(edge)->u.txt.para->width)); SET_SLOT(curLab, Rf_install("labelColor"), Rgraphviz_ScalarStringOrNull(edge->u.label->fontcolor)); SET_SLOT(curLab, Rf_install("labelFontsize"), Rf_ScalarReal(edge->u.label->fontsize)); SET_SLOT(curEP, Rf_install("txtLabel"), curLab); UNPROTECT(1); } SET_ELEMENT(outList, curEle++, curEP); UNPROTECT(2); edge = agnxtout(g, edge); } node = agnxtnode(g, node); } UNPROTECT(1); return(outList); }
SEXP getNodeLayouts(Agraph_t *g) { Agnode_t *node; SEXP outLst, nlClass, xyClass, curXY, curNL; SEXP curLab, labClass; int i, nodes; char *tmpString; if (g == NULL) error("getNodeLayouts passed a NULL graph"); nlClass = MAKE_CLASS("AgNode"); xyClass = MAKE_CLASS("xyPoint"); labClass = MAKE_CLASS("AgTextLabel"); /* tmpString is used to convert a char to a char* w/ labels */ tmpString = (char *)R_alloc(2, sizeof(char)); if (tmpString == NULL) error("Allocation error in getNodeLayouts"); nodes = agnnodes(g); node = agfstnode(g); PROTECT(outLst = allocVector(VECSXP, nodes)); for (i = 0; i < nodes; i++) { PROTECT(curNL = NEW_OBJECT(nlClass)); PROTECT(curXY = NEW_OBJECT(xyClass)); SET_SLOT(curXY,Rf_install("x"),Rf_ScalarInteger(node->u.coord.x)); SET_SLOT(curXY,Rf_install("y"),Rf_ScalarInteger(node->u.coord.y)); SET_SLOT(curNL,Rf_install("center"),curXY); SET_SLOT(curNL,Rf_install("height"),Rf_ScalarInteger(node->u.ht)); SET_SLOT(curNL,Rf_install("rWidth"),Rf_ScalarInteger(node->u.rw)); SET_SLOT(curNL,Rf_install("lWidth"),Rf_ScalarInteger(node->u.lw)); SET_SLOT(curNL,Rf_install("name"), Rgraphviz_ScalarStringOrNull(node->name)); SET_SLOT(curNL, Rf_install("color"), Rgraphviz_ScalarStringOrNull(agget(node, "color"))); SET_SLOT(curNL, Rf_install("fillcolor"), Rgraphviz_ScalarStringOrNull(agget(node, "fillcolor"))); SET_SLOT(curNL, Rf_install("shape"), Rgraphviz_ScalarStringOrNull(agget(node, "shape"))); SET_SLOT(curNL, Rf_install("style"), Rgraphviz_ScalarStringOrNull(agget(node, "style"))); PROTECT(curLab = NEW_OBJECT(labClass)); if (ND_label(node) == NULL) { } else if (ND_label(node)->u.txt.para != NULL) { SET_SLOT(curLab, Rf_install("labelText"), Rgraphviz_ScalarStringOrNull(ND_label(node)->u.txt.para->str)); snprintf(tmpString, 2, "%c",ND_label(node)->u.txt.para->just); SET_SLOT(curLab, Rf_install("labelJust"), Rgraphviz_ScalarStringOrNull(tmpString)); SET_SLOT(curLab, Rf_install("labelWidth"), Rf_ScalarInteger(ND_label(node)->u.txt.para->width)); /* Get the X/Y location of the label */ PROTECT(curXY = NEW_OBJECT(xyClass)); #if GRAPHVIZ_MAJOR == 2 && GRAPHVIZ_MINOR > 20 SET_SLOT(curXY, Rf_install("x"), Rf_ScalarInteger(ND_label(node)->pos.x)); SET_SLOT(curXY, Rf_install("y"), Rf_ScalarInteger(ND_label(node)->pos.y)); #else SET_SLOT(curXY, Rf_install("x"), Rf_ScalarInteger(node->u.label->p.x)); SET_SLOT(curXY, Rf_install("y"), Rf_ScalarInteger(node->u.label->p.y)); #endif SET_SLOT(curLab, Rf_install("labelLoc"), curXY); UNPROTECT(1); SET_SLOT(curLab, Rf_install("labelColor"), Rgraphviz_ScalarStringOrNull(node->u.label->fontcolor)); SET_SLOT(curLab, Rf_install("labelFontsize"), Rf_ScalarReal(node->u.label->fontsize)); } SET_SLOT(curNL, Rf_install("txtLabel"), curLab); SET_ELEMENT(outLst, i, curNL); node = agnxtnode(g,node); UNPROTECT(3); } UNPROTECT(1); return(outLst); }
static void end_edgestmt(void) { objstack_t *old_SP; objlist_t *tailptr,*headptr,*freeptr; Agraph_t *t_graph,*h_graph; Agnode_t *t_node,*h_node,*t_first,*h_first; Agedge_t *e; char *tport,*hport; for (tailptr = SP->list; tailptr->link; tailptr = tailptr->link) { headptr = tailptr->link; tport = tailptr->data.port; hport = headptr->data.port; if (TAG_OF(tailptr->data.obj) == TAG_NODE) { t_graph = NULL; t_first = (Agnode_t*)(tailptr->data.obj); } else { t_graph = (Agraph_t*)(tailptr->data.obj); t_first = agfstnode(t_graph); } if (TAG_OF(headptr->data.obj) == TAG_NODE) { h_graph = NULL; h_first = (Agnode_t*)(headptr->data.obj); } else { h_graph = (Agraph_t*)(headptr->data.obj); h_first = agfstnode(h_graph); } for (t_node = t_first; t_node; t_node = t_graph ? agnxtnode(t_graph,t_node) : NULL) { for (h_node = h_first; h_node; h_node = h_graph ? agnxtnode(h_graph,h_node) : NULL ) { e = agedge(G,t_node,h_node); if (e) { char *tp = tport; char *hp = hport; if ((e->tail != e->head) && (e->head == t_node)) { /* could happen with an undirected edge */ char *temp; temp = tp; tp = hp; hp = temp; } if (tp && tp[0]) agxset(e,TAILX,tp); if (hp && hp[0]) agxset(e,HEADX,hp); } } } } tailptr = SP->list; while (tailptr) { freeptr = tailptr; tailptr = tailptr->link; if (TAG_OF(freeptr->data.obj) == TAG_NODE) free(freeptr->data.port); free(freeptr); } if (G != SP->subg) abort(); agpopproto(G); In_edge_stmt = SP->in_edge_stmt; old_SP = SP; SP = SP->link; In_decl = FALSE; free(old_SP); Current_class = TAG_GRAPH; }
xbt_dynar_t SD_dotload_generic(const char * filename, seq_par_t seq_or_par, bool schedule){ xbt_assert(filename, "Unable to use a null file descriptor\n"); FILE *in_file = fopen(filename, "r"); xbt_assert(in_file != nullptr, "Failed to open file: %s", filename); unsigned int i; SD_task_t root; SD_task_t end; SD_task_t task; xbt_dict_t computers; xbt_dynar_t computer = nullptr; xbt_dict_cursor_t dict_cursor; bool schedule_success = true; xbt_dict_t jobs = xbt_dict_new_homogeneous(nullptr); xbt_dynar_t result = xbt_dynar_new(sizeof(SD_task_t), dot_task_p_free); Agraph_t * dag_dot = agread(in_file, NIL(Agdisc_t *)); if (schedule) computers = xbt_dict_new_homogeneous(nullptr); /* Create all the nodes */ Agnode_t *node = nullptr; for (node = agfstnode(dag_dot); node; node = agnxtnode(dag_dot, node)) { char *name = agnameof(node); double amount = atof(agget(node, (char*)"size")); task = static_cast<SD_task_t>(xbt_dict_get_or_null(jobs, name)); if (task == nullptr) { if (seq_or_par == sequential){ XBT_DEBUG("See <job id=%s amount =%.0f>", name, amount); task = SD_task_create_comp_seq(name, nullptr , amount); } else { double alpha = atof(agget(node, (char *) "alpha")); XBT_DEBUG("See <job id=%s amount =%.0f alpha = %.3f>", name, amount, alpha); task = SD_task_create_comp_par_amdahl(name, nullptr , amount, alpha); } xbt_dict_set(jobs, name, task, nullptr); if (strcmp(name,"root") && strcmp(name,"end")) xbt_dynar_push(result, &task); if((seq_or_par == sequential) && ((schedule && schedule_success) || XBT_LOG_ISENABLED(sd_dotparse, xbt_log_priority_verbose))){ /* try to take the information to schedule the task only if all is right*/ char *char_performer = agget(node, (char *) "performer"); char *char_order = agget(node, (char *) "order"); /* Tasks will execute on in a given "order" on a given set of "performer" hosts */ int performer = ((!char_performer || !strcmp(char_performer,"")) ? -1:atoi(char_performer)); int order = ((!char_order || !strcmp(char_order, ""))? -1:atoi(char_order)); if((performer != -1 && order != -1) && performer < (int) sg_host_count()){ /* required parameters are given and less performers than hosts are required */ XBT_DEBUG ("Task '%s' is scheduled on workstation '%d' in position '%d'", task->name, performer, order); if(!(computer = (xbt_dynar_t) xbt_dict_get_or_null(computers, char_performer))){ computer = xbt_dynar_new(sizeof(SD_task_t), nullptr); xbt_dict_set(computers, char_performer, computer, nullptr); } if((unsigned int)order < xbt_dynar_length(computer)){ SD_task_t *task_test = (SD_task_t *)xbt_dynar_get_ptr(computer,order); if(*task_test && *task_test != task){ /* the user gave the same order to several tasks */ schedule_success = false; XBT_VERB("Task '%s' wants to start on performer '%s' at the same position '%s' as task '%s'", (*task_test)->name, char_performer, char_order, task->name); continue; } } /* the parameter seems to be ok */ xbt_dynar_set_as(computer, order, SD_task_t, task); } else { /* one of required parameters is not given */ schedule_success = false; XBT_VERB("The schedule is ignored, task '%s' can not be scheduled on %d hosts", task->name, performer); } } } else { XBT_WARN("Task '%s' is defined more than once", name); } } /*Check if 'root' and 'end' nodes have been explicitly declared. If not, create them. */ if (!(root = (SD_task_t)xbt_dict_get_or_null(jobs, "root"))) root = (seq_or_par == sequential?SD_task_create_comp_seq("root", nullptr, 0): SD_task_create_comp_par_amdahl("root", nullptr, 0, 0)); SD_task_set_state(root, SD_SCHEDULABLE); /* by design the root task is always SCHEDULABLE */ xbt_dynar_insert_at(result, 0, &root); /* Put it at the beginning of the dynar */ if (!(end = (SD_task_t)xbt_dict_get_or_null(jobs, "end"))) end = (seq_or_par == sequential?SD_task_create_comp_seq("end", nullptr, 0): SD_task_create_comp_par_amdahl("end", nullptr, 0, 0)); /* Create edges */ xbt_dynar_t edges = xbt_dynar_new(sizeof(Agedge_t*), nullptr); for (node = agfstnode(dag_dot); node; node = agnxtnode(dag_dot, node)) { Agedge_t * edge; xbt_dynar_reset(edges); for (edge = agfstout(dag_dot, node); edge; edge = agnxtout(dag_dot, edge)) xbt_dynar_push_as(edges, Agedge_t *, edge); /* Be sure edges are sorted */ xbt_dynar_sort(edges, edge_compare); xbt_dynar_foreach(edges, i, edge) { char *src_name=agnameof(agtail(edge)), *dst_name=agnameof(aghead(edge)); double size = atof(agget(edge, (char *) "size")); SD_task_t src = static_cast<SD_task_t>(xbt_dict_get_or_null(jobs, src_name)); SD_task_t dst = static_cast<SD_task_t>(xbt_dict_get_or_null(jobs, dst_name)); if (size > 0) { char *name = bprintf("%s->%s", src_name, dst_name); XBT_DEBUG("See <transfer id=%s amount = %.0f>", name, size); task = static_cast<SD_task_t>(xbt_dict_get_or_null(jobs, name)); if (task == nullptr) { if (seq_or_par == sequential) task = SD_task_create_comm_e2e(name, nullptr , size); else task = SD_task_create_comm_par_mxn_1d_block(name, nullptr , size); SD_task_dependency_add(nullptr, nullptr, src, task); SD_task_dependency_add(nullptr, nullptr, task, dst); xbt_dict_set(jobs, name, task, nullptr); xbt_dynar_push(result, &task); } else { XBT_WARN("Task '%s' is defined more than once", name); } xbt_free(name); } else { SD_task_dependency_add(nullptr, nullptr, src, dst); } } }
Agnode_t *firstnode(Agraph_t *g) { if (!g) return NULL; return agfstnode(g); }
/* _write_plain: */ void write_plain(GVJ_t * job, graph_t * g, FILE * f, boolean extend) { int i, j, splinePoints; char *tport, *hport; node_t *n; edge_t *e; bezier bz; pointf pt; char *lbl; char* fillcolor; putstr = g->clos->disc.io->putstr; // setup_graph(job, g); setYInvert(g); pt = GD_bb(g).UR; printdouble(f, "graph ", job->zoom); printdouble(f, " ", PS2INCH(pt.x)); printdouble(f, " ", PS2INCH(pt.y)); agputc('\n', f); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (IS_CLUST_NODE(n)) continue; printstring(f, "node ", agcanonStr(agnameof(n))); printpoint(f, ND_coord(n)); if (ND_label(n)->html) /* if html, get original text */ lbl = agcanonStr (agxget(n, N_label)); else lbl = canon(agraphof(n),ND_label(n)->text); printdouble(f, " ", ND_width(n)); printdouble(f, " ", ND_height(n)); printstring(f, " ", lbl); printstring(f, " ", late_nnstring(n, N_style, "solid")); printstring(f, " ", ND_shape(n)->name); printstring(f, " ", late_nnstring(n, N_color, DEFAULT_COLOR)); fillcolor = late_nnstring(n, N_fillcolor, ""); if (fillcolor[0] == '\0') fillcolor = late_nnstring(n, N_color, DEFAULT_FILL); printstring(f, " ", fillcolor); agputc('\n', f); } for (n = agfstnode(g); n; n = agnxtnode(g, n)) { for (e = agfstout(g, n); e; e = agnxtout(g, e)) { if (extend) { //assuming these two attrs have already been created by cgraph if (!(tport = agget(e,"tailport"))) tport = ""; if (!(hport = agget(e,"headport"))) hport = ""; } else tport = hport = ""; if (ED_spl(e)) { splinePoints = 0; for (i = 0; i < ED_spl(e)->size; i++) { bz = ED_spl(e)->list[i]; splinePoints += bz.size; } printstring(f, NULL, "edge"); writenodeandport(f, agtail(e), tport); writenodeandport(f, aghead(e), hport); printint(f, " ", splinePoints); for (i = 0; i < ED_spl(e)->size; i++) { bz = ED_spl(e)->list[i]; for (j = 0; j < bz.size; j++) printpoint(f, bz.list[j]); } } if (ED_label(e)) { printstring(f, " ", canon(agraphof(agtail(e)),ED_label(e)->text)); printpoint(f, ED_label(e)->pos); } printstring(f, " ", late_nnstring(e, E_style, "solid")); printstring(f, " ", late_nnstring(e, E_color, DEFAULT_COLOR)); agputc('\n', f); } } agputs("stop\n", f); }
/* Execute union commands for "same rank" subgraphs and clusters. */ static void collapse_sets(graph_t *rg, graph_t *g) { int c; graph_t *subg; #ifdef OBSOLETE node_t *n; #endif #ifndef WITH_CGRAPH graph_t *mg; node_t *mn; edge_t *me; mg = g->meta_node->graph; for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) { mn = aghead(me); subg = agusergraph(mn); #else /* WITH_CGRAPH */ for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) { #endif /* WITH_CGRAPH */ c = rank_set_class(subg); if (c) { if ((c == CLUSTER) && CL_type == LOCAL) collapse_cluster(rg, subg); else collapse_rankset(rg, subg, c); } else collapse_sets(rg, subg); #ifdef OBSOLETE Collapsing leaves is currently obsolete /* mark nodes with ordered edges so their leaves are not collapsed */ if (agget(subg, "ordering")) for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) ND_order(n) = 1; #endif } } static void find_clusters(graph_t * g) { graph_t *subg; #ifndef WITH_CGRAPH graph_t *mg; node_t *mn; edge_t *me; mg = g->meta_node->graph; for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) { mn = me->head; subg = agusergraph(mn); #else /* WITH_CGRAPH */ for (subg = agfstsubg(agroot(g)); subg; subg = agnxtsubg(subg)) { #endif /* WITH_CGRAPH */ if (GD_set_type(subg) == CLUSTER) collapse_cluster(g, subg); } } static void set_minmax(graph_t * g) { int c; GD_minrank(g) += ND_rank(GD_leader(g)); GD_maxrank(g) += ND_rank(GD_leader(g)); for (c = 1; c <= GD_n_cluster(g); c++) set_minmax(GD_clust(g)[c]); }