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