|
Graphviz
2.29.20120524.0446
|
00001 /* $Id$ $Revision$ */ 00002 /* vim:set shiftwidth=4 ts=8: */ 00003 00004 /************************************************************************* 00005 * Copyright (c) 2011 AT&T Intellectual Property 00006 * All rights reserved. This program and the accompanying materials 00007 * are made available under the terms of the Eclipse Public License v1.0 00008 * which accompanies this distribution, and is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * 00011 * Contributors: See CVS logs. Details at http://www.graphviz.org/ 00012 *************************************************************************/ 00013 00014 00015 #include "render.h" 00016 #include "xlabels.h" 00017 00018 static int Rankdir; 00019 static boolean Flip; 00020 static pointf Offset; 00021 00022 static void place_flip_graph_label(graph_t * g); 00023 00024 #define M1 \ 00025 "/pathbox {\n\ 00026 /Y exch %.5g sub def\n\ 00027 /X exch %.5g sub def\n\ 00028 /y exch %.5g sub def\n\ 00029 /x exch %.5g sub def\n\ 00030 newpath x y moveto\n\ 00031 X y lineto\n\ 00032 X Y lineto\n\ 00033 x Y lineto\n\ 00034 closepath stroke\n \ 00035 } def\n\ 00036 /dbgstart { gsave %.5g %.5g translate } def\n\ 00037 /arrowlength 10 def\n\ 00038 /arrowwidth arrowlength 2 div def\n\ 00039 /arrowhead {\n\ 00040 gsave\n\ 00041 rotate\n\ 00042 currentpoint\n\ 00043 newpath\n\ 00044 moveto\n\ 00045 arrowlength arrowwidth 2 div rlineto\n\ 00046 0 arrowwidth neg rlineto\n\ 00047 closepath fill\n\ 00048 grestore\n\ 00049 } bind def\n\ 00050 /makearrow {\n\ 00051 currentpoint exch pop sub exch currentpoint pop sub atan\n\ 00052 arrowhead\n\ 00053 } bind def\n\ 00054 /point {\ 00055 newpath\ 00056 2 0 360 arc fill\ 00057 } def\ 00058 /makevec {\n\ 00059 /Y exch def\n\ 00060 /X exch def\n\ 00061 /y exch def\n\ 00062 /x exch def\n\ 00063 newpath x y moveto\n\ 00064 X Y lineto stroke\n\ 00065 X Y moveto\n\ 00066 x y makearrow\n\ 00067 } def\n" 00068 00069 #define M2 \ 00070 "/pathbox {\n\ 00071 /X exch neg %.5g sub def\n\ 00072 /Y exch %.5g sub def\n\ 00073 /x exch neg %.5g sub def\n\ 00074 /y exch %.5g sub def\n\ 00075 newpath x y moveto\n\ 00076 X y lineto\n\ 00077 X Y lineto\n\ 00078 x Y lineto\n\ 00079 closepath stroke\n\ 00080 } def\n" 00081 00082 static pointf map_point(pointf p) 00083 { 00084 p = ccwrotatepf(p, Rankdir * 90); 00085 p.x -= Offset.x; 00086 p.y -= Offset.y; 00087 return p; 00088 } 00089 00090 static void map_edge(edge_t * e) 00091 { 00092 int j, k; 00093 bezier bz; 00094 00095 if (ED_spl(e) == NULL) { 00096 if ((Concentrate == FALSE) && (ED_edge_type(e) != IGNORED)) 00097 agerr(AGERR, "lost %s %s edge\n", agnameof(agtail(e)), 00098 agnameof(aghead(e))); 00099 return; 00100 } 00101 for (j = 0; j < ED_spl(e)->size; j++) { 00102 bz = ED_spl(e)->list[j]; 00103 for (k = 0; k < bz.size; k++) 00104 bz.list[k] = map_point(bz.list[k]); 00105 if (bz.sflag) 00106 ED_spl(e)->list[j].sp = map_point(ED_spl(e)->list[j].sp); 00107 if (bz.eflag) 00108 ED_spl(e)->list[j].ep = map_point(ED_spl(e)->list[j].ep); 00109 } 00110 if (ED_label(e)) 00111 ED_label(e)->pos = map_point(ED_label(e)->pos); 00112 if (ED_xlabel(e)) 00113 ED_xlabel(e)->pos = map_point(ED_xlabel(e)->pos); 00114 /* vladimir */ 00115 if (ED_head_label(e)) 00116 ED_head_label(e)->pos = map_point(ED_head_label(e)->pos); 00117 if (ED_tail_label(e)) 00118 ED_tail_label(e)->pos = map_point(ED_tail_label(e)->pos); 00119 } 00120 00121 void translate_bb(graph_t * g, int rankdir) 00122 { 00123 int c; 00124 boxf bb, new_bb; 00125 00126 bb = GD_bb(g); 00127 if (rankdir == RANKDIR_LR || rankdir == RANKDIR_BT) { 00128 new_bb.LL = map_point(pointfof(bb.LL.x, bb.UR.y)); 00129 new_bb.UR = map_point(pointfof(bb.UR.x, bb.LL.y)); 00130 } else { 00131 new_bb.LL = map_point(pointfof(bb.LL.x, bb.LL.y)); 00132 new_bb.UR = map_point(pointfof(bb.UR.x, bb.UR.y)); 00133 } 00134 GD_bb(g) = new_bb; 00135 if (GD_label(g)) { 00136 GD_label(g)->pos = map_point(GD_label(g)->pos); 00137 } 00138 for (c = 1; c <= GD_n_cluster(g); c++) 00139 translate_bb(GD_clust(g)[c], rankdir); 00140 } 00141 00142 /* translate_drawing: 00143 * Translate and/or rotate nodes, spline points, and bbox info if 00144 * necessary. Also, if Rankdir (!= RANKDIR_BT), reset ND_lw, ND_rw, 00145 * and ND_ht to correct value. 00146 */ 00147 static void translate_drawing(graph_t * g) 00148 { 00149 node_t *v; 00150 edge_t *e; 00151 int shift = (Offset.x || Offset.y); 00152 00153 if (!shift && !Rankdir) 00154 return; 00155 for (v = agfstnode(g); v; v = agnxtnode(g, v)) { 00156 if (Rankdir) 00157 gv_nodesize(v, FALSE); 00158 ND_coord(v) = map_point(ND_coord(v)); 00159 if (ND_xlabel(v)) 00160 ND_xlabel(v)->pos = map_point(ND_xlabel(v)->pos); 00161 if (State == GVSPLINES) 00162 for (e = agfstout(g, v); e; e = agnxtout(g, e)) 00163 map_edge(e); 00164 } 00165 translate_bb(g, GD_rankdir(g)); 00166 } 00167 00168 /* place_root_label: 00169 * Set position of root graph label. 00170 * Note that at this point, after translate_drawing, a 00171 * flipped drawing has been transposed, so we don't have 00172 * to worry about switching x and y. 00173 */ 00174 static void place_root_label(graph_t * g, pointf d) 00175 { 00176 pointf p; 00177 00178 if (GD_label_pos(g) & LABEL_AT_RIGHT) { 00179 p.x = GD_bb(g).UR.x - d.x / 2; 00180 } else if (GD_label_pos(g) & LABEL_AT_LEFT) { 00181 p.x = GD_bb(g).LL.x + d.x / 2; 00182 } else { 00183 p.x = (GD_bb(g).LL.x + GD_bb(g).UR.x) / 2; 00184 } 00185 00186 if (GD_label_pos(g) & LABEL_AT_TOP) { 00187 p.y = GD_bb(g).UR.y - d.y / 2; 00188 } else { 00189 p.y = GD_bb(g).LL.y + d.y / 2; 00190 } 00191 00192 GD_label(g)->pos = p; 00193 GD_label(g)->set = TRUE; 00194 } 00195 00196 /* centerPt: 00197 * Calculate the center point of the xlabel. The returned positions for 00198 * xlabels always correspond to the lower left corner. 00199 */ 00200 static pointf 00201 centerPt (xlabel_t* xlp) { 00202 pointf p; 00203 00204 p = xlp->pos; 00205 p.x += (xlp->sz.x)/2.0; 00206 p.y += (xlp->sz.y)/2.0; 00207 00208 return p; 00209 } 00210 00211 static int 00212 printData (object_t* objs, int n_objs, xlabel_t* lbls, int n_lbls, 00213 label_params_t* params) { 00214 int i; 00215 xlabel_t* xp; 00216 fprintf (stderr, "%d objs %d xlabels force=%d bb=(%.02f,%.02f) (%.02f,%.02f)\n", 00217 n_objs, n_lbls, params->force, params->bb.LL.x, params->bb.LL.y, 00218 params->bb.UR.x, params->bb.UR.y); 00219 if (Verbose < 2) return 0; 00220 fprintf(stderr, "objects\n"); 00221 for (i = 0; i < n_objs; i++) { 00222 xp = objs->lbl; 00223 fprintf (stderr, " [%d] (%.02f,%.02f) (%.02f,%.02f) %p \"%s\"\n", 00224 i, objs->pos.x,objs->pos.y,objs->sz.x,objs->sz.y, objs->lbl, 00225 (xp?((textlabel_t*)(xp->lbl))->text:"")); 00226 objs++; 00227 } 00228 fprintf(stderr, "xlabels\n"); 00229 for (i = 0; i < n_lbls; i++) { 00230 fprintf (stderr, " [%d] %p set %d (%.02f,%.02f) (%.02f,%.02f) %s\n", 00231 i, lbls, lbls->set, lbls->pos.x,lbls->pos.y, lbls->sz.x,lbls->sz.y, ((textlabel_t*)lbls->lbl)->text); 00232 lbls++; 00233 } 00234 return 0; 00235 } 00236 00237 static pointf 00238 edgeTailpoint (Agedge_t* e) 00239 { 00240 splines *spl; 00241 bezier *bez; 00242 00243 if ((spl = getsplinepoints(e)) == NULL) { 00244 pointf p; 00245 p.x = p.y = 0; 00246 return p; 00247 } 00248 bez = &spl->list[0]; 00249 if (bez->sflag) { 00250 return bez->sp; 00251 } else { 00252 return bez->list[0]; 00253 } 00254 } 00255 00256 static pointf 00257 edgeHeadpoint (Agedge_t* e) 00258 { 00259 splines *spl; 00260 bezier *bez; 00261 00262 if ((spl = getsplinepoints(e)) == NULL) { 00263 pointf p; 00264 p.x = p.y = 0; 00265 return p; 00266 } 00267 bez = &spl->list[spl->size - 1]; 00268 if (bez->eflag) { 00269 return bez->ep; 00270 } else { 00271 return bez->list[bez->size - 1]; 00272 } 00273 } 00274 00275 /* adjustBB: 00276 */ 00277 static boxf 00278 adjustBB (object_t* objp, boxf bb) 00279 { 00280 pointf ur; 00281 00282 /* Adjust bounding box */ 00283 bb.LL.x = MIN(bb.LL.x, objp->pos.x); 00284 bb.LL.y = MIN(bb.LL.y, objp->pos.y); 00285 ur.x = objp->pos.x + objp->sz.x; 00286 ur.y = objp->pos.y + objp->sz.y; 00287 bb.UR.x = MAX(bb.UR.x, ur.x); 00288 bb.UR.y = MAX(bb.UR.y, ur.y); 00289 00290 return bb; 00291 } 00292 00293 /* addXLabel: 00294 * Set up xlabel_t object and connect with related object. 00295 * If initObj is set, initialize the object. 00296 */ 00297 static void 00298 addXLabel (textlabel_t* lp, object_t* objp, xlabel_t* xlp, int initObj, pointf pos) 00299 { 00300 if (initObj) { 00301 objp->sz.x = 0; 00302 objp->sz.y = 0; 00303 objp->pos = pos; 00304 } 00305 00306 if (Flip) { 00307 xlp->sz.x = lp->dimen.y; 00308 xlp->sz.y = lp->dimen.x; 00309 } 00310 else { 00311 xlp->sz = lp->dimen; 00312 } 00313 xlp->lbl = lp; 00314 xlp->set = 0; 00315 objp->lbl = xlp; 00316 } 00317 00318 /* addLabelObj: 00319 * Set up obstacle object based on set external label. 00320 * This includes dot edge labels. 00321 * Use label information to determine size and position of object. 00322 * Then adjust given bounding box bb to include label and return new bb. 00323 */ 00324 static boxf 00325 addLabelObj (textlabel_t* lp, object_t* objp, boxf bb) 00326 { 00327 if (Flip) { 00328 objp->sz.x = lp->dimen.y; 00329 objp->sz.y = lp->dimen.x; 00330 } 00331 else { 00332 objp->sz.x = lp->dimen.x; 00333 objp->sz.y = lp->dimen.y; 00334 } 00335 objp->pos = lp->pos; 00336 objp->pos.x -= (objp->sz.x) / 2.0; 00337 objp->pos.y -= (objp->sz.y) / 2.0; 00338 00339 return adjustBB(objp, bb); 00340 } 00341 00342 /* addNodeOjb: 00343 * Set up obstacle object based on a node. 00344 * Use node information to determine size and position of object. 00345 * Then adjust given bounding box bb to include label and return new bb. 00346 */ 00347 static boxf 00348 addNodeObj (node_t* np, object_t* objp, boxf bb) 00349 { 00350 if (Flip) { 00351 objp->sz.x = INCH2PS(ND_height(np)); 00352 objp->sz.y = INCH2PS(ND_width(np)); 00353 } 00354 else { 00355 objp->sz.x = INCH2PS(ND_width(np)); 00356 objp->sz.y = INCH2PS(ND_height(np)); 00357 } 00358 objp->pos = ND_coord(np); 00359 objp->pos.x -= (objp->sz.x) / 2.0; 00360 objp->pos.y -= (objp->sz.y) / 2.0; 00361 00362 return adjustBB(objp, bb); 00363 } 00364 00365 typedef struct { 00366 boxf bb; 00367 object_t* objp; 00368 } cinfo_t; 00369 00370 static cinfo_t 00371 addClusterObj (Agraph_t* g, cinfo_t info) 00372 { 00373 int c; 00374 00375 for (c = 1; c <= GD_n_cluster(g); c++) 00376 info = addClusterObj (GD_clust(g)[c], info); 00377 if ((g != agroot(g)) && (GD_label(g)) && GD_label(g)->set) { 00378 object_t* objp = info.objp; 00379 info.bb = addLabelObj (GD_label(g), objp, info.bb); 00380 info.objp++; 00381 } 00382 00383 return info; 00384 } 00385 00386 static int 00387 countClusterLabels (Agraph_t* g) 00388 { 00389 int c, i = 0; 00390 if ((g != agroot(g)) && (GD_label(g)) && GD_label(g)->set) 00391 i++; 00392 for (c = 1; c <= GD_n_cluster(g); c++) 00393 i += countClusterLabels (GD_clust(g)[c]); 00394 return i; 00395 } 00396 00397 /* addXLabels: 00398 * Position xlabels and any unpositioned edge labels using 00399 * a map placement algorithm to avoid overlap. 00400 * 00401 * TODO: interaction with spline=ortho 00402 */ 00403 static void addXLabels(Agraph_t * gp) 00404 { 00405 Agnode_t *np; 00406 Agedge_t *ep; 00407 int cnt, i, n_objs, n_lbls; 00408 int n_nlbls = 0; /* # of unset node xlabels */ 00409 int n_elbls = 0; /* # of unset edge labels or xlabels */ 00410 int n_set_lbls = 0; /* # of set xlabels and edge labels */ 00411 int n_clbls = 0; /* # of set cluster labels */ 00412 boxf bb; 00413 pointf ur; 00414 textlabel_t* lp; 00415 label_params_t params; 00416 object_t* objs; 00417 xlabel_t* lbls; 00418 object_t* objp; 00419 xlabel_t* xlp; 00420 Agsym_t* force; 00421 int et = EDGE_TYPE(gp); 00422 00423 if (!(GD_has_labels(gp) & NODE_XLABEL) && 00424 !(GD_has_labels(gp) & EDGE_XLABEL) && 00425 !(GD_has_labels(gp) & TAIL_LABEL) && 00426 !(GD_has_labels(gp) & HEAD_LABEL) && 00427 (!(GD_has_labels(gp) & EDGE_LABEL) || EdgeLabelsDone)) 00428 return; 00429 00430 for (np = agfstnode(gp); np; np = agnxtnode(gp, np)) { 00431 if (ND_xlabel(np)) { 00432 if (ND_xlabel(np)->set) 00433 n_set_lbls++; 00434 else 00435 n_nlbls++; 00436 } 00437 for (ep = agfstout(gp, np); ep; ep = agnxtout(gp, ep)) { 00438 if (ED_xlabel(ep)) { 00439 if (ED_xlabel(ep)->set) 00440 n_set_lbls++; 00441 else if (et != ET_NONE) 00442 n_elbls++; 00443 } 00444 if (ED_head_label(ep)) { 00445 if (ED_head_label(ep)->set) 00446 n_set_lbls++; 00447 else if (et != ET_NONE) 00448 n_elbls++; 00449 } 00450 if (ED_tail_label(ep)) { 00451 if (ED_tail_label(ep)->set) 00452 n_set_lbls++; 00453 else if (et != ET_NONE) 00454 n_elbls++; 00455 } 00456 if (ED_label(ep)) { 00457 if (ED_label(ep)->set) 00458 n_set_lbls++; 00459 else if (et != ET_NONE) 00460 n_elbls++; 00461 } 00462 } 00463 } 00464 if (GD_has_labels(gp) & GRAPH_LABEL) 00465 n_clbls = countClusterLabels (gp); 00466 00467 /* A label for each unpositioned external label */ 00468 n_lbls = n_nlbls + n_elbls; 00469 if (n_lbls == 0) return; 00470 00471 /* An object for each node, each positioned external label, any cluster label, 00472 * and all unset edge labels and xlabels. 00473 */ 00474 n_objs = agnnodes(gp) + n_set_lbls + n_clbls + n_elbls; 00475 objp = objs = N_NEW(n_objs, object_t); 00476 xlp = lbls = N_NEW(n_lbls, xlabel_t); 00477 bb.LL = pointfof(INT_MAX, INT_MAX); 00478 bb.UR = pointfof(-INT_MAX, -INT_MAX); 00479 00480 for (np = agfstnode(gp); np; np = agnxtnode(gp, np)) { 00481 00482 bb = addNodeObj (np, objp, bb); 00483 if ((lp = ND_xlabel(np))) { 00484 if (lp->set) { 00485 objp++; 00486 bb = addLabelObj (lp, objp, bb); 00487 } 00488 else { 00489 addXLabel (lp, objp, xlp, 0, ur); 00490 xlp++; 00491 } 00492 } 00493 objp++; 00494 for (ep = agfstout(gp, np); ep; ep = agnxtout(gp, ep)) { 00495 if ((lp = ED_label(ep))) { 00496 if (lp->set) { 00497 bb = addLabelObj (lp, objp, bb); 00498 } 00499 else if (et != ET_NONE) { 00500 addXLabel (lp, objp, xlp, 1, edgeMidpoint(gp, ep)); 00501 xlp++; 00502 } 00503 objp++; 00504 } 00505 if ((lp = ED_tail_label(ep))) { 00506 if (lp->set) { 00507 bb = addLabelObj (lp, objp, bb); 00508 } 00509 else if (et != ET_NONE) { 00510 addXLabel (lp, objp, xlp, 1, edgeTailpoint(ep)); 00511 xlp++; 00512 } 00513 objp++; 00514 } 00515 if ((lp = ED_head_label(ep))) { 00516 if (lp->set) { 00517 bb = addLabelObj (lp, objp, bb); 00518 } 00519 else if (et != ET_NONE) { 00520 addXLabel (lp, objp, xlp, 1, edgeHeadpoint(ep)); 00521 xlp++; 00522 } 00523 objp++; 00524 } 00525 if ((lp = ED_xlabel(ep))) { 00526 if (lp->set) { 00527 bb = addLabelObj (lp, objp, bb); 00528 } 00529 else if (et != ET_NONE) { 00530 addXLabel (lp, objp, xlp, 1, edgeMidpoint(gp, ep)); 00531 xlp++; 00532 } 00533 objp++; 00534 } 00535 } 00536 } 00537 if (n_clbls) { 00538 cinfo_t info; 00539 info.bb = bb; 00540 info.objp = objp; 00541 info = addClusterObj (gp, info); 00542 bb = info.bb; 00543 } 00544 00545 force = agfindgraphattr(gp, "forcelabels"); 00546 00547 params.force = late_bool(gp, force, TRUE); 00548 params.bb = bb; 00549 placeLabels(objs, n_objs, lbls, n_lbls, ¶ms); 00550 if (Verbose) 00551 printData(objs, n_objs, lbls, n_lbls, ¶ms); 00552 00553 xlp = lbls; 00554 cnt = 0; 00555 for (i = 0; i < n_lbls; i++) { 00556 if (xlp->set) { 00557 cnt++; 00558 lp = (textlabel_t *) (xlp->lbl); 00559 lp->set = 1; 00560 lp->pos = centerPt(xlp); 00561 updateBB (gp, lp); 00562 } 00563 xlp++; 00564 } 00565 if (Verbose) 00566 fprintf (stderr, "%d out of %d labels positioned.\n", cnt, n_lbls); 00567 else if (cnt != n_lbls) 00568 agerr(AGWARN, "%d out of %d exterior labels positioned.\n", cnt, n_lbls); 00569 free(objs); 00570 free(lbls); 00571 } 00572 00573 /* dotneato_postprocess: 00574 * Set graph and cluster label positions. 00575 * Add space for root graph label and translate graph accordingly. 00576 * Set final nodesize using ns. 00577 * Assumes the boxes of all clusters have been computed. 00578 * When done, the bounding box of g has LL at origin. 00579 */ 00580 void gv_postprocess(Agraph_t * g, int allowTranslation) 00581 { 00582 double diff; 00583 pointf dimen = { 0., 0. }; 00584 00585 00586 Rankdir = GD_rankdir(g); 00587 Flip = GD_flip(g); 00588 /* Handle cluster labels */ 00589 if (Flip) 00590 place_flip_graph_label(g); 00591 else 00592 place_graph_label(g); 00593 00594 /* Everything has been placed except the root graph label, if any. 00595 * The graph positions have not yet been rotated back if necessary. 00596 */ 00597 addXLabels(g); 00598 00599 /* Add space for graph label if necessary */ 00600 if (GD_label(g) && !GD_label(g)->set) { 00601 dimen = GD_label(g)->dimen; 00602 PAD(dimen); 00603 if (Flip) { 00604 if (GD_label_pos(g) & LABEL_AT_TOP) { 00605 GD_bb(g).UR.x += dimen.y; 00606 } else { 00607 GD_bb(g).LL.x -= dimen.y; 00608 } 00609 00610 if (dimen.x > (GD_bb(g).UR.y - GD_bb(g).LL.y)) { 00611 diff = dimen.x - (GD_bb(g).UR.y - GD_bb(g).LL.y); 00612 diff = diff / 2.; 00613 GD_bb(g).LL.y -= diff; 00614 GD_bb(g).UR.y += diff; 00615 } 00616 } else { 00617 if (GD_label_pos(g) & LABEL_AT_TOP) { 00618 if (Rankdir == RANKDIR_TB) 00619 GD_bb(g).UR.y += dimen.y; 00620 else 00621 GD_bb(g).LL.y -= dimen.y; 00622 } else { 00623 if (Rankdir == RANKDIR_TB) 00624 GD_bb(g).LL.y -= dimen.y; 00625 else 00626 GD_bb(g).UR.y += dimen.y; 00627 } 00628 00629 if (dimen.x > (GD_bb(g).UR.x - GD_bb(g).LL.x)) { 00630 diff = dimen.x - (GD_bb(g).UR.x - GD_bb(g).LL.x); 00631 diff = diff / 2.; 00632 GD_bb(g).LL.x -= diff; 00633 GD_bb(g).UR.x += diff; 00634 } 00635 } 00636 } 00637 if (allowTranslation) { 00638 switch (Rankdir) { 00639 case RANKDIR_TB: 00640 Offset = GD_bb(g).LL; 00641 break; 00642 case RANKDIR_LR: 00643 Offset = pointfof(-GD_bb(g).UR.y, GD_bb(g).LL.x); 00644 break; 00645 case RANKDIR_BT: 00646 Offset = pointfof(GD_bb(g).LL.x, -GD_bb(g).UR.y); 00647 break; 00648 case RANKDIR_RL: 00649 Offset = pointfof(GD_bb(g).LL.y, GD_bb(g).LL.x); 00650 break; 00651 } 00652 translate_drawing(g); 00653 } 00654 if (GD_label(g) && !GD_label(g)->set) 00655 place_root_label(g, dimen); 00656 00657 if (Show_boxes) { 00658 char buf[BUFSIZ]; 00659 if (Flip) 00660 sprintf(buf, M2, Offset.x, Offset.y, Offset.x, Offset.y); 00661 else 00662 sprintf(buf, M1, Offset.y, Offset.x, Offset.y, Offset.x, 00663 -Offset.x, -Offset.y); 00664 Show_boxes[0] = strdup(buf); 00665 } 00666 } 00667 00668 void dotneato_postprocess(Agraph_t * g) 00669 { 00670 gv_postprocess(g, 1); 00671 } 00672 00673 /* place_flip_graph_label: 00674 * Put cluster labels recursively in the flip case. 00675 */ 00676 static void place_flip_graph_label(graph_t * g) 00677 { 00678 int c; 00679 pointf p, d; 00680 00681 if ((g != agroot(g)) && (GD_label(g)) && !GD_label(g)->set) { 00682 if (GD_label_pos(g) & LABEL_AT_TOP) { 00683 d = GD_border(g)[RIGHT_IX]; 00684 p.x = GD_bb(g).UR.x - d.x / 2; 00685 } else { 00686 d = GD_border(g)[LEFT_IX]; 00687 p.x = GD_bb(g).LL.x + d.x / 2; 00688 } 00689 00690 if (GD_label_pos(g) & LABEL_AT_RIGHT) { 00691 p.y = GD_bb(g).LL.y + d.y / 2; 00692 } else if (GD_label_pos(g) & LABEL_AT_LEFT) { 00693 p.y = GD_bb(g).UR.y - d.y / 2; 00694 } else { 00695 p.y = (GD_bb(g).LL.y + GD_bb(g).UR.y) / 2; 00696 } 00697 GD_label(g)->pos = p; 00698 GD_label(g)->set = TRUE; 00699 } 00700 00701 for (c = 1; c <= GD_n_cluster(g); c++) 00702 place_flip_graph_label(GD_clust(g)[c]); 00703 } 00704 00705 /* place_graph_label: 00706 * Put cluster labels recursively in the non-flip case. 00707 * The adjustments to the bounding boxes should no longer 00708 * be necessary, since we now guarantee the label fits in 00709 * the cluster. 00710 */ 00711 void place_graph_label(graph_t * g) 00712 { 00713 int c; 00714 pointf p, d; 00715 00716 if ((g != agroot(g)) && (GD_label(g)) && !GD_label(g)->set) { 00717 if (GD_label_pos(g) & LABEL_AT_TOP) { 00718 d = GD_border(g)[TOP_IX]; 00719 p.y = GD_bb(g).UR.y - d.y / 2; 00720 } else { 00721 d = GD_border(g)[BOTTOM_IX]; 00722 p.y = GD_bb(g).LL.y + d.y / 2; 00723 } 00724 00725 if (GD_label_pos(g) & LABEL_AT_RIGHT) { 00726 p.x = GD_bb(g).UR.x - d.x / 2; 00727 } else if (GD_label_pos(g) & LABEL_AT_LEFT) { 00728 p.x = GD_bb(g).LL.x + d.x / 2; 00729 } else { 00730 p.x = (GD_bb(g).LL.x + GD_bb(g).UR.x) / 2; 00731 } 00732 GD_label(g)->pos = p; 00733 GD_label(g)->set = TRUE; 00734 } 00735 00736 for (c = 1; c <= GD_n_cluster(g); c++) 00737 place_graph_label(GD_clust(g)[c]); 00738 }
1.7.5