/* copy: * Create new object of type AGTYPE(obj) with all of its * attributes. * If obj is an edge, only create end nodes if necessary. * If obj is a graph, if g is null, create a top-level * graph. Otherwise, create a subgraph of g. * Assume obj != NULL. */ Agobj_t *copy(Agraph_t * g, Agobj_t * obj) { Agobj_t *nobj = 0; Agedge_t *e; Agnode_t *h; Agnode_t *t; int kind = AGTYPE(obj); char *name = agnameof(obj); if ((kind != AGRAPH) && !g) { error(ERROR_FATAL, "NULL graph with non-graph object in copy()"); return 0; } switch (kind) { case AGNODE: nobj = (Agobj_t *) openNode(g, name); break; case AGRAPH: if (g) nobj = (Agobj_t *) openSubg(g, name); else nobj = (Agobj_t *) openG(name, ((Agraph_t *) obj)->desc); break; case AGEDGE: e = (Agedge_t *) obj; t = openNode(g, agnameof(agtail(e))); h = openNode(g, agnameof(aghead(e))); nobj = (Agobj_t *) openEdge(t, h, name); break; } if (nobj) copyAttr(obj, nobj); return nobj; }
static void add_node(Agraph_t * g, Agedge_t * e, int labels) { /*find out how the ranks increase ,it may not always be from tail to head! */ int rankDiff; int i; Agnode_t *tmpN; Agedge_t *tmpE; Agnode_t *tail; Agnode_t *head; Agraph_t *cluster = NULL; Agraph_t *tempC1 = NULL; Agraph_t *tempC2 = NULL; int type = INTNODE; head = aghead(e); tail = agtail(e); #if 0 if ((strcmp(agnameof(head), "T1") == 0) && (strcmp(agnameof(tail), "23") == 0)) fprintf(stderr, "found \n"); if ((strcmp(agnameof(head), "23") == 0) && (strcmp(agnameof(tail), "T1") == 0)) fprintf(stderr, "found \n"); #endif /*check whether edge is a cluster */ tempC1 = MND_highCluster(head); tempC2 = MND_highCluster(tail); if (tempC1 == tempC2) cluster = tempC1; rankDiff = MND_rank(head) - MND_rank(tail); if ((rankDiff == 1) || (rankDiff == -1)) return; if (rankDiff == 0) return; if (rankDiff > 0) /*expected */ for (i = MND_rank(tail) + 1; i < MND_rank(head); i++) { if (labels) { if (type == LBLNODE) type = INTNODE; else type = LBLNODE; } else type = INTNODE; tmpN = mkMCNode (g, type, (char *) 0); MND_rank(tmpN) = i; MND_type(tmpN) = type; MND_highCluster(tmpN) = cluster; MND_orderr(tmpN) = MND_orderr(tail); /*create internal edge */ tmpE = mkMCEdge (g, tail, tmpN, 0, VIRTUAL, MED_orig(e)); tail = tmpN; } else for (i = MND_rank(tail) - 1; i > MND_rank(head); i--) { if (labels) { if (type == LBLNODE) type = INTNODE; else type = LBLNODE; } else type = INTNODE; tmpN = mkMCNode (g, type, (char *) 0); MND_rank(tmpN) = i; MND_type(tmpN) = type; MND_highCluster(tmpN) = cluster; /*create internal edge */ tmpE = mkMCEdge (g, tail, tmpN, 0, VIRTUAL, MED_orig(e)); tail = tmpN; } tmpE = mkMCEdge (g, tail, head, 0, VIRTUAL, MED_orig(e)); /*mark the long edge for deletion */ MED_deleteFlag(e) = 1; }
static pointf *_routesplines(path * pp, int *npoints, int polyline) { Ppoly_t poly; Ppolyline_t pl, spl; int splinepi; Ppoint_t eps[2]; Pvector_t evs[2]; int edgei, prev, next; pointf sp[4]; int pi, bi, si; double t; boxf *boxes; int boxn; edge_t* realedge; int flip; int delta = 10; nedges++; nboxes += pp->nbox; for (realedge = (edge_t *) pp->data; #ifdef NOTNOW origedge = realedge; #endif realedge && ED_edge_type(realedge) != NORMAL; realedge = ED_to_orig(realedge)); if (!realedge) { agerr(AGERR, "in routesplines, cannot find NORMAL edge\n"); abort(); } boxes = pp->boxes; boxn = pp->nbox; checkpath(boxn, boxes, pp); #ifdef DEBUG if (debugleveln(realedge, 1)) printboxes(boxn, boxes); if (debugleveln(realedge, 3)) { psprintinit(1); psprintboxes(boxn, boxes); } #endif if (boxn * 8 > polypointn) { polypoints = ALLOC(boxn * 8, polypoints, Ppoint_t); polypointn = boxn * 8; } if ((boxn > 1) && (boxes[0].LL.y > boxes[1].LL.y)) { flip = 1; for (bi = 0; bi < boxn; bi++) { double v = boxes[bi].UR.y; boxes[bi].UR.y = -1*boxes[bi].LL.y; boxes[bi].LL.y = -v; } } else flip = 0; if (agtail(realedge) != aghead(realedge)) { /* I assume that the path goes either down only or up - right - down */ for (bi = 0, pi = 0; bi < boxn; bi++) { next = prev = 0; if (bi > 0) prev = (boxes[bi].LL.y > boxes[bi - 1].LL.y) ? -1 : 1; if (bi < boxn - 1) next = (boxes[bi + 1].LL.y > boxes[bi].LL.y) ? 1 : -1; if (prev != next) { if (next == -1 || prev == 1) { polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } else { polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; } } else if (prev == 0) { /* single box */ polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } else { if (!(prev == -1 && next == -1)) abort(); } } for (bi = boxn - 1; bi >= 0; bi--) { next = prev = 0; if (bi < boxn - 1) prev = (boxes[bi].LL.y > boxes[bi + 1].LL.y) ? -1 : 1; if (bi > 0) next = (boxes[bi - 1].LL.y > boxes[bi].LL.y) ? 1 : -1; if (prev != next) { if (next == -1 || prev == 1 ) { polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } else { polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; } } else if (prev == 0) { /* single box */ polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; } else { if (!(prev == -1 && next == -1)) { /* it went badly, e.g. degenerate box in boxlist */ *npoints = 0; abort(); /* for correctness sake, it's best to just stop */ return ps; /* could also be reported as a lost edge (no spline) */ } polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } } } else { abort(); } if (flip) { int i; for (bi = 0; bi < boxn; bi++) { int v = boxes[bi].UR.y; boxes[bi].UR.y = -1*boxes[bi].LL.y; boxes[bi].LL.y = -v; } for (i = 0; i < pi; i++) polypoints[i].y *= -1; } for (bi = 0; bi < boxn; bi++) boxes[bi].LL.x = INT_MAX, boxes[bi].UR.x = INT_MIN; poly.ps = polypoints, poly.pn = pi; eps[0].x = pp->start.p.x, eps[0].y = pp->start.p.y; eps[1].x = pp->end.p.x, eps[1].y = pp->end.p.y; if (Pshortestpath(&poly, eps, &pl) == -1) abort(); #ifdef DEBUG if (debugleveln(realedge, 3)) { psprintpoly(poly); psprintline(pl); } #endif if (polyline) { make_polyline (pl, &spl); } else { if (poly.pn > edgen) { edges = ALLOC(poly.pn, edges, Pedge_t); edgen = poly.pn; } for (edgei = 0; edgei < poly.pn; edgei++) { edges[edgei].a = polypoints[edgei]; edges[edgei].b = polypoints[(edgei + 1) % poly.pn]; } if (pp->start.constrained) { evs[0].x = cos(pp->start.theta); evs[0].y = sin(pp->start.theta); } else evs[0].x = evs[0].y = 0; if (pp->end.constrained) { evs[1].x = -cos(pp->end.theta); evs[1].y = -sin(pp->end.theta); } else evs[1].x = evs[1].y = 0; if (Proutespline(edges, poly.pn, pl, evs, &spl) == -1) abort(); #ifdef DEBUG if (debugleveln(realedge, 3)) { psprintspline(spl); psprintinit(0); } #endif } mkspacep(spl.pn); for (bi = 0; bi < boxn; bi++) { boxes[bi].LL.x = INT_MAX; boxes[bi].UR.x = INT_MIN; } for (splinepi = 0; splinepi < spl.pn; splinepi++) { ps[splinepi] = spl.ps[splinepi]; } REDO: for (splinepi = 0; splinepi + 3 < spl.pn; splinepi += 3) { int num_div = delta * boxn; for (si = 0; si <= num_div; si++) { t = si / (double)num_div; sp[0] = ps[splinepi]; sp[1] = ps[splinepi + 1]; sp[2] = ps[splinepi + 2]; sp[3] = ps[splinepi + 3]; sp[0].x = sp[0].x + t * (sp[1].x - sp[0].x); sp[0].y = sp[0].y + t * (sp[1].y - sp[0].y); sp[1].x = sp[1].x + t * (sp[2].x - sp[1].x); sp[1].y = sp[1].y + t * (sp[2].y - sp[1].y); sp[2].x = sp[2].x + t * (sp[3].x - sp[2].x); sp[2].y = sp[2].y + t * (sp[3].y - sp[2].y); sp[0].x = sp[0].x + t * (sp[1].x - sp[0].x); sp[0].y = sp[0].y + t * (sp[1].y - sp[0].y); sp[1].x = sp[1].x + t * (sp[2].x - sp[1].x); sp[1].y = sp[1].y + t * (sp[2].y - sp[1].y); sp[0].x = sp[0].x + t * (sp[1].x - sp[0].x); sp[0].y = sp[0].y + t * (sp[1].y - sp[0].y); for (bi = 0; bi < boxn; bi++) { /* this tested ok on 64bit machines, but on 32bit we need this FUDGE * or graphs/directed/records.gv fails */ #define FUDGE .0001 if (sp[0].y <= boxes[bi].UR.y+FUDGE && sp[0].y >= boxes[bi].LL.y-FUDGE) { if (boxes[bi].LL.x > sp[0].x) boxes[bi].LL.x = sp[0].x; if (boxes[bi].UR.x < sp[0].x) boxes[bi].UR.x = sp[0].x; } } } } /* The following check is necessary because if a box is not very * high, it is possible that the sampling above might miss it. * Therefore, we make the sample finer until all boxes have * valid values. cf. bug 456. Would making sp[] pointfs help? */ for (bi = 0; bi < boxn; bi++) { /* these fp equality tests are used only to detect if the * values have been changed since initialization - ok */ if ((boxes[bi].LL.x == INT_MAX) || (boxes[bi].UR.x == INT_MIN)) { delta *= 2; goto REDO; } } *npoints = spl.pn; #ifdef DEBUG if (GD_showboxes(realedge->head->graph) == 2 || GD_showboxes(realedge->tail->graph) == 2 || ED_showboxes(realedge) == 2 || ND_showboxes(realedge->head) == 2 || ND_showboxes(realedge->tail) == 2) printboxes(boxn, boxes); #endif return ps; }
/* routesplines: * Route a path using the path info in pp. This includes start and end points * plus a collection of contiguous boxes contain the terminal points. The boxes * are converted into a containing polygon. A shortest path is constructed within * the polygon from between the terminal points. If polyline is true, this path * is converted to a spline representation. Otherwise, we call the path planner to * convert the polyline into a smooth spline staying within the polygon. In both * cases, the function returns an array of the computed control points. The number * of these points is given in npoints. * * Note that the returned points are stored in a single array, so the points must be * used before another call to this function. * * During cleanup, the function determines the x-extent of the spline in the box, so * the box can be shrunk to the minimum width. The extra space can then be used by other * edges. * * If a catastrophic error, return NULL. */ static pointf *_routesplines(path * pp, int *npoints, int polyline) { Ppoly_t poly; Ppolyline_t pl, spl; int splinepi; Ppoint_t eps[2]; Pvector_t evs[2]; int edgei, prev, next; int pi, bi; boxf *boxes; int boxn; edge_t* realedge; int flip; int loopcnt, delta = INIT_DELTA; boolean unbounded; nedges++; nboxes += pp->nbox; for (realedge = (edge_t *) pp->data; #ifdef NOTNOW origedge = realedge; #endif realedge && ED_edge_type(realedge) != NORMAL; realedge = ED_to_orig(realedge)); if (!realedge) { agerr(AGERR, "in routesplines, cannot find NORMAL edge\n"); return NULL; } boxes = pp->boxes; boxn = pp->nbox; if (checkpath(boxn, boxes, pp)) return NULL; #ifdef DEBUG if (debugleveln(realedge, 1)) printboxes(boxn, boxes); if (debugleveln(realedge, 3)) { psprintinit(1); psprintboxes(boxn, boxes); } #endif if (boxn * 8 > polypointn) { polypoints = ALLOC(boxn * 8, polypoints, Ppoint_t); polypointn = boxn * 8; } if ((boxn > 1) && (boxes[0].LL.y > boxes[1].LL.y)) { flip = 1; for (bi = 0; bi < boxn; bi++) { double v = boxes[bi].UR.y; boxes[bi].UR.y = -1*boxes[bi].LL.y; boxes[bi].LL.y = -v; } } else flip = 0; if (agtail(realedge) != aghead(realedge)) { /* I assume that the path goes either down only or up - right - down */ for (bi = 0, pi = 0; bi < boxn; bi++) { next = prev = 0; if (bi > 0) prev = (boxes[bi].LL.y > boxes[bi - 1].LL.y) ? -1 : 1; if (bi < boxn - 1) next = (boxes[bi + 1].LL.y > boxes[bi].LL.y) ? 1 : -1; if (prev != next) { if (next == -1 || prev == 1) { polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } else { polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; } } else if (prev == 0) { /* single box */ polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } else { if (!(prev == -1 && next == -1)) { agerr(AGERR, "in routesplines, illegal values of prev %d and next %d, line %d\n", prev, next, __LINE__); return NULL; } } } for (bi = boxn - 1; bi >= 0; bi--) { next = prev = 0; if (bi < boxn - 1) prev = (boxes[bi].LL.y > boxes[bi + 1].LL.y) ? -1 : 1; if (bi > 0) next = (boxes[bi - 1].LL.y > boxes[bi].LL.y) ? 1 : -1; if (prev != next) { if (next == -1 || prev == 1 ) { polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } else { polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; } } else if (prev == 0) { /* single box */ polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; } else { if (!(prev == -1 && next == -1)) { /* it went badly, e.g. degenerate box in boxlist */ agerr(AGERR, "in routesplines, illegal values of prev %d and next %d, line %d\n", prev, next, __LINE__); return NULL; /* for correctness sake, it's best to just stop */ } polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].LL.y; polypoints[pi].x = boxes[bi].UR.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].UR.y; polypoints[pi].x = boxes[bi].LL.x; polypoints[pi++].y = boxes[bi].LL.y; } } } else { agerr(AGERR, "in routesplines, edge is a loop at %s\n", agnameof(aghead(realedge))); return NULL; } if (flip) { int i; for (bi = 0; bi < boxn; bi++) { int v = boxes[bi].UR.y; boxes[bi].UR.y = -1*boxes[bi].LL.y; boxes[bi].LL.y = -v; } for (i = 0; i < pi; i++) polypoints[i].y *= -1; } for (bi = 0; bi < boxn; bi++) boxes[bi].LL.x = INT_MAX, boxes[bi].UR.x = INT_MIN; poly.ps = polypoints, poly.pn = pi; eps[0].x = pp->start.p.x, eps[0].y = pp->start.p.y; eps[1].x = pp->end.p.x, eps[1].y = pp->end.p.y; if (Pshortestpath(&poly, eps, &pl) < 0) { agerr(AGERR, "in routesplines, Pshortestpath failed\n"); return NULL; } #ifdef DEBUG if (debugleveln(realedge, 3)) { psprintpoly(poly); psprintline(pl); } #endif if (polyline) { make_polyline (pl, &spl); } else { if (poly.pn > edgen) { edges = ALLOC(poly.pn, edges, Pedge_t); edgen = poly.pn; } for (edgei = 0; edgei < poly.pn; edgei++) { edges[edgei].a = polypoints[edgei]; edges[edgei].b = polypoints[(edgei + 1) % poly.pn]; } if (pp->start.constrained) { evs[0].x = cos(pp->start.theta); evs[0].y = sin(pp->start.theta); } else evs[0].x = evs[0].y = 0; if (pp->end.constrained) { evs[1].x = -cos(pp->end.theta); evs[1].y = -sin(pp->end.theta); } else evs[1].x = evs[1].y = 0; if (Proutespline(edges, poly.pn, pl, evs, &spl) < 0) { agerr(AGERR, "in routesplines, Proutespline failed\n"); return NULL; } #ifdef DEBUG if (debugleveln(realedge, 3)) { psprintspline(spl); psprintinit(0); } #endif } if (mkspacep(spl.pn)) return NULL; /* Bailout if no memory left */ for (bi = 0; bi < boxn; bi++) { boxes[bi].LL.x = INT_MAX; boxes[bi].UR.x = INT_MIN; } unbounded = TRUE; for (splinepi = 0; splinepi < spl.pn; splinepi++) { ps[splinepi] = spl.ps[splinepi]; } for (loopcnt = 0; unbounded && (loopcnt < LOOP_TRIES); loopcnt++) { limitBoxes (boxes, boxn, ps, spl.pn, delta); /* The following check is necessary because if a box is not very * high, it is possible that the sampling above might miss it. * Therefore, we make the sample finer until all boxes have * valid values. cf. bug 456. Would making sp[] pointfs help? */ for (bi = 0; bi < boxn; bi++) { /* these fp equality tests are used only to detect if the * values have been changed since initialization - ok */ if ((boxes[bi].LL.x == INT_MAX) || (boxes[bi].UR.x == INT_MIN)) { delta *= 2; /* try again with a finer interval */ if (delta > INT_MAX/boxn) /* in limitBoxes, boxn*delta must fit in an int, so give up */ loopcnt = LOOP_TRIES; break; } } if (bi == boxn) unbounded = FALSE; } if (unbounded) { /* Either an extremely short, even degenerate, box, or some failure with the path * planner causing the spline to miss some boxes. In any case, use the shortest path * to bound the boxes. This will probably mean a bad edge, but we avoid an infinite * loop and we can see the bad edge, and even use the showboxes scaffolding. */ Ppolyline_t polyspl; agerr(AGWARN, "Unable to reclaim box space in spline routing for edge \"%s\" -> \"%s\". Something is probably seriously wrong.\n", agnameof(agtail(realedge)), agnameof(aghead(realedge))); make_polyline (pl, &polyspl); limitBoxes (boxes, boxn, polyspl.ps, polyspl.pn, INIT_DELTA); free (polyspl.ps); } *npoints = spl.pn; #ifdef DEBUG if (GD_showboxes(agraphof(aghead(realedge))) == 2 || GD_showboxes(agraphof(agtail(realedge))) == 2 || ED_showboxes(realedge) == 2 || ND_showboxes(aghead(realedge)) == 2 || ND_showboxes(agtail(realedge)) == 2) printboxes(boxn, boxes); #endif return ps; }
/* * attach and install edges between clusters. * essentially, class2() for interclust edges. */ void interclexp(graph_t * subg) { graph_t *g; node_t *n; edge_t *e, *prev, *next; g = agroot(subg); for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) { /* N.B. n may be in a sub-cluster of subg */ prev = NULL; for (e = agfstedge(agroot(subg), n); e; e = next) { next = agnxtedge(agroot(subg), e, n); if (agcontains(subg, e)) continue; #ifdef WITH_CGRAPH /* canonicalize edge */ e = AGMKOUT(e); #endif /* short/flat multi edges */ if (mergeable(prev, e)) { if (ND_rank(agtail(e)) == ND_rank(aghead(e))) ED_to_virt(e) = prev; else ED_to_virt(e) = NULL; if (ED_to_virt(prev) == NULL) continue; /* internal edge */ merge_chain(subg, e, ED_to_virt(prev), FALSE); safe_other_edge(e); continue; } /* flat edges */ if (ND_rank(agtail(e)) == ND_rank(aghead(e))) { edge_t* fe; if ((fe = find_flat_edge(agtail(e), aghead(e))) == NULL) { flat_edge(g, e); prev = e; } else if (e != fe) { safe_other_edge(e); if (!ED_to_virt(e)) merge_oneway(e, fe); } continue; } /* This assertion is still valid if the new ranking is not used */ #ifndef WITH_CGRAPH assert(ED_to_virt(e) != NULL); #endif /* forward edges */ if (ND_rank(aghead(e)) > ND_rank(agtail(e))) { make_interclust_chain(g, agtail(e), aghead(e), e); prev = e; continue; } /* backward edges */ else { /* I think that make_interclust_chain should create call other_edge(e) anyway if (agcontains(subg,agtail(e)) && agfindedge(subg->root,aghead(e),agtail(e))) other_edge(e); */ make_interclust_chain(g, aghead(e), agtail(e), e); prev = e; } } } }
/* make_label: * Assume str is freshly allocated for this instance, so it * can be freed in free_label. */ textlabel_t *make_label(void *obj, char *str, int kind, double fontsize, char *fontname, char *fontcolor) { textlabel_t *rv = NEW(textlabel_t); graph_t *g = NULL, *sg = NULL; node_t *n = NULL; edge_t *e = NULL; char *s; switch (agobjkind(obj)) { case AGRAPH: sg = (graph_t*)obj; g = sg->root; break; case AGNODE: n = (node_t*)obj; g = agroot(agraphof(n)); break; case AGEDGE: e = (edge_t*)obj; g = agroot(agraphof(aghead(e))); break; } rv->fontname = fontname; rv->fontcolor = fontcolor; rv->fontsize = fontsize; rv->charset = GD_charset(g); if (kind & LT_RECD) { rv->text = strdup(str); if (kind & LT_HTML) { rv->html = TRUE; } } else if (kind == LT_HTML) { rv->text = strdup(str); rv->html = TRUE; if (make_html_label(obj, rv)) { switch (agobjkind(obj)) { case AGRAPH: agerr(AGPREV, "in label of graph %s\n",agnameof(sg)); break; case AGNODE: agerr(AGPREV, "in label of node %s\n", agnameof(n)); break; case AGEDGE: agerr(AGPREV, "in label of edge %s %s %s\n", agnameof(agtail(e)), agisdirected(g)?"->":"--", agnameof(aghead(e))); break; } } } else { assert(kind == LT_NONE); /* This call just processes the graph object based escape sequences. The formatting escape * sequences (\n, \l, \r) are processed in make_simple_label. That call also replaces \\ with \. */ rv->text = strdup_and_subst_obj0(str, obj, 0); switch (rv->charset) { case CHAR_LATIN1: s = latin1ToUTF8(rv->text); break; default: /* UTF8 */ s = htmlEntityUTF8(rv->text, g); break; } free(rv->text); rv->text = s; make_simple_label(GD_gvc(g), rv); } return rv; }
/* return true if edge has label */ int common_init_edge(edge_t * e) { char *str; int r = 0; struct fontinfo fi; struct fontinfo lfi; graph_t *sg = agraphof(agtail(e)); fi.fontname = NULL; lfi.fontname = NULL; if (E_label && (str = agxget(e, E_label)) && (str[0])) { r = 1; initFontEdgeAttr(e, &fi); ED_label(e) = make_label((void*)e, str, (aghtmlstr(str) ? LT_HTML : LT_NONE), fi.fontsize, fi.fontname, fi.fontcolor); GD_has_labels(sg) |= EDGE_LABEL; ED_label_ontop(e) = mapbool(late_string(e, E_label_float, "false")); } if (E_xlabel && (str = agxget(e, E_xlabel)) && (str[0])) { if (!fi.fontname) initFontEdgeAttr(e, &fi); ED_xlabel(e) = make_label((void*)e, str, (aghtmlstr(str) ? LT_HTML : LT_NONE), fi.fontsize, fi.fontname, fi.fontcolor); GD_has_labels(sg) |= EDGE_XLABEL; } /* vladimir */ if (E_headlabel && (str = agxget(e, E_headlabel)) && (str[0])) { initFontLabelEdgeAttr(e, &fi, &lfi); ED_head_label(e) = make_label((void*)e, str, (aghtmlstr(str) ? LT_HTML : LT_NONE), lfi.fontsize, lfi.fontname, lfi.fontcolor); GD_has_labels(sg) |= HEAD_LABEL; } if (E_taillabel && (str = agxget(e, E_taillabel)) && (str[0])) { if (!lfi.fontname) initFontLabelEdgeAttr(e, &fi, &lfi); ED_tail_label(e) = make_label((void*)e, str, (aghtmlstr(str) ? LT_HTML : LT_NONE), lfi.fontsize, lfi.fontname, lfi.fontcolor); GD_has_labels(sg) |= TAIL_LABEL; } /* end vladimir */ /* We still accept ports beginning with colons but this is deprecated * That is, we allow tailport = ":abc" as well as the preferred * tailport = "abc". */ str = agget(e, TAIL_ID); /* libgraph always defines tailport/headport; libcgraph doesn't */ if (!str) str = ""; if (str && str[0]) ND_has_port(agtail(e)) = TRUE; ED_tail_port(e) = chkPort (ND_shape(agtail(e))->fns->portfn, agtail(e), str); if (noClip(e, E_tailclip)) ED_tail_port(e).clip = FALSE; str = agget(e, HEAD_ID); /* libgraph always defines tailport/headport; libcgraph doesn't */ if (!str) str = ""; if (str && str[0]) ND_has_port(aghead(e)) = TRUE; ED_head_port(e) = chkPort(ND_shape(aghead(e))->fns->portfn, aghead(e), str); if (noClip(e, E_headclip)) ED_head_port(e).clip = FALSE; return r; }
/* 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 if (doLbls) { agerr(AGWARN, "Orthogonal edges do not currently handle edge labels. Try using xlabels.\n"); doLbls = 0; } 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); } if (shortPath (sg, dn, sn)) goto orthofinish; } route_list[i] = convertSPtoRoute(sg, sn, dn); reset (sg); } PQfree (); mp->hchans = extractHChans (mp); mp->vchans = extractVChans (mp); assignSegs (n_edges, route_list, mp); if (setjmp(jbuf)) goto orthofinish; 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); orthofinish: if (Concentrate) freePS (ps); for (i=0; i < n_edges; i++) free (route_list[i].segs); free (route_list); freeMaze (mp); }
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); } } }
static void checkCompound(edge_t * e, graph_t * clg, agxbuf * xb, Dt_t * map, Dt_t* cmap) { graph_t *tg; graph_t *hg; node_t *cn; node_t *cn1; node_t *t = agtail(e); node_t *h = aghead(e); edge_t *ce; item *ip; if (IS_CLUST_NODE(h)) return; tg = MAPC(t); hg = MAPC(h); if (!tg && !hg) return; if (tg == hg) { agerr(AGWARN, "cluster cycle %s -- %s not supported\n", agnameof(t), agnameof(t)); return; } ip = mapEdge(map, e); if (ip) { cloneEdge(e, ip->t, ip->h); return; } if (hg) { if (tg) { if (agcontains(hg, tg)) { agerr(AGWARN, "tail cluster %s inside head cluster %s\n", agnameof(tg), agnameof(hg)); return; } if (agcontains(tg, hg)) { agerr(AGWARN, "head cluster %s inside tail cluster %s\n", agnameof(hg),agnameof(tg)); return; } cn = clustNode(t, tg, xb, clg); cn1 = clustNode(h, hg, xb, clg); ce = cloneEdge(e, cn, cn1); insertEdge(map, t, h, ce); } else { if (agcontains(hg, t)) { agerr(AGWARN, "tail node %s inside head cluster %s\n", agnameof(t), agnameof(hg)); return; } cn = clustNode(h, hg, xb, clg); ce = cloneEdge(e, t, cn); insertEdge(map, t, h, ce); } } else { if (agcontains(tg, h)) { agerr(AGWARN, "head node %s inside tail cluster %s\n", agnameof(h), agnameof(tg)); return; } cn = clustNode(t, tg, xb, clg); ce = cloneEdge(e, cn, h); insertEdge(map, t, h, ce); } }
/* 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; }
Agnode_t *nextnode(Agedge_t *e, Agnode_t *n) { if (!e || n != agtail(e)) return NULL; return aghead(e); }
Agnode_t *firstnode(Agedge_t *e) { if (!e) return NULL; return agtail(e); }
xbt_dynar_t SD_dotload_generic(const char* filename, bool sequential, 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); SD_task_t root; SD_task_t end; SD_task_t task; std::vector<SD_task_t>* computer; std::unordered_map<std::string, std::vector<SD_task_t>*> computers; bool schedule_success = true; std::unordered_map<std::string, SD_task_t> jobs; 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 *)); /* 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")); if (jobs.find(name) == jobs.end()) { if (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); } jobs.insert({std::string(name), task}); if (strcmp(name,"root") && strcmp(name,"end")) xbt_dynar_push(result, &task); if ((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 = ((not char_performer || not strcmp(char_performer, "")) ? -1 : atoi(char_performer)); int order = ((not char_order || not strcmp(char_order, "")) ? -1 : atoi(char_order)); if ((performer != -1 && order != -1) && performer < static_cast<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); auto comp = computers.find(char_performer); if (comp != computers.end()) { computer = comp->second; } else { computer = new std::vector<SD_task_t>; computers.insert({char_performer, computer}); } if (static_cast<unsigned int>(order) < computer->size()) { SD_task_t task_test = computer->at(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; } } else computer->resize(order); computer->insert(computer->begin() + order, 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 (jobs.find("root") == jobs.end()) root = (sequential ? SD_task_create_comp_seq("root", nullptr, 0) : SD_task_create_comp_par_amdahl("root", nullptr, 0, 0)); else root = jobs.at("root"); 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 (jobs.find("end") == jobs.end()) end = (sequential ? SD_task_create_comp_seq("end", nullptr, 0) : SD_task_create_comp_par_amdahl("end", nullptr, 0, 0)); else end = jobs.at("end"); /* Create edges */ std::vector<Agedge_t*> edges; for (node = agfstnode(dag_dot); node; node = agnxtnode(dag_dot, node)) { edges.clear(); for (Agedge_t* edge = agfstout(dag_dot, node); edge; edge = agnxtout(dag_dot, edge)) edges.push_back(edge); /* Be sure edges are sorted */ std::sort(edges.begin(), edges.end(), [](const Agedge_t* a, const Agedge_t* b) { return AGSEQ(a) < AGSEQ(b); }); for (Agedge_t* edge : edges) { char *src_name=agnameof(agtail(edge)); char *dst_name=agnameof(aghead(edge)); double size = atof(agget(edge, (char *) "size")); SD_task_t src = jobs.at(src_name); SD_task_t dst = jobs.at(dst_name); if (size > 0) { std::string name = std::string(src_name) + "->" + dst_name; XBT_DEBUG("See <transfer id=%s amount = %.0f>", name.c_str(), size); if (jobs.find(name) == jobs.end()) { if (sequential) task = SD_task_create_comm_e2e(name.c_str(), nullptr, size); else task = SD_task_create_comm_par_mxn_1d_block(name.c_str(), nullptr, size); SD_task_dependency_add(src, task); SD_task_dependency_add(task, dst); jobs.insert({name, task}); xbt_dynar_push(result, &task); } else { XBT_WARN("Task '%s' is defined more than once", name.c_str()); } } else { SD_task_dependency_add(src, dst); } } } XBT_DEBUG("All tasks have been created, put %s at the end of the dynar", end->name); xbt_dynar_push(result, &end); /* Connect entry tasks to 'root', and exit tasks to 'end'*/ unsigned i; xbt_dynar_foreach (result, i, task){ if (task->predecessors->empty() && task->inputs->empty() && task != root) { XBT_DEBUG("Task '%s' has no source. Add dependency from 'root'", task->name); SD_task_dependency_add(root, task); } if (task->successors->empty() && task->outputs->empty() && task != end) { XBT_DEBUG("Task '%s' has no destination. Add dependency to 'end'", task->name); SD_task_dependency_add(task, end); } } agclose(dag_dot); fclose(in_file); if(schedule){ if (schedule_success) { std::vector<simgrid::s4u::Host*> hosts = simgrid::s4u::Engine::get_instance()->get_all_hosts(); for (auto const& elm : computers) { SD_task_t previous_task = nullptr; for (auto const& cur_task : *elm.second) { /* add dependency between the previous and the task to avoid parallel execution */ if (cur_task) { if (previous_task && not SD_task_dependency_exists(previous_task, cur_task)) SD_task_dependency_add(previous_task, cur_task); SD_task_schedulel(cur_task, 1, hosts[std::stod(elm.first)]); previous_task = cur_task; } } delete elm.second; } } else { XBT_WARN("The scheduling is ignored"); for (auto const& elm : computers) delete elm.second; xbt_dynar_free(&result); result = nullptr; } } if (result && not acyclic_graph_detail(result)) { std::string base = simgrid::xbt::Path(filename).get_base_name(); XBT_ERROR("The DOT described in %s is not a DAG. It contains a cycle.", base.c_str()); xbt_dynar_free(&result); result = nullptr; } return result; }
static void relocate_spline(sdot_op * sop, int param) { Agedge_t *e; Agnode_t *tn; //tail node Agnode_t *hn; //head node int i = 0; xdot_op *op = &sop->op; if (AGTYPE(sop->obj) == AGEDGE) { e = sop->obj; tn = agtail(e); hn = aghead(e); if ((OD_Selected(hn) == 1) && (OD_Selected(tn) == 0)) { set_options(sop, 1); for (i = 1; i < op->u.bezier.cnt - 1; i = i + 1) { if ((dx != 0) || (dy != 0)) { op->u.bezier.pts[i].x = op->u.bezier.pts[i].x - (int) (dx * (float) i / (float) (op->u.bezier.cnt)); op->u.bezier.pts[i].y = op->u.bezier.pts[i].y - (int) (dy * (float) i / (float) (op->u.bezier.cnt)); } } if ((dx != 0) || (dy != 0)) { op->u.bezier.pts[op->u.bezier.cnt - 1].x = op->u.bezier.pts[op->u.bezier.cnt - 1].x - (int) dx; op->u.bezier.pts[op->u.bezier.cnt - 1].y = op->u.bezier.pts[op->u.bezier.cnt - 1].y - (int) dy; } } else if ((OD_Selected(hn) == 0) && (OD_Selected(tn) == 1)) { set_options(sop, 1); for (i = op->u.bezier.cnt - 1; i > 0; i = i - 1) { if ((dx != 0) || (dy != 0)) { op->u.bezier.pts[i].x = op->u.bezier.pts[i].x - (int) (dx * (float) (op->u.bezier.cnt - i) / (float) (op->u.bezier.cnt)); op->u.bezier.pts[i].y = op->u.bezier.pts[i].y - (int) (dy * (float) (op->u.bezier.cnt - i) / (float) (op->u.bezier.cnt)); } } if ((dx != 0) || (dy != 0)) { op->u.bezier.pts[0].x = op->u.bezier.pts[0].x - (int) dx; op->u.bezier.pts[0].y = op->u.bezier.pts[0].y - (int) dy; } } else if ((OD_Selected(hn) == 1) && (OD_Selected(tn) == 1)) { set_options(sop, 1); for (i = 0; i < op->u.bezier.cnt; i = i + 1) { if ((dx != 0) || (dy != 0)) { op->u.bezier.pts[i].x = op->u.bezier.pts[i].x - (int) dx; op->u.bezier.pts[i].y = op->u.bezier.pts[i].y - (int) dy; } } } } }
static void attachOrthoEdges (Agraph_t* g, maze* mp, int n_edges, route* route_list, splineInfo *sinfo, epair_t es[], int doLbls) { int irte = 0; int i, ipt, npts; pointf* ispline = 0; int splsz = 0; pointf p, p1, q1; route rte; segment* seg; Agedge_t* e; textlabel_t* lbl; for (; irte < n_edges; irte++) { e = es[irte].e; p1 = addPoints(ND_coord(agtail(e)), ED_tail_port(e).p); q1 = addPoints(ND_coord(aghead(e)), ED_head_port(e).p); rte = route_list[irte]; npts = 1 + 3*rte.n; if (npts > splsz) { if (ispline) free (ispline); ispline = N_GNEW(npts, pointf); splsz = npts; } seg = rte.segs; if (seg->isVert) { p.x = vtrack(seg, mp); p.y = p1.y; } else { p.y = htrack(seg, mp); p.x = p1.x; } ispline[0] = ispline[1] = p; ipt = 2; for (i = 1;i<rte.n;i++) { seg = rte.segs+i; if (seg->isVert) p.x = vtrack(seg, mp); else p.y = htrack(seg, mp); ispline[ipt+2] = ispline[ipt+1] = ispline[ipt] = p; ipt += 3; } if (seg->isVert) { p.x = vtrack(seg, mp); p.y = q1.y; } else { p.y = htrack(seg, mp); p.x = q1.x; } ispline[ipt] = ispline[ipt+1] = p; if (Verbose > 1) fprintf(stderr, "ortho %s %s\n", agnameof(agtail(e)),agnameof(aghead(e))); clip_and_install(e, aghead(e), ispline, npts, sinfo); if (doLbls && (lbl = ED_label(e)) && !lbl->set) addEdgeLabels(g, e, p1, q1); } free(ispline); }
static void makeCompoundEdge(graph_t * g, edge_t * e) #endif { graph_t *lh; /* cluster containing head */ graph_t *lt; /* cluster containing tail */ bezier *bez; /* original Bezier for e */ bezier *nbez; /* new Bezier for e */ int starti = 0, endi = 0; /* index of first and last control point */ node_t *head; node_t *tail; boxf *bb; int i, j; int size; pointf pts[4]; pointf p; int fixed; /* find head and tail target clusters, if defined */ #ifdef WITH_CGRAPH lh = getCluster(g, agget(e, "lhead"), clustMap); lt = getCluster(g, agget(e, "ltail"), clustMap); #else lh = getCluster(g, agget(e, "lhead")); lt = getCluster(g, agget(e, "ltail")); #endif if (!lt && !lh) return; if (!ED_spl(e)) return; /* at present, we only handle single spline case */ if (ED_spl(e)->size > 1) { agerr(AGWARN, "%s -> %s: spline size > 1 not supported\n", agnameof(agtail(e)), agnameof(aghead(e))); return; } bez = ED_spl(e)->list; size = bez->size; head = aghead(e); tail = agtail(e); /* allocate new Bezier */ nbez = GNEW(bezier); nbez->eflag = bez->eflag; nbez->sflag = bez->sflag; /* if Bezier has four points, almost collinear, * make line - unimplemented optimization? */ /* If head cluster defined, find first Bezier * crossing head cluster, and truncate spline to * box edge. * Otherwise, leave end alone. */ fixed = 0; if (lh) { bb = &(GD_bb(lh)); if (!inBoxf(ND_coord(head), bb)) { agerr(AGWARN, "%s -> %s: head not inside head cluster %s\n", agnameof(agtail(e)), agnameof(aghead(e)), agget(e, "lhead")); } else { /* If first control point is in bb, degenerate case. Spline * reduces to four points between the arrow head and the point * where the segment between the first control point and arrow head * crosses box. */ if (inBoxf(bez->list[0], bb)) { if (inBoxf(ND_coord(tail), bb)) { agerr(AGWARN, "%s -> %s: tail is inside head cluster %s\n", agnameof(agtail(e)), agnameof(aghead(e)), agget(e, "lhead")); } else { assert(bez->sflag); /* must be arrowhead on tail */ p = boxIntersectf(bez->list[0], bez->sp, bb); bez->list[3] = p; bez->list[1] = mid_pointf(p, bez->sp); bez->list[0] = mid_pointf(bez->list[1], bez->sp); bez->list[2] = mid_pointf(bez->list[1], p); if (bez->eflag) endi = arrowEndClip(e, bez->list, starti, 0, nbez, bez->eflag); endi += 3; fixed = 1; } } else { for (endi = 0; endi < size - 1; endi += 3) { if (splineIntersectf(&(bez->list[endi]), bb)) break; } if (endi == size - 1) { /* no intersection */ assert(bez->eflag); nbez->ep = boxIntersectf(bez->ep, bez->list[endi], bb); } else { if (bez->eflag) endi = arrowEndClip(e, bez->list, starti, endi, nbez, bez->eflag); endi += 3; } fixed = 1; } } } if (fixed == 0) { /* if no lh, or something went wrong, use original head */ endi = size - 1; if (bez->eflag) nbez->ep = bez->ep; } /* If tail cluster defined, find last Bezier * crossing tail cluster, and truncate spline to * box edge. * Otherwise, leave end alone. */ fixed = 0; if (lt) { bb = &(GD_bb(lt)); if (!inBoxf(ND_coord(tail), bb)) { agerr(AGWARN, "%s -> %s: tail not inside tail cluster %s\n", agnameof(agtail(e)), agnameof(aghead(e)), agget(e, "ltail")); } else { /* If last control point is in bb, degenerate case. Spline * reduces to four points between arrow head, and the point * where the segment between the last control point and the * arrow head crosses box. */ if (inBoxf(bez->list[endi], bb)) { if (inBoxf(ND_coord(head), bb)) { agerr(AGWARN, "%s -> %s: head is inside tail cluster %s\n", agnameof(agtail(e)), agnameof(aghead(e)), agget(e, "ltail")); } else { assert(bez->eflag); /* must be arrowhead on head */ p = boxIntersectf(bez->list[endi], nbez->ep, bb); starti = endi - 3; bez->list[starti] = p; bez->list[starti + 2] = mid_pointf(p, nbez->ep); bez->list[starti + 3] = mid_pointf(bez->list[starti + 2], nbez->ep); bez->list[starti + 1] = mid_pointf(bez->list[starti + 2], p); if (bez->sflag) starti = arrowStartClip(e, bez->list, starti, endi - 3, nbez, bez->sflag); fixed = 1; } } else { for (starti = endi; starti > 0; starti -= 3) { for (i = 0; i < 4; i++) pts[i] = bez->list[starti - i]; if (splineIntersectf(pts, bb)) { for (i = 0; i < 4; i++) bez->list[starti - i] = pts[i]; break; } } if (starti == 0) { assert(bez->sflag); nbez->sp = boxIntersectf(bez->sp, bez->list[starti], bb); } else { starti -= 3; if (bez->sflag) starti = arrowStartClip(e, bez->list, starti, endi - 3, nbez, bez->sflag); } fixed = 1; } } } if (fixed == 0) { /* if no lt, or something went wrong, use original tail */ /* Note: starti == 0 */ if (bez->sflag) nbez->sp = bez->sp; } /* complete Bezier, free garbage and attach new Bezier to edge */ nbez->size = endi - starti + 1; nbez->list = N_GNEW(nbez->size, pointf); for (i = 0, j = starti; i < nbez->size; i++, j++) nbez->list[i] = bez->list[j]; free(bez->list); free(bez); ED_spl(e)->list = nbez; }
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); } } } }
/* _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); }
/* 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)--; } }
grafo le_grafo(FILE *input) { Agraph_t *ag = agread(input, 0); if(!(ag && agisstrict(ag))) return NULL; // struct grafo *g = malloc(sizeof(struct grafo)); grafo g = malloc(sizeof(struct grafo)); if( !g ) return NULL; g->vertices = constroi_lista(); g->nome = malloc(sizeof(char) * strlen(agnameof(ag)+1)); strcpy(g->nome, agnameof(ag)); g->direcionado = agisdirected(ag); g->n_vertices = (unsigned int)agnnodes(ag); g->n_arestas = (unsigned int)agnedges(ag); g->ponderado = 0; for( Agnode_t *v = agfstnode(ag); v; v = agnxtnode(ag,v) ){ vertice vt = malloc(sizeof(struct vertice)); vt->nome = malloc(sizeof(char) * strlen(agnameof(v))+1); strcpy( vt->nome, agnameof(v) ); vt->visitado = 0; vt->coberto = 0; vt->arestas_saida = constroi_lista(); vt->arestas_entrada = constroi_lista(); insere_lista(vt, g->vertices); } for( Agnode_t *v = agfstnode(ag); v; v = agnxtnode(ag,v) ){ vertice vt = busca_vertice(g->vertices, agnameof(v)); if( g-> direcionado ){ for( Agedge_t *e = agfstout(ag,v); e; e = agnxtout(ag,e) ){ aresta at = cria_aresta(g->vertices, e); if( at->peso != 0 ) g->ponderado = 1; insere_lista(at, vt->arestas_saida); } for( Agedge_t *e = agfstin(ag,v); e; e = agnxtin(ag,e) ){ aresta at = cria_aresta(g->vertices, e); if( at->peso != 0 ) g->ponderado = 1; insere_lista(at, vt->arestas_entrada); } } else { for( Agedge_t *e = agfstedge(ag,v); e; e = agnxtedge(ag,e,v) ){ if( agtail(e) != v ) continue; aresta at = cria_aresta(g->vertices, e); if( at->peso != 0 ) g->ponderado = 1; insere_lista(at, at->origem->arestas_saida); insere_lista(at, at->destino->arestas_saida); } } } if( agclose(ag) ) return NULL; return g; }
/* strdup_and_subst_obj0: * Replace various escape sequences with the name of the associated * graph object. A double backslash \\ can be used to avoid a replacement. * If escBackslash is true, convert \\ to \; else leave alone. All other dyads * of the form \. are passed through unchanged. */ static char *strdup_and_subst_obj0 (char *str, void *obj, int escBackslash) { char c, *s, *p, *t, *newstr; char *tp_str = "", *hp_str = ""; char *g_str = "\\G", *n_str = "\\N", *e_str = "\\E", *h_str = "\\H", *t_str = "\\T", *l_str = "\\L"; int g_len = 2, n_len = 2, e_len = 2, h_len = 2, t_len = 2, l_len = 2, tp_len = 0, hp_len = 0; int newlen = 0; int isEdge = 0; textlabel_t *tl; port pt; /* prepare substitution strings */ switch (agobjkind(obj)) { case AGRAPH: g_str = agnameof((graph_t *)obj); g_len = strlen(g_str); tl = GD_label((graph_t *)obj); if (tl) { l_str = tl->text; if (str) l_len = strlen(l_str); } break; case AGNODE: g_str = agnameof(agraphof((node_t *)obj)); g_len = strlen(g_str); n_str = agnameof((node_t *)obj); n_len = strlen(n_str); tl = ND_label((node_t *)obj); if (tl) { l_str = tl->text; if (str) l_len = strlen(l_str); } break; case AGEDGE: isEdge = 1; g_str = agnameof(agroot(agraphof(agtail(((edge_t *)obj))))); g_len = strlen(g_str); t_str = agnameof(agtail(((edge_t *)obj))); t_len = strlen(t_str); pt = ED_tail_port((edge_t *)obj); if ((tp_str = pt.name)) tp_len = strlen(tp_str); h_str = agnameof(aghead(((edge_t *)obj))); h_len = strlen(h_str); pt = ED_head_port((edge_t *)obj); if ((hp_str = pt.name)) hp_len = strlen(hp_str); h_len = strlen(h_str); tl = ED_label((edge_t *)obj); if (tl) { l_str = tl->text; if (str) l_len = strlen(l_str); } if (agisdirected(agroot(agraphof(agtail(((edge_t*)obj)))))) e_str = "->"; else e_str = "--"; e_len = t_len + (tp_len?tp_len+1:0) + 2 + h_len + (hp_len?hp_len+1:0); break; } /* two passes over str. * * first pass prepares substitution strings and computes * total length for newstring required from malloc. */ for (s = str; (c = *s++);) { if (c == '\\') { switch (c = *s++) { case 'G': newlen += g_len; break; case 'N': newlen += n_len; break; case 'E': newlen += e_len; break; case 'H': newlen += h_len; break; case 'T': newlen += t_len; break; case 'L': newlen += l_len; break; case '\\': if (escBackslash) { newlen += 1; break; } /* Fall through */ default: /* leave other escape sequences unmodified, e.g. \n \l \r */ newlen += 2; } } else { newlen++; } } /* allocate new string */ newstr = gmalloc(newlen + 1); /* second pass over str assembles new string */ for (s = str, p = newstr; (c = *s++);) { if (c == '\\') { switch (c = *s++) { case 'G': for (t = g_str; (*p = *t++); p++); break; case 'N': for (t = n_str; (*p = *t++); p++); break; case 'E': if (isEdge) { for (t = t_str; (*p = *t++); p++); if (tp_len) { *p++ = ':'; for (t = tp_str; (*p = *t++); p++); } for (t = e_str; (*p = *t++); p++); for (t = h_str; (*p = *t++); p++); if (hp_len) { *p++ = ':'; for (t = hp_str; (*p = *t++); p++); } } break; case 'T': for (t = t_str; (*p = *t++); p++); break; case 'H': for (t = h_str; (*p = *t++); p++); break; case 'L': for (t = l_str; (*p = *t++); p++); break; case '\\': if (escBackslash) { *p++ = '\\'; break; } /* Fall through */ default: /* leave other escape sequences unmodified, e.g. \n \l \r */ *p++ = '\\'; *p++ = c; break; } } else { *p++ = c; } } *p++ = '\0'; return newstr; }
static void gv_graph_state(GVJ_t *job, graph_t *g) { #ifndef WITH_CGRAPH int i; #endif int j; Agsym_t *a; gv_argvlist_t *list; list = &(job->selected_obj_type_name); j = 0; if (g == agroot(g)) { if (agisdirected(g)) gv_argvlist_set_item(list, j++, s_digraph); else gv_argvlist_set_item(list, j++, s_graph); } else { gv_argvlist_set_item(list, j++, s_subgraph); } gv_argvlist_set_item(list, j++, agnameof(g)); list->argc = j; list = &(job->selected_obj_attributes); #ifndef WITH_CGRAPH for (i = 0, j = 0; i < dtsize(g->univ->globattr->dict); i++) { a = g->univ->globattr->list[i]; #else a = NULL; while ((a = agnxtattr(g, AGRAPH, a))) { #endif gv_argvlist_set_item(list, j++, a->name); #ifndef WITH_CGRAPH gv_argvlist_set_item(list, j++, agxget(g, a->index)); #else gv_argvlist_set_item(list, j++, agxget(g, a)); #endif gv_argvlist_set_item(list, j++, (char*)GVATTR_STRING); } list->argc = j; a = agfindgraphattr(g, s_href); if (!a) a = agfindgraphattr(g, s_URL); if (a) #ifndef WITH_CGRAPH job->selected_href = strdup_and_subst_obj(agxget(g, a->index), (void*)g); #else job->selected_href = strdup_and_subst_obj(agxget(g, a), (void*)g); #endif } static void gv_node_state(GVJ_t *job, node_t *n) { #ifndef WITH_CGRAPH int i; #endif int j; Agsym_t *a; Agraph_t *g; gv_argvlist_t *list; list = &(job->selected_obj_type_name); j = 0; gv_argvlist_set_item(list, j++, s_node); gv_argvlist_set_item(list, j++, agnameof(n)); list->argc = j; list = &(job->selected_obj_attributes); g = agroot(agraphof(n)); #ifndef WITH_CGRAPH for (i = 0, j = 0; i < dtsize(g->univ->nodeattr->dict); i++) { a = g->univ->nodeattr->list[i]; #else a = NULL; while ((a = agnxtattr(g, AGNODE, a))) { #endif gv_argvlist_set_item(list, j++, a->name); #ifndef WITH_CGRAPH gv_argvlist_set_item(list, j++, agxget(n, a->index)); #else gv_argvlist_set_item(list, j++, agxget(n, a)); #endif } list->argc = j; a = agfindnodeattr(agraphof(n), s_href); if (!a) a = agfindnodeattr(agraphof(n), s_URL); if (a) #ifndef WITH_CGRAPH job->selected_href = strdup_and_subst_obj(agxget(n, a->index), (void*)n); #else job->selected_href = strdup_and_subst_obj(agxget(n, a), (void*)n); #endif } static void gv_edge_state(GVJ_t *job, edge_t *e) { #ifndef WITH_CGRAPH int i; #endif int j; Agsym_t *a; Agraph_t *g; gv_argvlist_t *nlist, *alist; nlist = &(job->selected_obj_type_name); /* only tail, head, and key are strictly identifying properties, * but we commonly alse use edge kind (e.g. "->") and tailport,headport * in edge names */ j = 0; gv_argvlist_set_item(nlist, j++, s_edge); gv_argvlist_set_item(nlist, j++, agnameof(agtail(e))); j++; /* skip tailport slot for now */ gv_argvlist_set_item(nlist, j++, agisdirected(agraphof(agtail(e)))?"->":"--"); gv_argvlist_set_item(nlist, j++, agnameof(aghead(e))); j++; /* skip headport slot for now */ j++; /* skip key slot for now */ nlist->argc = j; alist = &(job->selected_obj_attributes); g = agroot(agraphof(aghead(e))); #ifndef WITH_CGRAPH for (i = 0, j = 0; i < dtsize(g->univ->edgeattr->dict); i++) { a = g->univ->edgeattr->list[i]; #else a = NULL; while ((a = agnxtattr(g, AGEDGE, a))) { #endif /* tailport and headport can be shown as part of the name, but they * are not identifying properties of the edge so we * also list them as modifyable attributes. */ if (strcmp(a->name,s_tailport) == 0) #ifndef WITH_CGRAPH gv_argvlist_set_item(nlist, 2, agxget(e, a->index)); #else gv_argvlist_set_item(nlist, 2, agxget(e, a)); #endif else if (strcmp(a->name,s_headport) == 0) #ifndef WITH_CGRAPH gv_argvlist_set_item(nlist, 5, agxget(e, a->index)); #else gv_argvlist_set_item(nlist, 5, agxget(e, a)); #endif /* key is strictly an identifying property to distinguish multiple * edges between the same node pair. Its non-writable, so * no need to list it as an attribute as well. */ else if (strcmp(a->name,s_key) == 0) { #ifndef WITH_CGRAPH gv_argvlist_set_item(nlist, 6, agxget(e, a->index)); #else gv_argvlist_set_item(nlist, 6, agxget(e, a)); #endif continue; } gv_argvlist_set_item(alist, j++, a->name); #ifndef WITH_CGRAPH gv_argvlist_set_item(alist, j++, agxget(e, a->index)); #else gv_argvlist_set_item(alist, j++, agxget(e, a)); #endif }
/* 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; } }
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); } }