void common_init_node(node_t * n) { struct fontinfo fi; char *str; ND_width(n) = late_double(n, N_width, DEFAULT_NODEWIDTH, MIN_NODEWIDTH); ND_height(n) = late_double(n, N_height, DEFAULT_NODEHEIGHT, MIN_NODEHEIGHT); ND_shape(n) = bind_shape(late_nnstring(n, N_shape, DEFAULT_NODESHAPE), n); str = agxget(n, N_label); fi.fontsize = late_double(n, N_fontsize, DEFAULT_FONTSIZE, MIN_FONTSIZE); fi.fontname = late_nnstring(n, N_fontname, DEFAULT_FONTNAME); fi.fontcolor = late_nnstring(n, N_fontcolor, DEFAULT_COLOR); ND_label(n) = make_label((void*)n, str, ((aghtmlstr(str) ? LT_HTML : LT_NONE) | ( (shapeOf(n) == SH_RECORD) ? LT_RECD : LT_NONE)), fi.fontsize, fi.fontname, fi.fontcolor); if (N_xlabel && (str = agxget(n, N_xlabel)) && (str[0])) { ND_xlabel(n) = make_label((void*)n, str, (aghtmlstr(str) ? LT_HTML : LT_NONE), fi.fontsize, fi.fontname, fi.fontcolor); GD_has_labels(agraphof(n)) |= NODE_XLABEL; } ND_showboxes(n) = late_int(n, N_showboxes, 0, 0); ND_shape(n)->fns->initfn(n); }
/* When there are edge labels, extra ranks are reserved here for the virtual * nodes of the labels. This is done by doubling the input edge lengths. * The input rank separation is adjusted to compensate. */ void edgelabel_ranks(graph_t* g) { node_t *n; edge_t *e; if (GD_has_labels(g)&EDGE_LABEL) { for (n = agfstnode(g); n; n = agnxtnode(g,n)) for (e = agfstout(g,n); e; e = agnxtout(g,e)) ED_minlen(e) *= 2; GD_ranksep(g) = (GD_ranksep(g) + 1) / 2; } }
/* return TRUE if edge has label */ int common_init_edge(edge_t * e) { char *s; int html = 0, r = 0; struct fontinfo fi; struct fontinfo lfi; fi.fontname = NULL; lfi.fontname = NULL; if (E_label && (s = agxget(e, E_label->index)) && (s[0])) { r = 1; html = aghtmlstr(s); if (html) s = strdup(s); else s = strdup_and_subst_edge(s, e); initFontEdgeAttr(e, &fi); ED_label(e) = make_label(html, s, fi.fontsize, fi.fontname, fi.fontcolor, e->tail->graph); #ifdef ENABLE_HTML //maks if (html) { if (make_html_label(ED_label(e), e) == 1) edgeError(e, "label"); } #endif GD_has_labels(e->tail->graph) |= EDGE_LABEL; ED_label_ontop(e) = mapbool(late_string(e, E_label_float, "false")); } /* vladimir */ if (E_headlabel && (s = agxget(e, E_headlabel->index)) && (s[0])) { html = aghtmlstr(s); if (html) s = strdup(s); else s = strdup_and_subst_edge(s, e); initFontLabelEdgeAttr(e, &fi, &lfi); ED_head_label(e) = make_label(html, s, lfi.fontsize, lfi.fontname, lfi.fontcolor, e->tail->graph); #ifdef ENABLE_HTML //maks if (html) { if (make_html_label(ED_head_label(e), e) == 1) edgeError(e, "head label"); } #endif GD_has_labels(e->tail->graph) |= HEAD_LABEL; } if (E_taillabel && (s = agxget(e, E_taillabel->index)) && (s[0])) { html = aghtmlstr(s); if (html) s = strdup(s); else s = strdup_and_subst_edge(s, e); if (!lfi.fontname) initFontLabelEdgeAttr(e, &fi, &lfi); ED_tail_label(e) = make_label(html, s, lfi.fontsize, lfi.fontname, lfi.fontcolor, e->tail->graph); #ifdef ENABLE_HTML //maks if (html) { if (make_html_label(ED_tail_label(e), e) == 1) edgeError(e, "tail label"); } #endif GD_has_labels(e->tail->graph) |= TAIL_LABEL; } /* end vladimir */ /* We still accept ports beginning with colons but this is deprecated */ s = agget(e, TAIL_ID); if (s[0]) ND_has_port(e->tail) = TRUE; ED_tail_port(e) = chkPort (ND_shape(e->tail)->fns->portfn,e->tail, s); if (noClip(e, E_tailclip)) ED_tail_port(e).clip = FALSE; s = agget(e, HEAD_ID); if (s[0]) ND_has_port(e->head) = TRUE; ED_head_port(e) = chkPort(ND_shape(e->head)->fns->portfn,e->head, s); if (noClip(e, E_headclip)) ED_head_port(e).clip = FALSE; return r; }
/* do_graph_label: * Set characteristics of graph label if it exists. * */ void do_graph_label(graph_t * sg) { char *str, *pos, *just; int pos_ix; /* it would be nice to allow multiple graph labels in the future */ if ((str = agget(sg, "label")) && (*str != '\0')) { char pos_flag; pointf dimen; GD_has_labels(sg->root) |= GRAPH_LABEL; GD_label(sg) = make_label((void*)sg, str, (aghtmlstr(str) ? LT_HTML : LT_NONE), late_double(sg, agfindgraphattr(sg, "fontsize"), DEFAULT_FONTSIZE, MIN_FONTSIZE), late_nnstring(sg, agfindgraphattr(sg, "fontname"), DEFAULT_FONTNAME), late_nnstring(sg, agfindgraphattr(sg, "fontcolor"), DEFAULT_COLOR)); /* set label position */ pos = agget(sg, "labelloc"); if (sg != agroot(sg)) { if (pos && (pos[0] == 'b')) pos_flag = LABEL_AT_BOTTOM; else pos_flag = LABEL_AT_TOP; } else { if (pos && (pos[0] == 't')) pos_flag = LABEL_AT_TOP; else pos_flag = LABEL_AT_BOTTOM; } just = agget(sg, "labeljust"); if (just) { if (just[0] == 'l') pos_flag |= LABEL_AT_LEFT; else if (just[0] == 'r') pos_flag |= LABEL_AT_RIGHT; } GD_label_pos(sg) = pos_flag; if (sg == agroot(sg)) return; /* Set border information for cluster labels to allow space */ dimen = GD_label(sg)->dimen; PAD(dimen); if (!GD_flip(agroot(sg))) { if (GD_label_pos(sg) & LABEL_AT_TOP) pos_ix = TOP_IX; else pos_ix = BOTTOM_IX; GD_border(sg)[pos_ix] = dimen; } else { /* when rotated, the labels will be restored to TOP or BOTTOM */ if (GD_label_pos(sg) & LABEL_AT_TOP) pos_ix = RIGHT_IX; else pos_ix = LEFT_IX; GD_border(sg)[pos_ix].x = dimen.y; GD_border(sg)[pos_ix].y = dimen.x; } } }
static void addXLabels(Agraph_t * gp) { Agnode_t *np; Agedge_t *ep; int cnt, i, n_objs, n_lbls; int n_nlbls = 0; /* # of unset node xlabels */ int n_elbls = 0; /* # of unset edge labels or xlabels */ int n_set_lbls = 0; /* # of set xlabels and edge labels */ int n_clbls = 0; /* # of set cluster labels */ boxf bb; pointf ur; textlabel_t* lp; label_params_t params; object_t* objs; xlabel_t* lbls; object_t* objp; xlabel_t* xlp; Agsym_t* force; int et = EDGE_TYPE(gp); if (!(GD_has_labels(gp) & NODE_XLABEL) && !(GD_has_labels(gp) & EDGE_XLABEL) && !(GD_has_labels(gp) & TAIL_LABEL) && !(GD_has_labels(gp) & HEAD_LABEL) && (!(GD_has_labels(gp) & EDGE_LABEL) || EdgeLabelsDone)) return; for (np = agfstnode(gp); np; np = agnxtnode(gp, np)) { if (ND_xlabel(np)) { if (ND_xlabel(np)->set) n_set_lbls++; else n_nlbls++; } for (ep = agfstout(gp, np); ep; ep = agnxtout(gp, ep)) { if (ED_xlabel(ep)) { if (ED_xlabel(ep)->set) n_set_lbls++; else if (HAVE_EDGE(ep)) n_elbls++; } if (ED_head_label(ep)) { if (ED_head_label(ep)->set) n_set_lbls++; else if (HAVE_EDGE(ep)) n_elbls++; } if (ED_tail_label(ep)) { if (ED_tail_label(ep)->set) n_set_lbls++; else if (HAVE_EDGE(ep)) n_elbls++; } if (ED_label(ep)) { if (ED_label(ep)->set) n_set_lbls++; else if (HAVE_EDGE(ep)) n_elbls++; } } } if (GD_has_labels(gp) & GRAPH_LABEL) n_clbls = countClusterLabels (gp); /* A label for each unpositioned external label */ n_lbls = n_nlbls + n_elbls; if (n_lbls == 0) return; /* An object for each node, each positioned external label, any cluster label, * and all unset edge labels and xlabels. */ n_objs = agnnodes(gp) + n_set_lbls + n_clbls + n_elbls; objp = objs = N_NEW(n_objs, object_t); xlp = lbls = N_NEW(n_lbls, xlabel_t); bb.LL = pointfof(INT_MAX, INT_MAX); bb.UR = pointfof(-INT_MAX, -INT_MAX); for (np = agfstnode(gp); np; np = agnxtnode(gp, np)) { bb = addNodeObj (np, objp, bb); if ((lp = ND_xlabel(np))) { if (lp->set) { objp++; bb = addLabelObj (lp, objp, bb); } else { addXLabel (lp, objp, xlp, 0, ur); xlp++; } } objp++; for (ep = agfstout(gp, np); ep; ep = agnxtout(gp, ep)) { if ((lp = ED_label(ep))) { if (lp->set) { bb = addLabelObj (lp, objp, bb); } else if (HAVE_EDGE(ep)) { addXLabel (lp, objp, xlp, 1, edgeMidpoint(gp, ep)); xlp++; } else { agerr(AGWARN, "no position for edge with label %s", ED_label(ep)->text); continue; } objp++; } if ((lp = ED_tail_label(ep))) { if (lp->set) { bb = addLabelObj (lp, objp, bb); } else if (HAVE_EDGE(ep)) { addXLabel (lp, objp, xlp, 1, edgeTailpoint(ep)); xlp++; } else { agerr(AGWARN, "no position for edge with tail label %s", ED_tail_label(ep)->text); continue; } objp++; } if ((lp = ED_head_label(ep))) { if (lp->set) { bb = addLabelObj (lp, objp, bb); } else if (HAVE_EDGE(ep)) { addXLabel (lp, objp, xlp, 1, edgeHeadpoint(ep)); xlp++; } else { agerr(AGWARN, "no position for edge with head label %s", ED_head_label(ep)->text); continue; } objp++; } if ((lp = ED_xlabel(ep))) { if (lp->set) { bb = addLabelObj (lp, objp, bb); } else if (HAVE_EDGE(ep)) { addXLabel (lp, objp, xlp, 1, edgeMidpoint(gp, ep)); xlp++; } else { agerr(AGWARN, "no position for edge with xlabel %s", ED_xlabel(ep)->text); continue; } objp++; } } } if (n_clbls) { cinfo_t info; info.bb = bb; info.objp = objp; info = addClusterObj (gp, info); bb = info.bb; } force = agfindgraphattr(gp, "forcelabels"); params.force = late_bool(gp, force, TRUE); params.bb = bb; placeLabels(objs, n_objs, lbls, n_lbls, ¶ms); if (Verbose) printData(objs, n_objs, lbls, n_lbls, ¶ms); xlp = lbls; cnt = 0; for (i = 0; i < n_lbls; i++) { if (xlp->set) { cnt++; lp = (textlabel_t *) (xlp->lbl); lp->set = 1; lp->pos = centerPt(xlp); updateBB (gp, lp); } xlp++; } if (Verbose) fprintf (stderr, "%d out of %d labels positioned.\n", cnt, n_lbls); else if (cnt != n_lbls) agerr(AGWARN, "%d out of %d exterior labels positioned.\n", cnt, n_lbls); free(objs); free(lbls); }
void attach_attrs_and_arrows(graph_t* g, int* sp, int* ep) { int e_arrows; /* graph has edges with end arrows */ int s_arrows; /* graph has edges with start arrows */ int i, j, sides; char buf[BUFSIZ]; /* Used only for small strings */ unsigned char xbuffer[BUFSIZ]; /* Initial buffer for xb */ agxbuf xb; node_t *n; edge_t *e; point pt; e_arrows = s_arrows = 0; setYInvert(g); agxbinit(&xb, BUFSIZ, xbuffer); safe_dcl(g, g->proto->n, "pos", "", agnodeattr); safe_dcl(g, g->proto->n, "rects", "", agnodeattr); N_width = safe_dcl(g, g->proto->n, "width", "", agnodeattr); N_height = safe_dcl(g, g->proto->n, "height", "", agnodeattr); safe_dcl(g, g->proto->e, "pos", "", agedgeattr); if (GD_has_labels(g) & EDGE_LABEL) safe_dcl(g, g->proto->e, "lp", "", agedgeattr); if (GD_has_labels(g) & HEAD_LABEL) safe_dcl(g, g->proto->e, "head_lp", "", agedgeattr); if (GD_has_labels(g) & TAIL_LABEL) safe_dcl(g, g->proto->e, "tail_lp", "", agedgeattr); if (GD_label(g)) { safe_dcl(g, g, "lp", "", agraphattr); if (GD_label(g)->text[0]) { pt = GD_label(g)->p; sprintf(buf, "%d,%d", pt.x, YDIR(pt.y)); agset(g, "lp", buf); } } safe_dcl(g, g, "bb", "", agraphattr); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { sprintf(buf, "%d,%d", ND_coord_i(n).x, YDIR(ND_coord_i(n).y)); agset(n, "pos", buf); sprintf(buf, "%.2f", PS2INCH(ND_ht_i(n))); agxset(n, N_height->index, buf); sprintf(buf, "%.2f", PS2INCH(ND_lw_i(n) + ND_rw_i(n))); agxset(n, N_width->index, buf); if (strcmp(ND_shape(n)->name, "record") == 0) { set_record_rects(n, ND_shape_info(n), &xb); agxbpop(&xb); /* get rid of last space */ agset(n, "rects", agxbuse(&xb)); } else { polygon_t *poly; int i; if (N_vertices && isPolygon(n)) { poly = (polygon_t *) ND_shape_info(n); sides = poly->sides; if (sides < 3) { char *p = agget(n, "samplepoints"); if (p) sides = atoi(p); else sides = 8; if (sides < 3) sides = 8; } for (i = 0; i < sides; i++) { if (i > 0) agxbputc(&xb, ' '); if (poly->sides >= 3) sprintf(buf, "%.3f %.3f", PS2INCH(poly->vertices[i].x), YFDIR(PS2INCH(poly->vertices[i].y))); else sprintf(buf, "%.3f %.3f", ND_width(n) / 2.0 * cos(i / (double) sides * PI * 2.0), YFDIR(ND_height(n) / 2.0 * sin(i / (double) sides * PI * 2.0))); agxbput(&xb, buf); } agxset(n, N_vertices->index, agxbuse(&xb)); } } if (State >= GVSPLINES) { for (e = agfstout(g, n); e; e = agnxtout(g, e)) { if (ED_edge_type(e) == IGNORED) continue; if (ED_spl(e) == NULL) continue; /* reported in postproc */ for (i = 0; i < ED_spl(e)->size; i++) { if (i > 0) agxbputc(&xb, ';'); if (ED_spl(e)->list[i].sflag) { s_arrows = 1; sprintf(buf, "s,%d,%d ", ED_spl(e)->list[i].sp.x, YDIR(ED_spl(e)->list[i].sp.y)); agxbput(&xb, buf); } if (ED_spl(e)->list[i].eflag) { e_arrows = 1; sprintf(buf, "e,%d,%d ", ED_spl(e)->list[i].ep.x, YDIR(ED_spl(e)->list[i].ep.y)); agxbput(&xb, buf); } for (j = 0; j < ED_spl(e)->list[i].size; j++) { if (j > 0) agxbputc(&xb, ' '); pt = ED_spl(e)->list[i].list[j]; sprintf(buf, "%d,%d", pt.x, YDIR(pt.y)); agxbput(&xb, buf); } } agset(e, "pos", agxbuse(&xb)); if (ED_label(e)) { pt = ED_label(e)->p; sprintf(buf, "%d,%d", pt.x, YDIR(pt.y)); agset(e, "lp", buf); } if (ED_head_label(e)) { pt = ED_head_label(e)->p; sprintf(buf, "%d,%d", pt.x, YDIR(pt.y)); agset(e, "head_lp", buf); } if (ED_tail_label(e)) { pt = ED_tail_label(e)->p; sprintf(buf, "%d,%d", pt.x, YDIR(pt.y)); agset(e, "tail_lp", buf); } } } } rec_attach_bb(g); agxbfree(&xb); if (HAS_CLUST_EDGE(g)) undoClusterEdges(g); *sp = s_arrows; *ep = e_arrows; }
/* * John M. suggests: * You might want to add four more: * * _ohdraw_ (optional head-end arrow for edges) * _ohldraw_ (optional head-end label for edges) * _otdraw_ (optional tail-end arrow for edges) * _otldraw_ (optional tail-end label for edges) * * that would be generated when an additional option is supplied to * dot, etc. and * these would be the arrow/label positions to use if a user want to flip the * direction of an edge (as sometimes is there want). * * N.B. John M. asks: * By the way, I don't know if you ever plan to add other letters for * the xdot spec, but could you reserve "a" and also "A" (for attribute), * "n" and also "N" (for numeric), "w" (for sWitch), "s" (for string) * and "t" (for tooltip) and "x" (for position). We use those letters in * our drawing spec (and also "<" and ">"), so if you start generating * output with them, it could break what we have. */ static void xdot_begin_graph (graph_t *g, int s_arrows, int e_arrows, format_type id) { int i, us; char* s; xd = GNEW(xdot_state_t); if (id == FORMAT_XDOT14) { xd->version = 14; xd->version_s = "1.4"; } else if (id == FORMAT_XDOT12) { xd->version = 12; xd->version_s = "1.2"; } else if ((s = agget(g, "xdotversion")) && s[0] && ((us = versionStr2Version(s)) > 10)) { xd->version = us; xd->version_s = s; } else { xd->version = versionStr2Version(XDOTVERSION); xd->version_s = XDOTVERSION; } if (GD_n_cluster(g)) xd->g_draw = safe_dcl(g, AGRAPH, "_draw_", ""); else xd->g_draw = NULL; if (GD_has_labels(g) & GRAPH_LABEL) xd->g_l_draw = safe_dcl(g, AGRAPH, "_ldraw_", ""); else xd->g_l_draw = NULL; xd->n_draw = safe_dcl(g, AGNODE, "_draw_", ""); xd->n_l_draw = safe_dcl(g, AGNODE, "_ldraw_", ""); xd->e_draw = safe_dcl(g, AGEDGE, "_draw_", ""); if (e_arrows) xd->h_draw = safe_dcl(g, AGEDGE, "_hdraw_", ""); else xd->h_draw = NULL; if (s_arrows) xd->t_draw = safe_dcl(g, AGEDGE, "_tdraw_", ""); else xd->t_draw = NULL; if (GD_has_labels(g) & (EDGE_LABEL|EDGE_XLABEL)) xd->e_l_draw = safe_dcl(g, AGEDGE, "_ldraw_", ""); else xd->e_l_draw = NULL; if (GD_has_labels(g) & HEAD_LABEL) xd->hl_draw = safe_dcl(g, AGEDGE, "_hldraw_", ""); else xd->hl_draw = NULL; if (GD_has_labels(g) & TAIL_LABEL) xd->tl_draw = safe_dcl(g, AGEDGE, "_tldraw_", ""); else xd->tl_draw = NULL; for (i = 0; i < NUMXBUFS; i++) agxbinit(xbuf+i, BUFSIZ, xd->buf[i]); }
/* do_graph_label: * If the ifdef'ed parts are added, clusters are guaranteed not * to overlap and have sufficient room for the label. The problem * is this approach does not use the actual size of the cluster, so * the resulting cluster tends to be far too large. */ void do_graph_label(graph_t* sg) { char *p, *pos, *just; int pos_ix; GVC_t *gvc = GD_gvc(sg->root); /* it would be nice to allow multiple graph labels in the future */ if ((p = agget(sg,"label"))) { char pos_flag; int html = aghtmlstr(p); GD_has_labels(sg->root) |= GRAPH_LABEL; GD_label(sg) = make_label(gvc, html,strdup_and_subst_graph(p,sg), late_double(sg,agfindattr(sg,"fontsize"),DEFAULT_FONTSIZE,MIN_FONTSIZE), late_nnstring(sg,agfindattr(sg,"fontname"),DEFAULT_FONTNAME), late_nnstring(sg,agfindattr(sg,"fontcolor"),DEFAULT_COLOR),sg); if (html) { if (make_html_label(gvc, GD_label(sg), sg)) agerr (AGPREV, "in label of graph %s\n", sg->name); } /* set label position */ pos = agget(sg,"labelloc"); if (sg != sg->root) { if (pos && (pos[0] == 'b')) pos_flag = LABEL_AT_BOTTOM; else pos_flag = LABEL_AT_TOP; } else { if (pos && (pos[0] == 't')) pos_flag = LABEL_AT_TOP; else pos_flag = LABEL_AT_BOTTOM; } just = agget(sg,"labeljust"); if (just) { if (just[0] == 'l') pos_flag |= LABEL_AT_LEFT; else if (just[0] == 'r') pos_flag |= LABEL_AT_RIGHT; } GD_label_pos(sg) = pos_flag; if(!GD_left_to_right(sg->root)) { point dpt; dpt = cvt2pt(GD_label(sg)->dimen); if (GD_label_pos(sg) & LABEL_AT_TOP) pos_ix = TOP_IX; else pos_ix = BOTTOM_IX; GD_border(sg)[pos_ix] = dpt; #if 0 if(g != g->root) { GD_border(g)[LEFT_IX].x = dpt.x/2; GD_border(g)[RIGHT_IX].x = dpt.x/2; GD_border(g)[LEFT_IX].y = 0; GD_border(g)[RIGHT_IX].y = 0; } #endif } else { point dpt; dpt = cvt2pt(GD_label(sg)->dimen); /* when rotated, the labels will be restored to TOP or BOTTOM */ if (GD_label_pos(sg) & LABEL_AT_TOP) pos_ix = RIGHT_IX; else pos_ix = LEFT_IX; GD_border(sg)[pos_ix].x = dpt.y; GD_border(sg)[pos_ix].y = dpt.x; #if 0 if(g != g->root) { GD_border(g)[TOP_IX].y = dpt.x/2; GD_border(g)[BOTTOM_IX].y = dpt.x/2; GD_border(g)[TOP_IX].x = 0; GD_border(g)[BOTTOM_IX].x = 0; } #endif } } }
/* do_graph_label: * Set characteristics of graph label if it exists. * */ void do_graph_label(graph_t * sg) { char *p, *pos, *just; int pos_ix; /* it would be nice to allow multiple graph labels in the future */ if ((p = agget(sg, "label"))) { char pos_flag; int lbl_kind = LT_NONE; point dpt; pointf dimen; if (aghtmlstr(p)) lbl_kind = LT_HTML; GD_has_labels(sg->root) |= GRAPH_LABEL; if (lbl_kind) p = strdup (p); else p = strdup_and_subst_obj(p, (void*)sg); GD_label(sg) = make_label(sg->root, lbl_kind, p, late_double(sg, agfindattr(sg, "fontsize"), DEFAULT_FONTSIZE, MIN_FONTSIZE), late_nnstring(sg, agfindattr(sg, "fontname"), DEFAULT_FONTNAME), late_nnstring(sg, agfindattr(sg, "fontcolor"), DEFAULT_COLOR)); if (lbl_kind) { if (make_html_label(sg->root, GD_label(sg), sg) == 1) agerr(AGPREV, "in label of graph %s\n", sg->name); } /* set label position */ pos = agget(sg, "labelloc"); if (sg != sg->root) { if (pos && (pos[0] == 'b')) pos_flag = LABEL_AT_BOTTOM; else pos_flag = LABEL_AT_TOP; } else { if (pos && (pos[0] == 't')) pos_flag = LABEL_AT_TOP; else pos_flag = LABEL_AT_BOTTOM; } just = agget(sg, "labeljust"); if (just) { if (just[0] == 'l') pos_flag |= LABEL_AT_LEFT; else if (just[0] == 'r') pos_flag |= LABEL_AT_RIGHT; } GD_label_pos(sg) = pos_flag; if (sg == sg->root) return; /* Set border information for cluster labels to allow space */ dimen = GD_label(sg)->dimen; PAD(dimen); PF2P(dimen, dpt); if (!GD_flip(sg->root)) { if (GD_label_pos(sg) & LABEL_AT_TOP) pos_ix = TOP_IX; else pos_ix = BOTTOM_IX; GD_border(sg)[pos_ix] = dpt; } else { /* when rotated, the labels will be restored to TOP or BOTTOM */ if (GD_label_pos(sg) & LABEL_AT_TOP) pos_ix = RIGHT_IX; else pos_ix = LEFT_IX; GD_border(sg)[pos_ix].x = dpt.y; GD_border(sg)[pos_ix].y = dpt.x; } } }
/* * John M. suggests: * You might want to add four more: * * _ohdraw_ (optional head-end arrow for edges) * _ohldraw_ (optional head-end label for edges) * _otdraw_ (optional tail-end arrow for edges) * _otldraw_ (optional tail-end label for edges) * * that would be generated when an additional option is supplied to * dot, etc. and * these would be the arrow/label positions to use if a user want to flip the * direction of an edge (as sometimes is there want). * * N.B. John M. asks: * By the way, I don't know if you ever plan to add other letters for * the xdot spec, but could you reserve "a" and also "A" (for attribute), * "n" and also "N" (for numeric), "w" (for sWitch), "s" (for string) * and "t" (for tooltip) and "x" (for position). We use those letters in * our drawing spec (and also "<" and ">"), so if you start generating * output with them, it could break what we have. */ void extend_attrs(GVJ_t * job, graph_t *g, int s_arrows, int e_arrows) { node_t *n; edge_t *e; attrsym_t *n_draw = NULL; attrsym_t *n_l_draw = NULL; attrsym_t *e_draw = NULL; attrsym_t *h_draw = NULL; attrsym_t *t_draw = NULL; attrsym_t *e_l_draw = NULL; attrsym_t *hl_draw = NULL; attrsym_t *tl_draw = NULL; unsigned char buf0[BUFSIZ]; unsigned char buf1[BUFSIZ]; unsigned char buf2[BUFSIZ]; unsigned char buf3[BUFSIZ]; unsigned char buf4[BUFSIZ]; unsigned char buf5[BUFSIZ]; gvc = job->gvc; agsafeset (g, "xdotversion", XDOTVERSION, ""); if (GD_has_labels(g) & GRAPH_LABEL) g_l_draw = safe_dcl(g, g, "_ldraw_", "", agraphattr); else g_l_draw = NULL; if (GD_n_cluster(g)) g_draw = safe_dcl(g, g, "_draw_", "", agraphattr); else g_draw = NULL; n_draw = safe_dcl(g, g->proto->n, "_draw_", "", agnodeattr); n_l_draw = safe_dcl(g, g->proto->n, "_ldraw_", "", agnodeattr); e_draw = safe_dcl(g, g->proto->e, "_draw_", "", agedgeattr); if (e_arrows) h_draw = safe_dcl(g, g->proto->e, "_hdraw_", "", agedgeattr); if (s_arrows) t_draw = safe_dcl(g, g->proto->e, "_tdraw_", "", agedgeattr); if (GD_has_labels(g) & EDGE_LABEL) e_l_draw = safe_dcl(g, g->proto->e, "_ldraw_", "", agedgeattr); if (GD_has_labels(g) & HEAD_LABEL) hl_draw = safe_dcl(g, g->proto->e, "_hldraw_", "", agedgeattr); if (GD_has_labels(g) & TAIL_LABEL) tl_draw = safe_dcl(g, g->proto->e, "_tldraw_", "", agedgeattr); agxbinit(&xbuf0, BUFSIZ, buf0); agxbinit(&xbuf1, BUFSIZ, buf1); agxbinit(&xbuf2, BUFSIZ, buf2); agxbinit(&xbuf3, BUFSIZ, buf3); agxbinit(&xbuf4, BUFSIZ, buf4); agxbinit(&xbuf5, BUFSIZ, buf5); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (ND_shape(n) && !isInvis(late_string(n, N_style, ""))) { ND_shape(n)->fns->codefn(job, n); agxset(n, n_draw->index, agxbuse(xbufs[EMIT_NDRAW])); agxset(n, n_l_draw->index, agxbuse(xbufs[EMIT_NLABEL])); } if (State < GVSPLINES) continue; for (e = agfstout(g, n); e; e = agnxtout(g, e)) { if (ED_edge_type(e) == IGNORED) continue; if (isInvis(late_string(e, E_style, ""))) continue; if (ED_spl(e) == NULL) continue; emit_edge_graphics (job, e); agxset(e, e_draw->index, agxbuse(xbufs[EMIT_EDRAW])); if (t_draw) agxset(e, t_draw->index, agxbuse(xbufs[EMIT_TDRAW])); if (h_draw) agxset(e, h_draw->index, agxbuse(xbufs[EMIT_HDRAW])); if (e_l_draw) agxset(e, e_l_draw->index,agxbuse(xbufs[EMIT_ELABEL])); if (tl_draw) agxset(e, tl_draw->index, agxbuse(xbufs[EMIT_TLABEL])); if (hl_draw) agxset(e, hl_draw->index, agxbuse(xbufs[EMIT_HLABEL])); } } emit_background(job, g); if (agxblen(xbufs[EMIT_GDRAW])) { if (!g_draw) g_draw = safe_dcl(g, g, "_draw_", "", agraphattr); agxset(g, g_draw->index, agxbuse(xbufs[EMIT_GDRAW])); } if (GD_label(g)) { emit_label(job, EMIT_GLABEL, GD_label(g), (void *) g); agxset(g, g_l_draw->index, agxbuse(xbufs[EMIT_GLABEL])); } emit_clusters(job, g, 0); agxbfree(&xbuf0); agxbfree(&xbuf1); agxbfree(&xbuf2); agxbfree(&xbuf3); agxbfree(&xbuf4); agxbfree(&xbuf5); }
void attach_attrs_and_arrows(graph_t* g, int* sp, int* ep) { int e_arrows; /* graph has edges with end arrows */ int s_arrows; /* graph has edges with start arrows */ int i, j, sides; char buf[BUFSIZ]; /* Used only for small strings */ unsigned char xbuffer[BUFSIZ]; /* Initial buffer for xb */ agxbuf xb; node_t *n; edge_t *e; pointf ptf; int dim3 = (GD_odim(g) >= 3); Agsym_t* bbsym; gv_fixLocale (1); e_arrows = s_arrows = 0; setYInvert(g); agxbinit(&xb, BUFSIZ, xbuffer); safe_dcl(g, AGNODE, "pos", ""); safe_dcl(g, AGNODE, "rects", ""); N_width = safe_dcl(g, AGNODE, "width", ""); N_height = safe_dcl(g, AGNODE, "height", ""); safe_dcl(g, AGEDGE, "pos", ""); if (GD_has_labels(g) & NODE_XLABEL) safe_dcl(g, AGNODE, "xlp", ""); if (GD_has_labels(g) & EDGE_LABEL) safe_dcl(g, AGEDGE, "lp", ""); if (GD_has_labels(g) & EDGE_XLABEL) safe_dcl(g, AGEDGE, "xlp", ""); if (GD_has_labels(g) & HEAD_LABEL) safe_dcl(g, AGEDGE, "head_lp", ""); if (GD_has_labels(g) & TAIL_LABEL) safe_dcl(g, AGEDGE, "tail_lp", ""); if (GD_label(g)) { safe_dcl(g, AGRAPH, "lp", ""); safe_dcl(g, AGRAPH, "lwidth", ""); safe_dcl(g, AGRAPH, "lheight", ""); if (GD_label(g)->text[0]) { ptf = GD_label(g)->pos; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agset(g, "lp", buf); ptf = GD_label(g)->dimen; sprintf(buf, "%.2f", PS2INCH(ptf.x)); agset(g, "lwidth", buf); sprintf(buf, "%.2f", PS2INCH(ptf.y)); agset(g, "lheight", buf); } } bbsym = safe_dcl(g, AGRAPH, "bb", ""); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (dim3) { int k; sprintf(buf, "%.5g,%.5g,%.5g", ND_coord(n).x, YDIR(ND_coord(n).y), POINTS_PER_INCH*(ND_pos(n)[2])); agxbput (&xb, buf); for (k = 3; k < GD_odim(g); k++) { sprintf(buf, ",%.5g", POINTS_PER_INCH*(ND_pos(n)[k])); agxbput (&xb, buf); } agset(n, "pos", agxbuse(&xb)); } else { sprintf(buf, "%.5g,%.5g", ND_coord(n).x, YDIR(ND_coord(n).y)); agset(n, "pos", buf); } sprintf(buf, "%.5g", PS2INCH(ND_ht(n))); agxset(n, N_height, buf); sprintf(buf, "%.5g", PS2INCH(ND_lw(n) + ND_rw(n))); agxset(n, N_width, buf); if (ND_xlabel(n) && ND_xlabel(n)->set) { ptf = ND_xlabel(n)->pos; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agset(n, "xlp", buf); } if (strcmp(ND_shape(n)->name, "record") == 0) { set_record_rects(n, ND_shape_info(n), &xb); agxbpop(&xb); /* get rid of last space */ agset(n, "rects", agxbuse(&xb)); } else { polygon_t *poly; int i; if (N_vertices && isPolygon(n)) { poly = (polygon_t *) ND_shape_info(n); sides = poly->sides; if (sides < 3) { char *p = agget(n, "samplepoints"); if (p) sides = atoi(p); else sides = 8; if (sides < 3) sides = 8; } for (i = 0; i < sides; i++) { if (i > 0) agxbputc(&xb, ' '); if (poly->sides >= 3) sprintf(buf, "%.5g %.5g", PS2INCH(poly->vertices[i].x), YFDIR(PS2INCH(poly->vertices[i].y))); else sprintf(buf, "%.5g %.5g", ND_width(n) / 2.0 * cos(i / (double) sides * M_PI * 2.0), YFDIR(ND_height(n) / 2.0 * sin(i / (double) sides * M_PI * 2.0))); agxbput(&xb, buf); } agxset(n, N_vertices, agxbuse(&xb)); } } if (State >= GVSPLINES) { for (e = agfstout(g, n); e; e = agnxtout(g, e)) { if (ED_edge_type(e) == IGNORED) continue; if (ED_spl(e) == NULL) continue; /* reported in postproc */ for (i = 0; i < ED_spl(e)->size; i++) { if (i > 0) agxbputc(&xb, ';'); if (ED_spl(e)->list[i].sflag) { s_arrows = 1; sprintf(buf, "s,%.5g,%.5g ", ED_spl(e)->list[i].sp.x, YDIR(ED_spl(e)->list[i].sp.y)); agxbput(&xb, buf); } if (ED_spl(e)->list[i].eflag) { e_arrows = 1; sprintf(buf, "e,%.5g,%.5g ", ED_spl(e)->list[i].ep.x, YDIR(ED_spl(e)->list[i].ep.y)); agxbput(&xb, buf); } for (j = 0; j < ED_spl(e)->list[i].size; j++) { if (j > 0) agxbputc(&xb, ' '); ptf = ED_spl(e)->list[i].list[j]; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agxbput(&xb, buf); } } agset(e, "pos", agxbuse(&xb)); if (ED_label(e)) { ptf = ED_label(e)->pos; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agset(e, "lp", buf); } if (ED_xlabel(e) && ED_xlabel(e)->set) { ptf = ED_xlabel(e)->pos; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agset(e, "xlp", buf); } if (ED_head_label(e)) { ptf = ED_head_label(e)->pos; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agset(e, "head_lp", buf); } if (ED_tail_label(e)) { ptf = ED_tail_label(e)->pos; sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y)); agset(e, "tail_lp", buf); } } } } rec_attach_bb(g, bbsym); agxbfree(&xb); if (HAS_CLUST_EDGE(g)) undoClusterEdges(g); *sp = s_arrows; *ep = e_arrows; gv_fixLocale (0); }
/* 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; }