Graphviz 13.0.0~dev.20250121.0651
Loading...
Searching...
No Matches
postproc.c
Go to the documentation of this file.
1
3/*************************************************************************
4 * Copyright (c) 2011 AT&T Intellectual Property
5 * All rights reserved. This program and the accompanying materials
6 * are made available under the terms of the Eclipse Public License v1.0
7 * which accompanies this distribution, and is available at
8 * https://www.eclipse.org/legal/epl-v10.html
9 *
10 * Contributors: Details at https://graphviz.org
11 *************************************************************************/
12
13#include <common/render.h>
14#include <float.h>
15#include <label/xlabels.h>
16#include <stdbool.h>
17#include <stddef.h>
18#include <util/agxbuf.h>
19#include <util/alloc.h>
20#include <util/prisize_t.h>
21#include <util/unreachable.h>
22
23static int Rankdir;
24static bool Flip;
26
27static void place_flip_graph_label(graph_t * g);
28
29#define M1 \
30"/pathbox {\n\
31 /Y exch %.5g sub def\n\
32 /X exch %.5g sub def\n\
33 /y exch %.5g sub def\n\
34 /x exch %.5g sub def\n\
35 newpath x y moveto\n\
36 X y lineto\n\
37 X Y lineto\n\
38 x Y lineto\n\
39 closepath stroke\n \
40} def\n\
41/dbgstart { gsave %.5g %.5g translate } def\n\
42/arrowlength 10 def\n\
43/arrowwidth arrowlength 2 div def\n\
44/arrowhead {\n\
45 gsave\n\
46 rotate\n\
47 currentpoint\n\
48 newpath\n\
49 moveto\n\
50 arrowlength arrowwidth 2 div rlineto\n\
51 0 arrowwidth neg rlineto\n\
52 closepath fill\n\
53 grestore\n\
54} bind def\n\
55/makearrow {\n\
56 currentpoint exch pop sub exch currentpoint pop sub atan\n\
57 arrowhead\n\
58} bind def\n\
59/point {\
60 newpath\
61 2 0 360 arc fill\
62} def\
63/makevec {\n\
64 /Y exch def\n\
65 /X exch def\n\
66 /y exch def\n\
67 /x exch def\n\
68 newpath x y moveto\n\
69 X Y lineto stroke\n\
70 X Y moveto\n\
71 x y makearrow\n\
72} def\n"
73
74#define M2 \
75"/pathbox {\n\
76 /X exch neg %.5g sub def\n\
77 /Y exch %.5g sub def\n\
78 /x exch neg %.5g sub def\n\
79 /y exch %.5g sub def\n\
80 newpath x y moveto\n\
81 X y lineto\n\
82 X Y lineto\n\
83 x Y lineto\n\
84 closepath stroke\n\
85} def\n"
86
88{
89 p = ccwrotatepf(p, Rankdir * 90);
90 p.x -= Offset.x;
91 p.y -= Offset.y;
92 return p;
93}
94
95static void map_edge(edge_t * e)
96{
97 bezier bz;
98
99 if (ED_spl(e) == NULL) {
100 if (!Concentrate && ED_edge_type(e) != IGNORED)
101 agerrorf("lost %s %s edge\n", agnameof(agtail(e)),
102 agnameof(aghead(e)));
103 return;
104 }
105 for (size_t j = 0; j < ED_spl(e)->size; j++) {
106 bz = ED_spl(e)->list[j];
107 for (size_t k = 0; k < bz.size; k++)
108 bz.list[k] = map_point(bz.list[k]);
109 if (bz.sflag)
110 ED_spl(e)->list[j].sp = map_point(ED_spl(e)->list[j].sp);
111 if (bz.eflag)
112 ED_spl(e)->list[j].ep = map_point(ED_spl(e)->list[j].ep);
113 }
114 if (ED_label(e))
115 ED_label(e)->pos = map_point(ED_label(e)->pos);
116 if (ED_xlabel(e))
117 ED_xlabel(e)->pos = map_point(ED_xlabel(e)->pos);
118 if (ED_head_label(e))
119 ED_head_label(e)->pos = map_point(ED_head_label(e)->pos);
120 if (ED_tail_label(e))
121 ED_tail_label(e)->pos = map_point(ED_tail_label(e)->pos);
122}
123
124void translate_bb(graph_t * g, int rankdir)
125{
126 int c;
127 boxf bb, new_bb;
128
129 bb = GD_bb(g);
130 if (rankdir == RANKDIR_LR || rankdir == RANKDIR_BT) {
131 new_bb.LL = map_point((pointf){bb.LL.x, bb.UR.y});
132 new_bb.UR = map_point((pointf){bb.UR.x, bb.LL.y});
133 } else {
134 new_bb.LL = map_point((pointf){bb.LL.x, bb.LL.y});
135 new_bb.UR = map_point((pointf){bb.UR.x, bb.UR.y});
136 }
137 GD_bb(g) = new_bb;
138 if (GD_label(g)) {
139 GD_label(g)->pos = map_point(GD_label(g)->pos);
140 }
141 for (c = 1; c <= GD_n_cluster(g); c++)
142 translate_bb(GD_clust(g)[c], rankdir);
143}
144
145/* translate_drawing:
146 * Translate and/or rotate nodes, spline points, and bbox info if
147 * necessary. Also, if Rankdir (!= RANKDIR_BT), reset ND_lw, ND_rw,
148 * and ND_ht to correct value.
149 */
151{
152 node_t *v;
153 edge_t *e;
154 bool shift = Offset.x || Offset.y;
155
156 if (!shift && !Rankdir)
157 return;
158 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
159 if (Rankdir)
160 gv_nodesize(v, false);
161 ND_coord(v) = map_point(ND_coord(v));
162 if (ND_xlabel(v))
163 ND_xlabel(v)->pos = map_point(ND_xlabel(v)->pos);
164 if (State == GVSPLINES)
165 for (e = agfstout(g, v); e; e = agnxtout(g, e))
166 map_edge(e);
167 }
169}
170
171/* place_root_label:
172 * Set position of root graph label.
173 * Note that at this point, after translate_drawing, a
174 * flipped drawing has been transposed, so we don't have
175 * to worry about switching x and y.
176 */
177static void place_root_label(graph_t * g, pointf d)
178{
179 pointf p;
180
181 if (GD_label_pos(g) & LABEL_AT_RIGHT) {
182 p.x = GD_bb(g).UR.x - d.x / 2;
183 } else if (GD_label_pos(g) & LABEL_AT_LEFT) {
184 p.x = GD_bb(g).LL.x + d.x / 2;
185 } else {
186 p.x = (GD_bb(g).LL.x + GD_bb(g).UR.x) / 2;
187 }
188
189 if (GD_label_pos(g) & LABEL_AT_TOP) {
190 p.y = GD_bb(g).UR.y - d.y / 2;
191 } else {
192 p.y = GD_bb(g).LL.y + d.y / 2;
193 }
194
195 GD_label(g)->pos = p;
196 GD_label(g)->set = true;
197}
198
199/* centerPt:
200 * Calculate the center point of the xlabel. The returned positions for
201 * xlabels always correspond to the lower left corner.
202 */
203static pointf
205 pointf p;
206
207 p = xlp->pos;
208 p.x += xlp->sz.x / 2.0;
209 p.y += xlp->sz.y / 2.0;
210
211 return p;
212}
213
214static void printData(object_t *objs, size_t n_objs, xlabel_t *lbls,
215 size_t n_lbls, label_params_t *params) {
216 xlabel_t* xp;
217 fprintf (stderr, "%" PRISIZE_T " objs %" PRISIZE_T
218 " xlabels force=%d bb=(%.02f,%.02f) (%.02f,%.02f)\n",
219 n_objs, n_lbls, params->force, params->bb.LL.x, params->bb.LL.y,
220 params->bb.UR.x, params->bb.UR.y);
221 if (Verbose < 2) return;
222 fprintf(stderr, "objects\n");
223 for (size_t i = 0; i < n_objs; i++) {
224 xp = objs->lbl;
225 fprintf(stderr, " [%" PRISIZE_T "] (%.02f,%.02f) (%.02f,%.02f) %p \"%s\"\n",
226 i, objs->pos.x, objs->pos.y, objs->sz.x, objs->sz.y, objs->lbl,
227 xp ? ((textlabel_t*)xp->lbl)->text : "");
228 objs++;
229 }
230 fprintf(stderr, "xlabels\n");
231 for (size_t i = 0; i < n_lbls; i++) {
232 fprintf(stderr, " [%" PRISIZE_T "] %p set %d (%.02f,%.02f) (%.02f,%.02f) %s\n",
233 i, lbls, lbls->set, lbls->pos.x, lbls->pos.y, lbls->sz.x,
234 lbls->sz.y, ((textlabel_t*)lbls->lbl)->text);
235 lbls++;
236 }
237}
238
239static pointf
241{
242 splines *spl;
243 bezier *bez;
244
245 if ((spl = getsplinepoints(e)) == NULL) {
246 pointf p;
247 p.x = p.y = 0;
248 return p;
249 }
250 bez = &spl->list[0];
251 if (bez->sflag) {
252 return bez->sp;
253 } else {
254 return bez->list[0];
255 }
256}
257
258static pointf
260{
261 splines *spl;
262 bezier *bez;
263
264 if ((spl = getsplinepoints(e)) == NULL) {
265 pointf p;
266 p.x = p.y = 0;
267 return p;
268 }
269 bez = &spl->list[spl->size - 1];
270 if (bez->eflag) {
271 return bez->ep;
272 } else {
273 return bez->list[bez->size - 1];
274 }
275}
276
277/* adjustBB:
278 */
279static boxf
281{
282 pointf ur;
283
284 /* Adjust bounding box */
285 bb.LL.x = MIN(bb.LL.x, objp->pos.x);
286 bb.LL.y = MIN(bb.LL.y, objp->pos.y);
287 ur.x = objp->pos.x + objp->sz.x;
288 ur.y = objp->pos.y + objp->sz.y;
289 bb.UR.x = MAX(bb.UR.x, ur.x);
290 bb.UR.y = MAX(bb.UR.y, ur.y);
291
292 return bb;
293}
294
295/* addXLabel:
296 * Set up xlabel_t object and connect with related object.
297 * If initObj is set, initialize the object.
298 */
299static void
300addXLabel (textlabel_t* lp, object_t* objp, xlabel_t* xlp, int initObj, pointf pos)
301{
302 if (initObj) {
303 *objp = (object_t){.pos = pos};
304 }
305
306 if (Flip) {
307 xlp->sz.x = lp->dimen.y;
308 xlp->sz.y = lp->dimen.x;
309 }
310 else {
311 xlp->sz = lp->dimen;
312 }
313 xlp->lbl = lp;
314 xlp->set = 0;
315 objp->lbl = xlp;
316}
317
318/* addLabelObj:
319 * Set up obstacle object based on set external label.
320 * This includes dot edge labels.
321 * Use label information to determine size and position of object.
322 * Then adjust given bounding box bb to include label and return new bb.
323 */
324static boxf
326{
327 if (Flip) {
328 objp->sz.x = lp->dimen.y;
329 objp->sz.y = lp->dimen.x;
330 }
331 else {
332 objp->sz.x = lp->dimen.x;
333 objp->sz.y = lp->dimen.y;
334 }
335 objp->pos = lp->pos;
336 objp->pos.x -= objp->sz.x / 2.0;
337 objp->pos.y -= objp->sz.y / 2.0;
338
339 return adjustBB(objp, bb);
340}
341
342/* addNodeOjb:
343 * Set up obstacle object based on a node.
344 * Use node information to determine size and position of object.
345 * Then adjust given bounding box bb to include label and return new bb.
346 */
347static boxf
349{
350 if (Flip) {
351 objp->sz.x = INCH2PS(ND_height(np));
352 objp->sz.y = INCH2PS(ND_width(np));
353 }
354 else {
355 objp->sz.x = INCH2PS(ND_width(np));
356 objp->sz.y = INCH2PS(ND_height(np));
357 }
358 objp->pos = ND_coord(np);
359 objp->pos.x -= objp->sz.x / 2.0;
360 objp->pos.y -= objp->sz.y / 2.0;
361
362 return adjustBB(objp, bb);
363}
364
365typedef struct {
368} cinfo_t;
369
370static cinfo_t
372{
373 int c;
374
375 for (c = 1; c <= GD_n_cluster(g); c++)
376 info = addClusterObj (GD_clust(g)[c], info);
377 if (g != agroot(g) && GD_label(g) && GD_label(g)->set) {
378 object_t* objp = info.objp;
379 info.bb = addLabelObj (GD_label(g), objp, info.bb);
380 info.objp++;
381 }
382
383 return info;
384}
385
386static size_t countClusterLabels(Agraph_t *g) {
387 size_t i = 0;
388 if (g != agroot(g) && GD_label(g) && GD_label(g)->set)
389 i++;
390 for (int c = 1; c <= GD_n_cluster(g); c++)
391 i += countClusterLabels (GD_clust(g)[c]);
392 return i;
393}
394
395 /* True if edges geometries were computed and this edge has a geometry */
396#define HAVE_EDGE(ep) ((et != EDGETYPE_NONE) && (ED_spl(ep) != NULL))
397
402static void addXLabels(Agraph_t * gp)
403{
404 Agnode_t *np;
405 Agedge_t *ep;
406 size_t n_nlbls = 0; // # of unset node xlabels
407 size_t n_elbls = 0; // # of unset edge labels or xlabels
408 size_t n_set_lbls = 0; // # of set xlabels and edge labels
409 size_t n_clbls = 0; // # of set cluster labels
410 boxf bb;
411 textlabel_t* lp;
412 label_params_t params;
413 object_t* objs;
414 xlabel_t* lbls;
415 Agsym_t* force;
416 int et = EDGE_TYPE(gp);
417
418 if (!(GD_has_labels(gp) & NODE_XLABEL) &&
419 !(GD_has_labels(gp) & EDGE_XLABEL) &&
420 !(GD_has_labels(gp) & TAIL_LABEL) &&
421 !(GD_has_labels(gp) & HEAD_LABEL) &&
423 return;
424
425 for (np = agfstnode(gp); np; np = agnxtnode(gp, np)) {
426 if (ND_xlabel(np)) {
427 if (ND_xlabel(np)->set)
428 n_set_lbls++;
429 else
430 n_nlbls++;
431 }
432 for (ep = agfstout(gp, np); ep; ep = agnxtout(gp, ep)) {
433 if (ED_xlabel(ep)) {
434 if (ED_xlabel(ep)->set)
435 n_set_lbls++;
436 else if (HAVE_EDGE(ep))
437 n_elbls++;
438 }
439 if (ED_head_label(ep)) {
440 if (ED_head_label(ep)->set)
441 n_set_lbls++;
442 else if (HAVE_EDGE(ep))
443 n_elbls++;
444 }
445 if (ED_tail_label(ep)) {
446 if (ED_tail_label(ep)->set)
447 n_set_lbls++;
448 else if (HAVE_EDGE(ep))
449 n_elbls++;
450 }
451 if (ED_label(ep)) {
452 if (ED_label(ep)->set)
453 n_set_lbls++;
454 else if (HAVE_EDGE(ep))
455 n_elbls++;
456 }
457 }
458 }
459 if (GD_has_labels(gp) & GRAPH_LABEL)
460 n_clbls = countClusterLabels (gp);
461
462 /* A label for each unpositioned external label */
463 size_t n_lbls = n_nlbls + n_elbls;
464 if (n_lbls == 0) return;
465
466 /* An object for each node, each positioned external label, any cluster label,
467 * and all unset edge labels and xlabels.
468 */
469 size_t n_objs = (size_t)agnnodes(gp) + n_set_lbls + n_clbls + n_elbls;
470 object_t* objp = objs = gv_calloc(n_objs, sizeof(object_t));
471 xlabel_t* xlp = lbls = gv_calloc(n_lbls, sizeof(xlabel_t));
472 bb.LL = (pointf){DBL_MAX, DBL_MAX};
473 bb.UR = (pointf){-DBL_MAX, -DBL_MAX};
474
475 for (np = agfstnode(gp); np; np = agnxtnode(gp, np)) {
476
477 bb = addNodeObj (np, objp, bb);
478 if ((lp = ND_xlabel(np))) {
479 if (lp->set) {
480 objp++;
481 bb = addLabelObj (lp, objp, bb);
482 }
483 else {
484 pointf ignored = { 0.0, 0.0 };
485 addXLabel (lp, objp, xlp, 0, ignored);
486 xlp++;
487 }
488 }
489 objp++;
490 for (ep = agfstout(gp, np); ep; ep = agnxtout(gp, ep)) {
491 if ((lp = ED_label(ep))) {
492 if (lp->set) {
493 bb = addLabelObj (lp, objp, bb);
494 }
495 else if (HAVE_EDGE(ep)) {
496 addXLabel (lp, objp, xlp, 1, edgeMidpoint(gp, ep));
497 xlp++;
498 }
499 else {
500 agwarningf("no position for edge with label %s\n",
501 ED_label(ep)->text);
502 continue;
503 }
504 objp++;
505 }
506 if ((lp = ED_tail_label(ep))) {
507 if (lp->set) {
508 bb = addLabelObj (lp, objp, bb);
509 }
510 else if (HAVE_EDGE(ep)) {
511 addXLabel (lp, objp, xlp, 1, edgeTailpoint(ep));
512 xlp++;
513 }
514 else {
515 agwarningf("no position for edge with tail label %s\n",
516 ED_tail_label(ep)->text);
517 continue;
518 }
519 objp++;
520 }
521 if ((lp = ED_head_label(ep))) {
522 if (lp->set) {
523 bb = addLabelObj (lp, objp, bb);
524 }
525 else if (HAVE_EDGE(ep)) {
526 addXLabel (lp, objp, xlp, 1, edgeHeadpoint(ep));
527 xlp++;
528 }
529 else {
530 agwarningf("no position for edge with head label %s\n",
531 ED_head_label(ep)->text);
532 continue;
533 }
534 objp++;
535 }
536 if ((lp = ED_xlabel(ep))) {
537 if (lp->set) {
538 bb = addLabelObj (lp, objp, bb);
539 }
540 else if (HAVE_EDGE(ep)) {
541 addXLabel (lp, objp, xlp, 1, edgeMidpoint(gp, ep));
542 xlp++;
543 }
544 else {
545 agwarningf("no position for edge with xlabel %s\n",
546 ED_xlabel(ep)->text);
547 continue;
548 }
549 objp++;
550 }
551 }
552 }
553 if (n_clbls) {
555 info.bb = bb;
556 info.objp = objp;
557 info = addClusterObj (gp, info);
558 bb = info.bb;
559 }
560
561 force = agfindgraphattr(gp, "forcelabels");
562
563 params.force = late_bool(gp, force, true);
564 params.bb = bb;
565 placeLabels(objs, n_objs, lbls, n_lbls, &params);
566 if (Verbose)
567 printData(objs, n_objs, lbls, n_lbls, &params);
568
569 xlp = lbls;
570 size_t cnt = 0;
571 for (size_t i = 0; i < n_lbls; i++) {
572 if (xlp->set) {
573 cnt++;
574 lp = (textlabel_t *)xlp->lbl;
575 lp->set = 1;
576 lp->pos = centerPt(xlp);
577 updateBB (gp, lp);
578 }
579 xlp++;
580 }
581 if (Verbose)
582 fprintf(stderr, "%" PRISIZE_T " out of %" PRISIZE_T " labels positioned.\n",
583 cnt, n_lbls);
584 else if (cnt != n_lbls)
585 agwarningf("%" PRISIZE_T " out of %" PRISIZE_T " exterior labels positioned.\n",
586 cnt, n_lbls);
587 free(objs);
588 free(lbls);
589}
590
591/* gv_postprocess:
592 * Set graph and cluster label positions.
593 * Add space for root graph label and translate graph accordingly.
594 * Set final nodesize using ns.
595 * Assumes the boxes of all clusters have been computed.
596 * When done, the bounding box of g has LL at origin.
597 */
598void gv_postprocess(Agraph_t * g, int allowTranslation)
599{
600 double diff;
601 pointf dimen = { 0., 0. };
602
603
604 Rankdir = GD_rankdir(g);
605 Flip = GD_flip(g);
606 /* Handle cluster labels */
607 if (Flip)
609 else
611
612 /* Everything has been placed except the root graph label, if any.
613 * The graph positions have not yet been rotated back if necessary.
614 */
615 addXLabels(g);
616
617 /* Add space for graph label if necessary */
618 if (GD_label(g) && !GD_label(g)->set) {
619 dimen = GD_label(g)->dimen;
620 PAD(dimen);
621 if (Flip) {
622 if (GD_label_pos(g) & LABEL_AT_TOP) {
623 GD_bb(g).UR.x += dimen.y;
624 } else {
625 GD_bb(g).LL.x -= dimen.y;
626 }
627
628 if (dimen.x > GD_bb(g).UR.y - GD_bb(g).LL.y) {
629 diff = dimen.x - (GD_bb(g).UR.y - GD_bb(g).LL.y);
630 diff = diff / 2.;
631 GD_bb(g).LL.y -= diff;
632 GD_bb(g).UR.y += diff;
633 }
634 } else {
635 if (GD_label_pos(g) & LABEL_AT_TOP) {
636 if (Rankdir == RANKDIR_TB)
637 GD_bb(g).UR.y += dimen.y;
638 else
639 GD_bb(g).LL.y -= dimen.y;
640 } else {
641 if (Rankdir == RANKDIR_TB)
642 GD_bb(g).LL.y -= dimen.y;
643 else
644 GD_bb(g).UR.y += dimen.y;
645 }
646
647 if (dimen.x > GD_bb(g).UR.x - GD_bb(g).LL.x) {
648 diff = dimen.x - (GD_bb(g).UR.x - GD_bb(g).LL.x);
649 diff = diff / 2.;
650 GD_bb(g).LL.x -= diff;
651 GD_bb(g).UR.x += diff;
652 }
653 }
654 }
655 if (allowTranslation) {
656 switch (Rankdir) {
657 case RANKDIR_TB:
658 Offset = GD_bb(g).LL;
659 break;
660 case RANKDIR_LR:
661 Offset = (pointf){-GD_bb(g).UR.y, GD_bb(g).LL.x};
662 break;
663 case RANKDIR_BT:
664 Offset = (pointf){GD_bb(g).LL.x, -GD_bb(g).UR.y};
665 break;
666 case RANKDIR_RL:
667 Offset = (pointf){GD_bb(g).LL.y, GD_bb(g).LL.x};
668 break;
669 default:
670 UNREACHABLE();
671 }
673 }
674 if (GD_label(g) && !GD_label(g)->set)
675 place_root_label(g, dimen);
676
677 if (!show_boxes_is_empty(&Show_boxes)) {
678 agxbuf buf = {0};
679 if (Flip)
680 agxbprint(&buf, M2, Offset.x, Offset.y, Offset.x, Offset.y);
681 else
683 -Offset.x, -Offset.y);
684 show_boxes_append(&Show_boxes, agxbdisown(&buf));
685 }
686}
687
688/* dotneato_postprocess:
689 */
691{
692 gv_postprocess(g, 1);
693}
694
695/* place_flip_graph_label:
696 * Put cluster labels recursively in the flip case.
697 */
699{
700 int c;
701 pointf p, d;
702
703 if (g != agroot(g) && GD_label(g) && !GD_label(g)->set) {
704 if (GD_label_pos(g) & LABEL_AT_TOP) {
705 d = GD_border(g)[RIGHT_IX];
706 p.x = GD_bb(g).UR.x - d.x / 2;
707 } else {
708 d = GD_border(g)[LEFT_IX];
709 p.x = GD_bb(g).LL.x + d.x / 2;
710 }
711
712 if (GD_label_pos(g) & LABEL_AT_RIGHT) {
713 p.y = GD_bb(g).LL.y + d.y / 2;
714 } else if (GD_label_pos(g) & LABEL_AT_LEFT) {
715 p.y = GD_bb(g).UR.y - d.y / 2;
716 } else {
717 p.y = (GD_bb(g).LL.y + GD_bb(g).UR.y) / 2;
718 }
719 GD_label(g)->pos = p;
720 GD_label(g)->set = true;
721 }
722
723 for (c = 1; c <= GD_n_cluster(g); c++)
725}
726
727/* place_graph_label:
728 * Put cluster labels recursively in the non-flip case.
729 * The adjustments to the bounding boxes should no longer
730 * be necessary, since we now guarantee the label fits in
731 * the cluster.
732 */
734{
735 int c;
736 pointf p, d;
737
738 if (g != agroot(g) && GD_label(g) && !GD_label(g)->set) {
739 if (GD_label_pos(g) & LABEL_AT_TOP) {
740 d = GD_border(g)[TOP_IX];
741 p.y = GD_bb(g).UR.y - d.y / 2;
742 } else {
743 d = GD_border(g)[BOTTOM_IX];
744 p.y = GD_bb(g).LL.y + d.y / 2;
745 }
746
747 if (GD_label_pos(g) & LABEL_AT_RIGHT) {
748 p.x = GD_bb(g).UR.x - d.x / 2;
749 } else if (GD_label_pos(g) & LABEL_AT_LEFT) {
750 p.x = GD_bb(g).LL.x + d.x / 2;
751 } else {
752 p.x = (GD_bb(g).LL.x + GD_bb(g).UR.x) / 2;
753 }
754 GD_label(g)->pos = p;
755 GD_label(g)->set = true;
756 }
757
758 for (c = 1; c <= GD_n_cluster(g); c++)
760}
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:234
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:327
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define MIN(a, b)
Definition arith.h:28
void updateBB(graph_t *g, textlabel_t *lp)
Definition utils.c:621
void gv_nodesize(node_t *n, bool flip)
Definition utils.c:1547
bool late_bool(void *obj, attrsym_t *attr, bool defaultValue)
Definition utils.c:93
#define LABEL_AT_LEFT
Definition const.h:186
#define BOTTOM_IX
Definition const.h:111
#define HEAD_LABEL
Definition const.h:177
#define TOP_IX
Definition const.h:113
#define EDGE_XLABEL
Definition const.h:181
#define GRAPH_LABEL
Definition const.h:179
#define RANKDIR_BT
Definition const.h:192
#define TAIL_LABEL
Definition const.h:178
#define EDGE_LABEL
Definition const.h:176
#define LEFT_IX
Definition const.h:114
#define IGNORED
Definition const.h:30
#define RANKDIR_TB
Definition const.h:190
#define RANKDIR_LR
Definition const.h:191
#define LABEL_AT_TOP
Definition const.h:185
#define LABEL_AT_RIGHT
Definition const.h:187
#define RANKDIR_RL
Definition const.h:193
#define GVSPLINES
Definition const.h:173
#define NODE_XLABEL
Definition const.h:180
#define RIGHT_IX
Definition const.h:112
pointf ccwrotatepf(pointf p, int ccwrot)
Definition geom.c:172
struct pointf_s pointf
#define INCH2PS(a_inches)
Definition geom.h:63
int State
Definition globals.h:62
bool Concentrate
Definition globals.h:58
int EdgeLabelsDone
Definition globals.h:63
show_boxes_t Show_boxes
Definition globals.h:56
static bool Verbose
Definition gml2gv.c:23
void free(void *)
node NULL
Definition grammar.y:163
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:206
int agnnodes(Agraph_t *g)
Definition graph.c:165
#define ED_xlabel(e)
Definition types.h:590
#define ED_head_label(e)
Definition types.h:587
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:24
#define ED_spl(e)
Definition types.h:595
#define agtail(e)
Definition cgraph.h:888
#define ED_edge_type(e)
Definition types.h:582
#define ED_tail_label(e)
Definition types.h:596
#define aghead(e)
Definition cgraph.h:889
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:39
#define ED_label(e)
Definition types.h:589
void agwarningf(const char *fmt,...)
Definition agerror.c:173
void agerrorf(const char *fmt,...)
Definition agerror.c:165
#define agfindgraphattr(g, a)
Definition types.h:613
#define GD_border(g)
Definition types.h:359
#define GD_has_labels(g)
Definition types.h:368
#define GD_clust(g)
Definition types.h:360
#define GD_bb(g)
Definition types.h:354
#define GD_label_pos(g)
Definition types.h:400
#define GD_n_cluster(g)
Definition types.h:389
#define GD_label(g)
Definition types.h:374
#define GD_rankdir(g)
Definition types.h:377
#define GD_flip(g)
Definition types.h:378
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
#define ND_height(n)
Definition types.h:498
#define ND_width(n)
Definition types.h:536
#define ND_xlabel(n)
Definition types.h:503
#define ND_coord(n)
Definition types.h:490
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:143
Agraph_t * agroot(void *obj)
Definition obj.c:168
#define EDGE_TYPE(g)
Definition macros.h:25
#define PAD(d)
Definition macros.h:29
#define M2
Definition postproc.c:74
static pointf edgeTailpoint(Agedge_t *e)
Definition postproc.c:240
static boxf adjustBB(object_t *objp, boxf bb)
Definition postproc.c:280
void translate_bb(graph_t *g, int rankdir)
Definition postproc.c:124
#define HAVE_EDGE(ep)
Definition postproc.c:396
static int Rankdir
Definition postproc.c:23
static void place_root_label(graph_t *g, pointf d)
Definition postproc.c:177
static void place_flip_graph_label(graph_t *g)
Definition postproc.c:698
static boxf addNodeObj(node_t *np, object_t *objp, boxf bb)
Definition postproc.c:348
static void map_edge(edge_t *e)
Definition postproc.c:95
void place_graph_label(graph_t *g)
Definition postproc.c:733
static size_t countClusterLabels(Agraph_t *g)
Definition postproc.c:386
static cinfo_t addClusterObj(Agraph_t *g, cinfo_t info)
Definition postproc.c:371
static pointf centerPt(xlabel_t *xlp)
Definition postproc.c:204
void dotneato_postprocess(Agraph_t *g)
Definition postproc.c:690
static void printData(object_t *objs, size_t n_objs, xlabel_t *lbls, size_t n_lbls, label_params_t *params)
Definition postproc.c:214
static pointf Offset
Definition postproc.c:25
static pointf edgeHeadpoint(Agedge_t *e)
Definition postproc.c:259
static bool Flip
Definition postproc.c:24
#define M1
Definition postproc.c:29
static void addXLabels(Agraph_t *gp)
Definition postproc.c:402
void gv_postprocess(Agraph_t *g, int allowTranslation)
Definition postproc.c:598
static void translate_drawing(graph_t *g)
Definition postproc.c:150
static boxf addLabelObj(textlabel_t *lp, object_t *objp, boxf bb)
Definition postproc.c:325
static pointf map_point(pointf p)
Definition postproc.c:87
static void addXLabel(textlabel_t *lp, object_t *objp, xlabel_t *xlp, int initObj, pointf pos)
Definition postproc.c:300
#define PRISIZE_T
PRIu64 alike for printing size_t
Definition prisize_t.h:27
splines * getsplinepoints(edge_t *e)
Definition splines.c:1392
pointf edgeMidpoint(graph_t *g, edge_t *e)
Definition splines.c:1299
graph or subgraph
Definition cgraph.h:424
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:641
Definition types.h:89
size_t size
Definition types.h:91
pointf sp
Definition types.h:94
pointf * list
Definition types.h:90
uint32_t eflag
Definition types.h:93
pointf ep
Definition types.h:95
uint32_t sflag
Definition types.h:92
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
object_t * objp
Definition postproc.c:367
boxf bb
Definition postproc.c:366
boxf bb
Definition constraint.c:625
unsigned char force
Definition xlabels.h:36
xlabel_t * lbl
Definition xlabels.h:31
pointf pos
Definition xlabels.h:29
pointf sz
Definition xlabels.h:30
double x
Definition geom.h:29
double y
Definition geom.h:29
bezier * list
Definition types.h:99
size_t size
Definition types.h:100
pointf pos
Definition types.h:114
bool set
Definition types.h:123
pointf dimen
Definition types.h:110
void * lbl
Definition xlabels.h:24
unsigned char set
Definition xlabels.h:25
pointf sz
Definition xlabels.h:22
pointf pos
Definition xlabels.h:23
#define UNREACHABLE()
Definition unreachable.h:30
#define MAX(a, b)
Definition write.c:31
int placeLabels(object_t *objs, size_t n_objs, xlabel_t *lbls, size_t n_lbls, label_params_t *params)
Definition xlabels.c:579