/* deleteObj: * Remove obj from g. * obj may belong to a subgraph of g, so we first must map * obj to its version in g. * If g is null, remove object from root graph. * If obj is a (sub)graph, close it. The g parameter is unused. * Return 0 on success, non-zero on failure. */ int deleteObj(Agraph_t * g, Agobj_t * obj) { gdata *data; if (AGTYPE(obj) == AGRAPH) { g = (Agraph_t *) obj; if (g != agroot(g)) return agclose(g); data = gData(g); if (data->lock & 1) { error(ERROR_WARNING, "Cannot delete locked graph %s", agnameof(g)); data->lock |= 2; return -1; } else return agclose(g); } /* node or edge */ if (!g) g = agroot(agraphof(obj)); if (obj) return agdelete(g, obj); else return -1; }
static void node_induce(graph_t * par, graph_t * g) { node_t *n, *nn; edge_t *e; int i; /* enforce that a node is in at most one cluster at this level */ for (n = agfstnode(g); n; n = nn) { nn = agnxtnode(g, n); if (ND_ranktype(n)) { agdelete(g, n); continue; } for (i = 1; i < GD_n_cluster(par); i++) if (agcontains(GD_clust(par)[i], n)) break; if (i < GD_n_cluster(par)) agdelete(g, n); ND_clust(n) = NULL; } for (n = agfstnode(g); n; n = agnxtnode(g, n)) { for (e = agfstout(agroot(g), n); e; e = agnxtout(agroot(g), e)) { if (agcontains(g, aghead(e))) #ifndef WITH_CGRAPH aginsert(g, e); #else /* WITH_CGRAPH */ agsubedge(g,e,1); #endif /* WITH_CGRAPH */ } } }
static void sfdp_init_graph(Agraph_t * g) { int outdim; setEdgeType(g, ET_LINE); outdim = late_int(g, agfindgraphattr(g, "dimen"), 2, 2); GD_ndim(agroot(g)) = late_int(g, agfindgraphattr(g, "dim"), outdim, 2); Ndim = GD_ndim(agroot(g)) = MIN(GD_ndim(agroot(g)), MAXDIM); GD_odim(agroot(g)) = MIN(outdim, Ndim); sfdp_init_node_edge(g); }
void setgraphattributes(Agraph_t * g, char *argv[], int argc) { int i; Agsym_t *a; for (i = 0; i < argc; i++) { if (!(a = agfindgraphattr(agroot(g), argv[i]))) a = agattr(agroot(g), AGRAPH, argv[i], ""); agxset(g, a, argv[++i]); } }
static void merge_ranks(graph_t * subg) { int i, d, r, pos, ipos; node_t *v; graph_t *root; root = agroot(subg); if (GD_minrank(subg) > 0) #ifndef WITH_CGRAPH ND_rank(root)[GD_minrank(subg) - 1].valid = FALSE; #else /* WITH_CGRAPH */ GD_rank(root)[GD_minrank(subg) - 1].valid = FALSE; #endif /* WITH_CGRAPH */ for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) { d = GD_rank(subg)[r].n; #ifndef WITH_CGRAPH ipos = pos = GD_rankleader(subg)[r]->u.order; #else /* WITH_CGRAPH */ ipos = pos = ND_order(GD_rankleader(subg)[r]); #endif /* WITH_CGRAPH */ make_slots(root, r, pos, d); for (i = 0; i < GD_rank(subg)[r].n; i++) { #ifndef WITH_CGRAPH v = ND_rank(root)[r].v[pos] = GD_rank(subg)[r].v[i]; #else /* WITH_CGRAPH */ v = GD_rank(root)[r].v[pos] = GD_rank(subg)[r].v[i]; #endif /* WITH_CGRAPH */ ND_order(v) = pos++; #ifndef WITH_CGRAPH v->graph = subg->root; #else /* WITH_CGRAPH */ /* real nodes automatically have v->root = root graph */ if (ND_node_type(v) == VIRTUAL) v->root = root; #endif /* WITH_CGRAPH */ delete_fast_node(subg, v); fast_node(agroot(subg), v); GD_n_nodes(agroot(subg))++; } #ifndef WITH_CGRAPH GD_rank(subg)[r].v = ND_rank(root)[r].v + ipos; ND_rank(root)[r].valid = FALSE; #else /* WITH_CGRAPH */ GD_rank(subg)[r].v = GD_rank(root)[r].v + ipos; GD_rank(root)[r].valid = FALSE; #endif /* WITH_CGRAPH */ } if (r < GD_maxrank(root)) GD_rank(root)[r].valid = FALSE; GD_expanded(subg) = TRUE; }
static void dot_init_subg(graph_t * g, graph_t* droot) { graph_t* subg; if ((g != agroot(g))) agbindrec(g, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE); if (g == droot) GD_dotroot(agroot(g)) = droot; for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) { dot_init_subg(subg, droot); } }
bool rm(Agraph_t *g) { Agedge_t *e; if (!g) return false; Agraph_t* sg; for (sg = agfstsubg (g); sg; sg = agnxtsubg (sg)) rm(sg); if (g == agroot(g)) agclose(g); else agdelete(agroot(g), g); return true; }
/* place_graph_label: * Put cluster labels recursively in the non-flip case. * The adjustments to the bounding boxes should no longer * be necessary, since we now guarantee the label fits in * the cluster. */ void place_graph_label(graph_t * g) { int c; pointf p, d; if ((g != agroot(g)) && (GD_label(g)) && !GD_label(g)->set) { if (GD_label_pos(g) & LABEL_AT_TOP) { d = GD_border(g)[TOP_IX]; p.y = GD_bb(g).UR.y - d.y / 2; } else { d = GD_border(g)[BOTTOM_IX]; p.y = GD_bb(g).LL.y + d.y / 2; } if (GD_label_pos(g) & LABEL_AT_RIGHT) { p.x = GD_bb(g).UR.x - d.x / 2; } else if (GD_label_pos(g) & LABEL_AT_LEFT) { p.x = GD_bb(g).LL.x + d.x / 2; } else { p.x = (GD_bb(g).LL.x + GD_bb(g).UR.x) / 2; } GD_label(g)->pos = p; GD_label(g)->set = TRUE; } for (c = 1; c <= GD_n_cluster(g); c++) place_graph_label(GD_clust(g)[c]); }
static void dot_cleanup_graph(graph_t * g) { int i, c; graph_t *clust; for (c = 1; c <= GD_n_cluster(g); c++) { clust = GD_clust(g)[c]; GD_cluster_was_collapsed(clust) = FALSE; dot_cleanup(clust); } if (GD_clust(g)) free (GD_clust(g)); if (GD_rankleader(g)) free (GD_rankleader(g)); free_list(GD_comp(g)); if (GD_rank(g)) { for (i = GD_minrank(g); i <= GD_maxrank(g); i++) free(GD_rank(g)[i].av); if (GD_minrank(g) == -1) free(GD_rank(g)-1); else free(GD_rank(g)); } if (g != agroot(g)) #ifndef WITH_CGRAPH memset(&(g->u), 0, sizeof(Agraphinfo_t)); #else /* WITH_CGRAPH */ agclean(g,AGRAPH,"Agraphinfo_t"); #endif /* WITH_CGRAPH */ }
Agsym_t *firstattr(Agraph_t *g) { if (!g) return NULL; g = agroot(g); return agnxtattr(g,AGRAPH,NULL); }
/*-------------------------------------------------------------------------*\ * Method: n.degree(self, what) * Determines degree of a node. * Returns number of in-edges (what='*i'), out-edges (what='*o') or the sum * of all edges (what='*a') to/from/of a node. * Example: * rv, err = n:degree("*i") \*-------------------------------------------------------------------------*/ int gr_degree(lua_State *L) { int count = 0; Agedge_t *e; Agraph_t *g; Agnode_t *n; gr_node_t *ud = tonode(L, 1, STRICT); char *flag = (char *) luaL_optstring(L, 2, "*a"); int indeg = TRUE; int outdeg = TRUE; n = ud->n; g = agroot(ud->n); if (*flag != '*'){ luaL_error(L, "invalid format specifier"); return 0; } switch(*(flag+1)){ case 'i': outdeg = FALSE; break; case 'o': indeg = FALSE; break; } if (indeg){ for (e = agfstin(g, n); e; e = agnxtin(g, e)){ count++; } } if (outdeg){ for (e = agfstout(g, n); e; e = agnxtout(g, e)){ count++; } } lua_pushnumber(L, count); return 1; }
/* clustNode: * Generate a special cluster node representing the end node * of an edge to the cluster cg. n is a node whose name is the same * as the cluster cg. clg is the subgraph of all of * the original nodes, which will be deleted later. */ static node_t *clustNode(node_t * n, graph_t * cg, agxbuf * xb, graph_t * clg) { node_t *cn; static int idx = 0; char num[100]; agxbput(xb, "__"); sprintf(num, "%d", idx++); agxbput(xb, num); agxbputc(xb, ':'); agxbput(xb, agnameof(cg)); cn = agnode(agroot(cg), agxbuse(xb), 1); agbindrec(cn, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE); SET_CLUST_NODE(cn); agsubnode(cg,cn,1); //aginsert(cg, cn); agsubnode(clg,n,1); //aginsert(clg, n); /* set attributes */ N_label = setAttr(agraphof(cn), cn, "label", "", N_label); N_style = setAttr(agraphof(cn), cn, "style", "invis", N_style); N_shape = setAttr(agraphof(cn), cn, "shape", "box", N_shape); /* N_width = setAttr (cn->graph, cn, "width", "0.0001", N_width); */ return cn; }
Agsym_t *nextattr(Agraph_t *g, Agsym_t *a) { int i; if (!g || !a) return NULL; g = agroot(g); return agnxtattr(g,AGRAPH,a); }
void deleteGraph(gctx_t * gctx, Agraph_t *g) { Agraph_t *sg; char *hndl; for (sg = agfstsubg (g); sg; sg = agnxtsubg (sg)) { deleteGraph(gctx, sg); } deleteGraphNodes(gctx, g); hndl = obj2cmd(g); if (g == agroot(g)) { agclose(g); } else { agdelsubg(agroot(g), g); } Tcl_DeleteCommand(gctx->ictx->interp, hndl); }
char *getv(Agraph_t *g, char *attr) { Agsym_t *a; if (!g || !attr) return NULL; a = agfindattr(agroot(g), attr); return myagxget(g, a); }
/* sameG: * Return common root if objects belong to same root graph. * NULL otherwise */ Agraph_t *sameG(void *p1, void *p2, char *fn, char *msg) { Agobj_t *obj1 = OBJ(p1); Agobj_t *obj2 = OBJ(p2); Agraph_t *root; root = agroot(agraphof(obj1)); if (root != agroot(agraphof(obj2))) { if (msg) error(ERROR_WARNING, "%s in %s() belong to different graphs", msg, fn); else error(ERROR_WARNING, "%s and %s in %s() belong to different graphs", KINDS(obj1), KINDS(obj2), fn); return 0; } else return root; }
static int countClusterLabels (Agraph_t* g) { int c, i = 0; if ((g != agroot(g)) && (GD_label(g)) && GD_label(g)->set) i++; for (c = 1; c <= GD_n_cluster(g); c++) i += countClusterLabels (GD_clust(g)[c]); return i; }
static void twopi_cleanup_graph(graph_t * g) { free(GD_neato_nlist(g)); if (g != agroot(g)) #ifndef WITH_CGRAPH memset(&(g->u), 0, sizeof(Agraphinfo_t)); #else /* WITH_CGRAPH */ agclean(g,AGRAPH,"Agraphinfo_t"); #endif /* WITH_CGRAPH */ }
/* * initialize dictionaries, set seq, invoke init method of new graph */ Agraph_t *agopen1(Agraph_t * g) { Agraph_t *par; g->n_seq = agdtopen(g, &Ag_subnode_seq_disc, Dttree); g->n_id = agdtopen(g, &Ag_subnode_id_disc, Dttree); g->e_seq = agdtopen(g, g == agroot(g)? &Ag_mainedge_seq_disc : &Ag_subedge_seq_disc, Dttree); g->e_id = agdtopen(g, g == agroot(g)? &Ag_mainedge_id_disc : &Ag_subedge_id_disc, Dttree); g->g_dict = agdtopen(g, &Ag_subgraph_id_disc, Dttree); par = agparent(g); if (par) { AGSEQ(g) = agnextseq(par, AGRAPH); dtinsert(par->g_dict, g); } /* else AGSEQ=0 */ if (!par || par->desc.has_attrs) agraphattr_init(g); agmethod_init(g, g); return g; }
bool rm(Agedge_t *e) { if (!e) return false; // removal of the protoedge is not permitted if ((agnameof(aghead(e))[0] == '\001' && strcmp (agnameof(aghead(e)), "\001proto") == 0) || (agnameof(agtail(e))[0] == '\001' && strcmp (agnameof(agtail(e)), "\001proto") == 0)) return false; agdelete(agroot(agraphof(aghead(e))), e); return true; }
char *setv(Agraph_t *g, char *attr, char *val) { Agsym_t *a; if (!g || !attr || !val) return NULL; a = agfindattr(agroot(g), attr); if (!a) a = agraphattr(g->root, attr, emptystring); myagxset(g, a, val); return val; }
char *getv(Agnode_t *n, char *attr) { Agraph_t *g; Agsym_t *a; if (!n || !attr) return NULL; if (AGTYPE(n) == AGRAPH) // protonode return NULL; // FIXME ?? g = agroot(agraphof(n)); a = agattr(g, AGNODE, attr, NULL); return myagxget(n, a); }
static int label_subgs(Agraph_t* g, int lbl, Dt_t* map) { Agraph_t* sg; if (g != agroot(g)) { GD_gid(g) = lbl++; if (IS_CLUSTER(g)) insert (map, agnameof(g), GD_gid(g)); } for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) { lbl = label_subgs(sg, lbl, map); } return lbl; }
static cinfo_t addClusterObj (Agraph_t* g, cinfo_t info) { int c; for (c = 1; c <= GD_n_cluster(g); c++) info = addClusterObj (GD_clust(g)[c], info); if ((g != agroot(g)) && (GD_label(g)) && GD_label(g)->set) { object_t* objp = info.objp; info.bb = addLabelObj (GD_label(g), objp, info.bb); info.objp++; } return info; }
/* isEdge: * Return edge, if any, between t and h with given key. * Edge is in g. */ Agedge_t *isEdge(Agraph_t* g, Agnode_t * t, Agnode_t * h, char *key) { Agraph_t *root; root = sameG(t, h, "isEdge", "tail and head node"); if (!root) return 0; if (g) { if (root != agroot(g)) return 0; } else g = root; return agedge(g, t, h, key, 0); }
void setnodeattributes(Agraph_t * g, Agnode_t * n, char *argv[], int argc) { int i; Agsym_t *a; for (i = 0; i < argc; i++) { if (n) { if (!(a = agfindnodeattr(g, argv[i]))) a = agattr(agroot(g), AGNODE, argv[i], ""); agxset(n, a, argv[++i]); } else { agattr(g, AGNODE, argv[i], argv[i+1]); i++; } } }
static void nodeInduce(Agraph_t * g) { Agnode_t *n, *rootn; Agedge_t *e; for (n = agfstnode(g); n; n = agnxtnode(n)) { rootn = agsubnode(agroot(g), n, FALSE); for (e = agfstout(rootn); e; e = agnxtout(e)) { if (agsubnode(g, aghead(e), FALSE)) agsubedge(g, e, TRUE); else { if (getscc(aghead(e)) && getscc(agtail(e))) agedge(getrep(getscc(agtail(e))), getrep(getscc(aghead(e))), NIL(char *), TRUE); } } } }
/* nodeInduce: * Add all edges in root graph connecting two nodes in * selected to selected. */ void nodeInduce(Agraph_t * selected) { Agnode_t *n; Agedge_t *e; Agraph_t *base; if (!selected) return; base = agroot(selected); if (base == selected) return; for (n = agfstnode(selected); n; n = agnxtnode(selected, n)) { for (e = agfstout(base, n); e; e = agnxtout(base, e)) { if (agsubnode(selected, aghead(e), FALSE)) agsubedge(selected, e, TRUE); } } }
static void remove_rankleaders(graph_t * g) { int r; node_t *v; edge_t *e; for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { v = GD_rankleader(g)[r]; /* remove the entire chain */ while ((e = ND_out(v).list[0])) delete_fast_edge(e); while ((e = ND_in(v).list[0])) delete_fast_edge(e); delete_fast_node(agroot(g), v); GD_rankleader(g)[r] = NULL; } }
static void write_attrs(Agobj_t * obj, GVJ_t * job, state_t* sp) { Agraph_t* g = agroot(obj); int type = AGTYPE(obj); char* attrval; Agsym_t* sym = agnxtattr(g, type, NULL); if (!sym) return; for (; sym; sym = agnxtattr(g, type, sym)) { if (!(attrval = agxget(obj, sym))) continue; if ((*attrval == '\0') && !streq(sym->name, "label")) continue; gvputs(job, ",\n"); indent(job, sp->Level); gvprintf(job, "\"%s\": ", stoj(sym->name, sp)); if (sp->doXDot && isXDot(sym->name)) write_xdots(agxget(obj, sym), job, sp); else gvprintf(job, "\"%s\"", stoj(agxget(obj, sym), sp)); } }