edge_t * debug_getedge(graph_t *g, char *s0, char *s1) { node_t *n0,*n1; n0 = agfindnode(g,s0); n1 = agfindnode(g,s1); if (n0 && n1) return agfindedge(g,n0,n1); else return NULL; }
/* mapN: * Convert cluster nodes back to ordinary nodes * If n is already ordinary, return it. * Otherwise, we know node's name is "__i:xxx" * where i is some number and xxx is the nodes's original name. * Create new node of name xxx if it doesn't exist and add n to clg * for later deletion. */ static node_t *mapN(node_t * n, graph_t * clg) { extern Agdict_t *agdictof(void *); node_t *nn; char *name; graph_t *g = n->graph; Agdict_t *d; Agsym_t **list; Agsym_t *sym; if (!(IS_CLUST_NODE(n))) return n; aginsert(clg, n); name = strchr(n->name, ':'); assert(name); name++; if ((nn = agfindnode(g, name))) return nn; nn = agnode(g, name); /* Set all attributes to default */ d = agdictof(n); list = d->list; while ((sym = *list++)) { /* Can use pointer comparison because of ref strings. */ if (agxget(nn, sym->index) != sym->value) agxset(nn, sym->index, sym->value); } return nn; }
/* mapN: * Convert cluster nodes back to ordinary nodes * If n is already ordinary, return it. * Otherwise, we know node's name is "__i:xxx" * where i is some number and xxx is the nodes's original name. * Create new node of name xxx if it doesn't exist and add n to clg * for later deletion. */ static node_t *mapN(node_t * n, graph_t * clg) { node_t *nn; char *name; graph_t *g = agraphof(n); Agsym_t *sym; if (!(IS_CLUST_NODE(n))) return n; agsubnode(clg, n, 1); name = strchr(agnameof(n), ':'); assert(name); name++; if ((nn = agfindnode(g, name))) return nn; nn = agnode(g, name, 1); agbindrec(nn, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE); /* Set all attributes to default */ for (sym = agnxtattr(g, AGNODE, NULL); sym; (sym = agnxtattr(g, AGNODE, sym))) { if (agxget(nn, sym) != sym->defval) agxset(nn, sym, sym->defval); } return nn; }
/* twopi_layout: */ void twopi_layout(Agraph_t * g) { Agnode_t *ctr = 0; char *s; twopi_init_graph(g); s = agget(g, "root"); if (s && (*s != '\0')) { ctr = agfindnode(g, s); if (!ctr) { agerr(AGWARN, "specified root node \"%s\" was not found.", s); agerr(AGPREV, "Using default calculation for root node\n"); } } if (agnnodes(g)) { Agraph_t **ccs; Agraph_t *sg; Agnode_t *c = NULL; int ncc; int i; ccs = ccomps(g, &ncc, 0); if (ncc == 1) { circleLayout(g, ctr); adjustNodes(g); spline_edges(g); } else { pack_info pinfo; pack_mode pmode = getPackMode(g, l_node); for (i = 0; i < ncc; i++) { sg = ccs[i]; if (ctr && agcontains(sg, ctr)) c = ctr; else c = 0; nodeInduce(sg); circleLayout(sg, c); adjustNodes(sg); } spline_edges(g); pinfo.margin = getPack(g, CL_OFFSET, CL_OFFSET); pinfo.doSplines = 1; pinfo.mode = pmode; pinfo.fixed = 0; packSubgraphs(ncc, ccs, g, &pinfo); } for (i = 0; i < ncc; i++) { agdelete(g, ccs[i]); } free(ccs); } dotneato_postprocess(g); }
/* find_blocks: */ static void find_blocks(Agraph_t * g, circ_state * state) { Agnode_t *n; Agnode_t *root = NULL; block_t *rootBlock = NULL; blocklist_t ublks; #ifdef USER_BLOCKS graph_t *clust_subg; graph_t *mg; edge_t *me; node_t *mm; int isRoot; #endif initBlocklist(&ublks); /* check to see if there is a node which is set to be the root */ if (state->rootname) { root = agfindnode(g, state->rootname); } if (!root && state->N_root) { for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (late_bool(ORIGN(n), state->N_root, 0)) { root = n; break; } } } #ifdef USER_BLOCKS /* process clusters first */ /* by construction, all subgraphs are blocks and are non-empty */ mm = g->meta_node; mg = mm->graph; for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) { block_t *block; clust_subg = agusergraph(me->head); isRoot = 0; block = mkBlock(clust_subg); /* block = makeBlock(g, state); */ for (n = agfstnode(clust_subg); n; n = agnxtnode(clust_subg, n)) { if (!BCDONE(n)) { /* test not necessary if blocks disjoint */ SET_BCDONE(n); BLOCK(n) = block; if (n == root) isRoot = 1; } } if (isRoot) { /* Assume blocks are disjoint, so don't check if rootBlock is * already assigned. */ rootBlock = block; insertBlock(&state->bl, block); } else { appendBlock(&state->bl, block); } } ublks.first = state->bl.first; ublks.last = state->bl.last; #endif if (!root) root = agfstnode(g); dfs(g, root, state, !rootBlock); #ifdef USER_BLOCKS /* If g has user-supplied blocks, it may be disconnected. * We then fall into the following ugly loop. * We are guaranteed !VISITED(n) and PARENT(n) has been * set to a visited node. */ if (ublks.first) { while (n = findUnvisited(&ublks)) { dfs(g, n, state, 0); } } #endif }
/* twopi_layout: */ void twopi_layout(Agraph_t * g) { Agnode_t *ctr = 0; char *s; int setRoot = 0; pointf sc; int doScale = 0; int r; if (agnnodes(g) == 0) return; twopi_init_graph(g); s = agget(g, "root"); if ((s = agget(g, "root"))) { if (*s) { ctr = agfindnode(g, s); if (!ctr) { agerr(AGWARN, "specified root node \"%s\" was not found.", s); agerr(AGPREV, "Using default calculation for root node\n"); setRoot = 1; } } else { setRoot = 1; } } if ((s = agget(g, "scale")) && *s) { if ((r = sscanf (s, "%lf,%lf",&sc.x,&sc.y))) { if (r == 1) sc.y = sc.x; doScale = 1; if (Verbose) fprintf (stderr, "scale = (%f,%f)\n", sc.x, sc.y); } } if (agnnodes(g)) { Agraph_t **ccs; Agraph_t *sg; Agnode_t *c = NULL; Agnode_t *n; int ncc; int i; ccs = ccomps(g, &ncc, 0); if (ncc == 1) { c = circleLayout(g, ctr); if (setRoot && !ctr) ctr = c; n = agfstnode(g); free(ND_alg(n)); ND_alg(n) = NULL; if (doScale) scaleGraph (g, c, sc); adjustNodes(g); spline_edges(g); } else { pack_info pinfo; getPackInfo (g, l_node, CL_OFFSET, &pinfo); pinfo.doSplines = 0; for (i = 0; i < ncc; i++) { sg = ccs[i]; if (ctr && agcontains(sg, ctr)) c = ctr; else c = 0; nodeInduce(sg); c = circleLayout(sg, c); if (setRoot && !ctr) ctr = c; if (doScale) scaleGraph (sg, c, sc); adjustNodes(sg); } n = agfstnode(g); free(ND_alg(n)); ND_alg(n) = NULL; packSubgraphs(ncc, ccs, g, &pinfo); spline_edges(g); } for (i = 0; i < ncc; i++) { agdelete(g, ccs[i]); } free(ccs); } if (setRoot) agset (g, "root", agnameof (ctr)); dotneato_postprocess(g); }
/* makeGraphs: * Generate dags modeling the row and column constraints. * If the table has cc columns, we create the graph * 0 -> 1 -> 2 -> ... -> cc * and if a cell starts in column c with span cspan, with * width w, we add the edge c -> c+cspan [minlen = w]. * * We might simplify the graph by removing multiedges, * using the max minlen, but will affect the balancing? */ void makeGraphs(htmltbl_t * tbl, graph_t * rowg, graph_t * colg) { htmlcell_t *cp; htmlcell_t **cells; node_t *t; node_t *lastn; node_t *h; edge_t *e; int i; int* minc; int* minr; lastn = NULL; for (i = 0; i <= tbl->cc; i++) { t = agnode(colg, nToName(i)); alloc_elist(tbl->rc, ND_in(t)); alloc_elist(tbl->rc, ND_out(t)); if (lastn) { ND_next(lastn) = t; lastn = t; } else { lastn = GD_nlist(colg) = t; } } lastn = NULL; for (i = 0; i <= tbl->rc; i++) { t = agnode(rowg, nToName(i)); alloc_elist(tbl->cc, ND_in(t)); alloc_elist(tbl->cc, ND_out(t)); if (lastn) { ND_next(lastn) = t; lastn = t; } else { lastn = GD_nlist(rowg) = t; } } minr = N_NEW(tbl->rc, int); minc = N_NEW(tbl->cc, int); for (cells = tbl->u.n.cells; *cells; cells++) { int x, y, c, r; cp = *cells; x = (cp->data.box.UR.x + (cp->cspan-1))/cp->cspan; for (c = 0; c < cp->cspan; c++) minc[cp->col + c] = MAX(minc[cp->col + c],x); y = (cp->data.box.UR.y + (cp->rspan-1))/cp->rspan; for (r = 0; r < cp->rspan; r++) minr[cp->row + r] = MAX(minr[cp->row + r],y); } for (cells = tbl->u.n.cells; *cells; cells++) { int x, y, c, r; cp = *cells; t = agfindnode(colg, nToName(cp->col)); h = agfindnode(colg, nToName(cp->col + cp->cspan)); e = agedge(colg, t, h); x = 0; for (c = 0; c < cp->cspan; c++) x += minc[cp->col + c]; ED_minlen(e) = x; /* ED_minlen(e) = cp->data.box.UR.x; */ #ifdef DEBUG fprintf(stderr, "col edge %s -> %s %d\n", t->name, h->name, ED_minlen(e)); #endif elist_append(e, ND_out(t)); elist_append(e, ND_in(h)); t = agfindnode(rowg, nToName(cp->row)); h = agfindnode(rowg, nToName(cp->row + cp->rspan)); e = agedge(rowg, t, h); y = 0; for (r = 0; r < cp->rspan; r++) y += minr[cp->row + r]; ED_minlen(e) = y; /* ED_minlen(e) = cp->data.box.UR.y; */ #ifdef DEBUG fprintf(stderr, "row edge %s -> %s %d\n", t->name, h->name, ED_minlen(e)); #endif elist_append(e, ND_out(t)); elist_append(e, ND_in(h)); } /* Make sure that 0 <= 1 <= 2 ...k. This implies graph connected. */ checkChain(colg); checkChain(rowg); free (minc); free (minr); }
Agnode_t *findnode(Agraph_t *g, char *name) { if (!g || !name) return NULL; return agfindnode(g, name); }
void gates_save_layout (GQueue *gates, const char *mode, const char *format, const char *filename) { Agraph_t *graph; GVC_t* context; if (!gates || g_queue_is_empty (gates)) return; // create context (automatically calls aginit()) context = gvContext(); // open a graph graph = agopen((char*)"map", AGRAPHSTRICT); // strict, directed graph // add all gates to the graph // for (GList *iter=g_queue_peek_tail_link (gates);iter;iter=g_list_previous (iter)) { gate_t *gate = (gate_t*)iter->data; char name[5]; sprintf (name, "%d", gate->uid); printf ("creating node with name %s\n", name); agnode (graph, name); } // create edges int count=0; for (GList *iter=g_queue_peek_tail_link (gates);iter;iter=g_list_previous (iter)) { gate_t *gate = (gate_t*)iter->data; // find corresponding node char name[5]; sprintf (name, "%d", gate->uid); Agnode_t *n1 = agfindnode (graph, name); if (!n1) { dbg (DBG_ERROR, "failed to retrieve node from name %s", name); continue; } printf ("adding %d edges to node %d\n", gate->ng, gate->uid); for (int j=0;j<gate->ng;j++) { sprintf (name, "%d", gate->ng_names[j]); Agnode_t *n2 = agfindnode (graph, name); if (!n2) { dbg (DBG_ERROR, "failed to retrieve node from name %s", name); continue; } agedge (graph, n1, n2); count++; } } printf ("created %d edges.\n", count); // layout the graph // choices are: manual, fdp, dot, neato, twopi, circo dbg (DBG_CLASS, "rendering graph with graphviz. mode = %s", mode); if (strcmp (mode, "fdp")) { gvLayout (context, graph, (char*)"fdp"); } if (strcmp (mode, "dot")) { gvLayout (context, graph, (char*)"dot"); } if (strcmp (mode, "neato")) { gvLayout (context, graph, (char*)"neato"); } if (strcmp (mode, "twopi")) { gvLayout (context, graph, (char*)"twopi"); } if (strcmp (mode, "circo")) { gvLayout (context, graph, (char*)"circo"); } // render graph to file dbg (DBG_CLASS, "saving graph to file %s", filename); gvRenderFilename(context, graph, (char*)format, (char*)filename); dbg (DBG_CLASS, "done."); // free graph gvFreeLayout(context, graph); agclose (graph); gvFreeContext(context); }
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); } } } }