/* 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]); }
/* 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; #ifdef OLD int minx, maxx; #endif point p, d; if ((g != g->root) && (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; #ifdef OLD minx = p.x - d.x / 2; if (GD_bb(g).LL.x > minx) GD_bb(g).LL.x = minx; if (GD_bb(g->root).LL.x > minx) GD_bb(g->root).LL.x = minx; #endif } else if (GD_label_pos(g) & LABEL_AT_LEFT) { p.x = GD_bb(g).LL.x + d.x / 2; #ifdef OLD maxx = p.x + d.x / 2; if (GD_bb(g).UR.x < maxx) GD_bb(g).UR.x = maxx; if (GD_bb(g->root).UR.x < maxx) GD_bb(g->root).UR.x = maxx; #endif } else { p.x = (GD_bb(g).LL.x + GD_bb(g).UR.x) / 2; #ifdef OLD maxx = p.x + d.x / 2; minx = p.x - d.x / 2; if (GD_bb(g).UR.x < maxx) GD_bb(g).UR.x = maxx; if (GD_bb(g).LL.x > minx) GD_bb(g).LL.x = minx; if (GD_bb(g->root).UR.x < maxx) GD_bb(g->root).UR.x = maxx; if (GD_bb(g->root).LL.x > minx) GD_bb(g->root).LL.x = minx; #endif } GD_label(g)->p = p; GD_label(g)->set = TRUE; } for (c = 1; c <= GD_n_cluster(g); c++) place_graph_label(GD_clust(g)[c]); }
/* 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; } } }
/* 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; } } }
/* place_flip_graph_label: * Put cluster labels recursively in the flip case. */ static void place_flip_graph_label(graph_t * g) { int c; point p, d; #ifdef OLD int maxx, minx; int maxy, miny; pointf dimen; #endif if ((g != g->root) && (GD_label(g)) && !GD_label(g)->set) { if (GD_label_pos(g) & LABEL_AT_TOP) { d = GD_border(g)[RIGHT_IX]; p.x = GD_bb(g).UR.x - d.x / 2; #ifdef OLD maxx = GD_bb(g).UR.x + d.y; GD_bb(g).UR.x = maxx; if (GD_bb(g->root).UR.x < maxx) GD_bb(g->root).UR.x = maxx; #endif } else { d = GD_border(g)[LEFT_IX]; p.x = GD_bb(g).LL.x + d.x / 2; #ifdef OLD minx = GD_bb(g).LL.x - d.y; GD_bb(g).LL.x = minx; if (GD_bb(g->root).LL.x > minx) GD_bb(g->root).LL.x = minx; #endif } if (GD_label_pos(g) & LABEL_AT_RIGHT) { p.y = GD_bb(g).LL.y + d.y / 2; #ifdef OLD maxy = p.y + d.x / 2; if (GD_bb(g->root).UR.y < maxy) GD_bb(g->root).UR.y = maxy; #endif } else if (GD_label_pos(g) & LABEL_AT_LEFT) { p.y = GD_bb(g).UR.y - d.y / 2; #ifdef OLD miny = p.y - d.x / 2; if (GD_bb(g->root).LL.y > miny) GD_bb(g->root).LL.y = miny; #endif } else { p.y = (GD_bb(g).LL.y + GD_bb(g).UR.y) / 2; #ifdef OLD maxy = p.y + d.x / 2; miny = p.y - d.x / 2; #endif } GD_label(g)->p = p; GD_label(g)->set = TRUE; } for (c = 1; c <= GD_n_cluster(g); c++) place_flip_graph_label(GD_clust(g)[c]); }
/* finalCC: * Set graph bounding box given list of connected * components, each with its bounding box set. * If c_cnt > 1, then pts != NULL and gives translations for components. * Add margin about whole graph unless isRoot is true. * Reposition nodes based on final position of * node's connected component. * Also, entire layout is translated to origin. */ static void finalCC(graph_t * g, int c_cnt, graph_t ** cc, point * pts, graph_t * rg, layout_info* infop) { attrsym_t * G_width = infop->G_width; attrsym_t * G_height = infop->G_height; graph_t *cg; box b, bb; boxf bbf; point pt; int margin; graph_t **cp = cc; point *pp = pts; int isRoot = (rg == infop->rootg); int isEmpty = 0; /* compute graph bounding box in points */ if (c_cnt) { cg = *cp++; BF2B(GD_bb(cg), bb); if (c_cnt > 1) { pt = *pp++; bb.LL.x += pt.x; bb.LL.y += pt.y; bb.UR.x += pt.x; bb.UR.y += pt.y; while ((cg = *cp++)) { BF2B(GD_bb(cg), b); pt = *pp++; b.LL.x += pt.x; b.LL.y += pt.y; b.UR.x += pt.x; b.UR.y += pt.y; bb.LL.x = MIN(bb.LL.x, b.LL.x); bb.LL.y = MIN(bb.LL.y, b.LL.y); bb.UR.x = MAX(bb.UR.x, b.UR.x); bb.UR.y = MAX(bb.UR.y, b.UR.y); } } } else { /* empty graph */ bb.LL.x = 0; bb.LL.y = 0; bb.UR.x = late_int(rg, G_width, POINTS(DEFAULT_NODEWIDTH), 3); bb.UR.y = late_int(rg, G_height, POINTS(DEFAULT_NODEHEIGHT), 3); isEmpty = 1; } if (GD_label(rg)) { point p; int d; isEmpty = 0; PF2P(GD_label(rg)->dimen, p); d = p.x - (bb.UR.x - bb.LL.x); if (d > 0) { /* height of label added below */ d /= 2; bb.LL.x -= d; bb.UR.x += d; } } if (isRoot || isEmpty) margin = 0; else margin = late_int (g, G_margin, CL_OFFSET, 0); pt.x = -bb.LL.x + margin; pt.y = -bb.LL.y + margin + GD_border(rg)[BOTTOM_IX].y; bb.LL.x = 0; bb.LL.y = 0; bb.UR.x += pt.x + margin; bb.UR.y += pt.y + margin + GD_border(rg)[TOP_IX].y; /* translate nodes */ if (c_cnt) { cp = cc; pp = pts; while ((cg = *cp++)) { point p; node_t *n; pointf del; if (pp) { p = *pp++; p.x += pt.x; p.y += pt.y; } else { p = pt; } del.x = PS2INCH(p.x); del.y = PS2INCH(p.y); for (n = agfstnode(cg); n; n = agnxtnode(cg, n)) { ND_pos(n)[0] += del.x; ND_pos(n)[1] += del.y; } } } bbf.LL.x = PS2INCH(bb.LL.x); bbf.LL.y = PS2INCH(bb.LL.y); bbf.UR.x = PS2INCH(bb.UR.x); bbf.UR.y = PS2INCH(bb.UR.y); BB(g) = bbf; }