Graphviz 13.1.3~dev.20250829.0113
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/list.h>
21#include <util/prisize_t.h>
22#include <util/unreachable.h>
23
24static int Rankdir;
25static bool Flip;
27
28static void place_flip_graph_label(graph_t * g);
29
30#define M1 \
31"/pathbox {\n\
32 /Y exch %.5g sub def\n\
33 /X exch %.5g sub def\n\
34 /y exch %.5g sub def\n\
35 /x exch %.5g sub def\n\
36 newpath x y moveto\n\
37 X y lineto\n\
38 X Y lineto\n\
39 x Y lineto\n\
40 closepath stroke\n \
41} def\n\
42/dbgstart { gsave %.5g %.5g translate } def\n\
43/arrowlength 10 def\n\
44/arrowwidth arrowlength 2 div def\n\
45/arrowhead {\n\
46 gsave\n\
47 rotate\n\
48 currentpoint\n\
49 newpath\n\
50 moveto\n\
51 arrowlength arrowwidth 2 div rlineto\n\
52 0 arrowwidth neg rlineto\n\
53 closepath fill\n\
54 grestore\n\
55} bind def\n\
56/makearrow {\n\
57 currentpoint exch pop sub exch currentpoint pop sub atan\n\
58 arrowhead\n\
59} bind def\n\
60/point {\
61 newpath\
62 2 0 360 arc fill\
63} def\
64/makevec {\n\
65 /Y exch def\n\
66 /X exch def\n\
67 /y exch def\n\
68 /x exch def\n\
69 newpath x y moveto\n\
70 X Y lineto stroke\n\
71 X Y moveto\n\
72 x y makearrow\n\
73} def\n"
74
75#define M2 \
76"/pathbox {\n\
77 /X exch neg %.5g sub def\n\
78 /Y exch %.5g sub def\n\
79 /x exch neg %.5g sub def\n\
80 /y exch %.5g sub def\n\
81 newpath x y moveto\n\
82 X y lineto\n\
83 X Y lineto\n\
84 x Y lineto\n\
85 closepath stroke\n\
86} def\n"
87
89{
90 p = ccwrotatepf(p, Rankdir * 90);
91 p.x -= Offset.x;
92 p.y -= Offset.y;
93 return p;
94}
95
96static void map_edge(edge_t * e)
97{
98 bezier bz;
99
100 if (ED_spl(e) == NULL) {
101 if (!Concentrate && ED_edge_type(e) != IGNORED)
102 agerrorf("lost %s %s edge\n", agnameof(agtail(e)),
103 agnameof(aghead(e)));
104 return;
105 }
106 for (size_t j = 0; j < ED_spl(e)->size; j++) {
107 bz = ED_spl(e)->list[j];
108 for (size_t k = 0; k < bz.size; k++)
109 bz.list[k] = map_point(bz.list[k]);
110 if (bz.sflag)
111 ED_spl(e)->list[j].sp = map_point(ED_spl(e)->list[j].sp);
112 if (bz.eflag)
113 ED_spl(e)->list[j].ep = map_point(ED_spl(e)->list[j].ep);
114 }
115 if (ED_label(e))
116 ED_label(e)->pos = map_point(ED_label(e)->pos);
117 if (ED_xlabel(e))
118 ED_xlabel(e)->pos = map_point(ED_xlabel(e)->pos);
119 if (ED_head_label(e))
120 ED_head_label(e)->pos = map_point(ED_head_label(e)->pos);
121 if (ED_tail_label(e))
122 ED_tail_label(e)->pos = map_point(ED_tail_label(e)->pos);
123}
124
125void translate_bb(graph_t * g, int rankdir)
126{
127 int c;
128 boxf bb, new_bb;
129
130 bb = GD_bb(g);
131 if (rankdir == RANKDIR_LR || rankdir == RANKDIR_BT) {
132 new_bb.LL = map_point((pointf){bb.LL.x, bb.UR.y});
133 new_bb.UR = map_point((pointf){bb.UR.x, bb.LL.y});
134 } else {
135 new_bb.LL = map_point((pointf){bb.LL.x, bb.LL.y});
136 new_bb.UR = map_point((pointf){bb.UR.x, bb.UR.y});
137 }
138 GD_bb(g) = new_bb;
139 if (GD_label(g)) {
140 GD_label(g)->pos = map_point(GD_label(g)->pos);
141 }
142 for (c = 1; c <= GD_n_cluster(g); c++)
143 translate_bb(GD_clust(g)[c], rankdir);
144}
145
146/* translate_drawing:
147 * Translate and/or rotate nodes, spline points, and bbox info if
148 * necessary. Also, if Rankdir (!= RANKDIR_BT), reset ND_lw, ND_rw,
149 * and ND_ht to correct value.
150 */
152{
153 node_t *v;
154 edge_t *e;
155 bool shift = Offset.x || Offset.y;
156
157 if (!shift && !Rankdir)
158 return;
159 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
160 if (Rankdir)
161 gv_nodesize(v, false);
162 ND_coord(v) = map_point(ND_coord(v));
163 if (ND_xlabel(v))
164 ND_xlabel(v)->pos = map_point(ND_xlabel(v)->pos);
165 if (State == GVSPLINES)
166 for (e = agfstout(g, v); e; e = agnxtout(g, e))
167 map_edge(e);
168 }
170}
171
172/* place_root_label:
173 * Set position of root graph label.
174 * Note that at this point, after translate_drawing, a
175 * flipped drawing has been transposed, so we don't have
176 * to worry about switching x and y.
177 */
178static void place_root_label(graph_t * g, pointf d)
179{
180 pointf p;
181
182 if (GD_label_pos(g) & LABEL_AT_RIGHT) {
183 p.x = GD_bb(g).UR.x - d.x / 2;
184 } else if (GD_label_pos(g) & LABEL_AT_LEFT) {
185 p.x = GD_bb(g).LL.x + d.x / 2;
186 } else {
187 p.x = (GD_bb(g).LL.x + GD_bb(g).UR.x) / 2;
188 }
189
190 if (GD_label_pos(g) & LABEL_AT_TOP) {
191 p.y = GD_bb(g).UR.y - d.y / 2;
192 } else {
193 p.y = GD_bb(g).LL.y + d.y / 2;
194 }
195
196 GD_label(g)->pos = p;
197 GD_label(g)->set = true;
198}
199
200/* centerPt:
201 * Calculate the center point of the xlabel. The returned positions for
202 * xlabels always correspond to the lower left corner.
203 */
204static pointf
206 pointf p;
207
208 p = xlp->pos;
209 p.x += xlp->sz.x / 2.0;
210 p.y += xlp->sz.y / 2.0;
211
212 return p;
213}
214
215static void printData(object_t *objs, size_t n_objs, xlabel_t *lbls,
216 size_t n_lbls, label_params_t *params) {
217 xlabel_t* xp;
218 fprintf (stderr, "%" PRISIZE_T " objs %" PRISIZE_T
219 " xlabels force=%d bb=(%.02f,%.02f) (%.02f,%.02f)\n",
220 n_objs, n_lbls, (int)params->force, params->bb.LL.x, params->bb.LL.y,
221 params->bb.UR.x, params->bb.UR.y);
222 if (Verbose < 2) return;
223 fprintf(stderr, "objects\n");
224 for (size_t i = 0; i < n_objs; i++) {
225 xp = objs->lbl;
226 fprintf(stderr, " [%" PRISIZE_T "] (%.02f,%.02f) (%.02f,%.02f) %p \"%s\"\n",
227 i, objs->pos.x, objs->pos.y, objs->sz.x, objs->sz.y, objs->lbl,
228 xp ? ((textlabel_t*)xp->lbl)->text : "");
229 objs++;
230 }
231 fprintf(stderr, "xlabels\n");
232 for (size_t i = 0; i < n_lbls; i++) {
233 fprintf(stderr, " [%" PRISIZE_T "] %p set %d (%.02f,%.02f) (%.02f,%.02f) %s\n",
234 i, lbls, lbls->set, lbls->pos.x, lbls->pos.y, lbls->sz.x,
235 lbls->sz.y, ((textlabel_t*)lbls->lbl)->text);
236 lbls++;
237 }
238}
239
240static pointf
242{
243 splines *spl;
244 bezier *bez;
245
246 if ((spl = getsplinepoints(e)) == NULL) {
247 pointf p;
248 p.x = p.y = 0;
249 return p;
250 }
251 bez = &spl->list[0];
252 if (bez->sflag) {
253 return bez->sp;
254 } else {
255 return bez->list[0];
256 }
257}
258
259static pointf
261{
262 splines *spl;
263 bezier *bez;
264
265 if ((spl = getsplinepoints(e)) == NULL) {
266 pointf p;
267 p.x = p.y = 0;
268 return p;
269 }
270 bez = &spl->list[spl->size - 1];
271 if (bez->eflag) {
272 return bez->ep;
273 } else {
274 return bez->list[bez->size - 1];
275 }
276}
277
278/* adjustBB:
279 */
280static boxf
282{
283 pointf ur;
284
285 /* Adjust bounding box */
286 bb.LL.x = MIN(bb.LL.x, objp->pos.x);
287 bb.LL.y = MIN(bb.LL.y, objp->pos.y);
288 ur.x = objp->pos.x + objp->sz.x;
289 ur.y = objp->pos.y + objp->sz.y;
290 bb.UR.x = MAX(bb.UR.x, ur.x);
291 bb.UR.y = MAX(bb.UR.y, ur.y);
292
293 return bb;
294}
295
296/* addXLabel:
297 * Set up xlabel_t object and connect with related object.
298 * If initObj is set, initialize the object.
299 */
300static void
301addXLabel (textlabel_t* lp, object_t* objp, xlabel_t* xlp, int initObj, pointf pos)
302{
303 if (initObj) {
304 *objp = (object_t){.pos = pos};
305 }
306
307 if (Flip) {
308 xlp->sz.x = lp->dimen.y;
309 xlp->sz.y = lp->dimen.x;
310 }
311 else {
312 xlp->sz = lp->dimen;
313 }
314 xlp->lbl = lp;
315 xlp->set = 0;
316 objp->lbl = xlp;
317}
318
319/* addLabelObj:
320 * Set up obstacle object based on set external label.
321 * This includes dot edge labels.
322 * Use label information to determine size and position of object.
323 * Then adjust given bounding box bb to include label and return new bb.
324 */
325static boxf
327{
328 if (Flip) {
329 objp->sz.x = lp->dimen.y;
330 objp->sz.y = lp->dimen.x;
331 }
332 else {
333 objp->sz.x = lp->dimen.x;
334 objp->sz.y = lp->dimen.y;
335 }
336 objp->pos = lp->pos;
337 objp->pos.x -= objp->sz.x / 2.0;
338 objp->pos.y -= objp->sz.y / 2.0;
339
340 return adjustBB(objp, bb);
341}
342
343/* addNodeOjb:
344 * Set up obstacle object based on a node.
345 * Use node information to determine size and position of object.
346 * Then adjust given bounding box bb to include label and return new bb.
347 */
348static boxf
350{
351 if (Flip) {
352 objp->sz.x = INCH2PS(ND_height(np));
353 objp->sz.y = INCH2PS(ND_width(np));
354 }
355 else {
356 objp->sz.x = INCH2PS(ND_width(np));
357 objp->sz.y = INCH2PS(ND_height(np));
358 }
359 objp->pos = ND_coord(np);
360 objp->pos.x -= objp->sz.x / 2.0;
361 objp->pos.y -= objp->sz.y / 2.0;
362
363 return adjustBB(objp, bb);
364}
365
366typedef struct {
369} cinfo_t;
370
371static cinfo_t
373{
374 int c;
375
376 for (c = 1; c <= GD_n_cluster(g); c++)
377 info = addClusterObj (GD_clust(g)[c], info);
378 if (g != agroot(g) && GD_label(g) && GD_label(g)->set) {
379 object_t* objp = info.objp;
380 info.bb = addLabelObj (GD_label(g), objp, info.bb);
381 info.objp++;
382 }
383
384 return info;
385}
386
387static size_t countClusterLabels(Agraph_t *g) {
388 size_t i = 0;
389 if (g != agroot(g) && GD_label(g) && GD_label(g)->set)
390 i++;
391 for (int c = 1; c <= GD_n_cluster(g); c++)
392 i += countClusterLabels (GD_clust(g)[c]);
393 return i;
394}
395
396 /* True if edges geometries were computed and this edge has a geometry */
397#define HAVE_EDGE(ep) ((et != EDGETYPE_NONE) && (ED_spl(ep) != NULL))
398
403static void addXLabels(Agraph_t * gp)
404{
405 Agnode_t *np;
406 Agedge_t *ep;
407 size_t n_nlbls = 0; // # of unset node xlabels
408 size_t n_elbls = 0; // # of unset edge labels or xlabels
409 size_t n_set_lbls = 0; // # of set xlabels and edge labels
410 size_t n_clbls = 0; // # of set cluster labels
411 boxf bb;
412 textlabel_t* lp;
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 label_params_t params = {.bb = bb, .force = late_bool(gp, force, true)};
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 (!LIST_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);
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:233
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:326
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:623
void gv_nodesize(node_t *n, bool flip)
Definition utils.c:1534
bool late_bool(void *obj, attrsym_t *attr, bool defaultValue)
Definition utils.c:94
#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:148
struct pointf_s pointf
#define INCH2PS(a_inches)
Definition geom.h:63
show_boxes_t Show_boxes
Definition globals.c:22
int State
Definition globals.h:63
bool Concentrate
Definition globals.h:59
int EdgeLabelsDone
Definition globals.h:64
static bool Verbose
Definition gml2gv.c:24
void free(void *)
node NULL
Definition grammar.y:181
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:196
int agnnodes(Agraph_t *g)
Definition graph.c:155
#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:26
#define ED_spl(e)
Definition types.h:595
#define agtail(e)
Definition cgraph.h:988
#define ED_edge_type(e)
Definition types.h:582
#define ED_tail_label(e)
Definition types.h:596
#define aghead(e)
Definition cgraph.h:989
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:41
#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:48
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:41
#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
type-generic dynamically expanding list
#define LIST_PREPEND(list, item)
Definition list.h:149
#define LIST_IS_EMPTY(list)
Definition list.h:90
#define EDGE_TYPE(g)
Definition macros.h:25
#define PAD(d)
Definition macros.h:29
#define M2
Definition postproc.c:75
static pointf edgeTailpoint(Agedge_t *e)
Definition postproc.c:241
static boxf adjustBB(object_t *objp, boxf bb)
Definition postproc.c:281
void translate_bb(graph_t *g, int rankdir)
Definition postproc.c:125
#define HAVE_EDGE(ep)
Definition postproc.c:397
static int Rankdir
Definition postproc.c:24
static void place_root_label(graph_t *g, pointf d)
Definition postproc.c:178
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:349
static void map_edge(edge_t *e)
Definition postproc.c:96
void place_graph_label(graph_t *g)
Definition postproc.c:732
static size_t countClusterLabels(Agraph_t *g)
Definition postproc.c:387
static cinfo_t addClusterObj(Agraph_t *g, cinfo_t info)
Definition postproc.c:372
static pointf centerPt(xlabel_t *xlp)
Definition postproc.c:205
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:215
static pointf Offset
Definition postproc.c:26
static pointf edgeHeadpoint(Agedge_t *e)
Definition postproc.c:260
static bool Flip
Definition postproc.c:25
#define M1
Definition postproc.c:30
static void addXLabels(Agraph_t *gp)
Definition postproc.c:403
void gv_postprocess(Agraph_t *g, int allowTranslation)
Definition postproc.c:597
static void translate_drawing(graph_t *g)
Definition postproc.c:151
static boxf addLabelObj(textlabel_t *lp, object_t *objp, boxf bb)
Definition postproc.c:326
static pointf map_point(pointf p)
Definition postproc.c:88
static void addXLabel(textlabel_t *lp, object_t *objp, xlabel_t *xlp, int initObj, pointf pos)
Definition postproc.c:301
#define PRISIZE_T
Definition prisize_t.h:25
splines * getsplinepoints(edge_t *e)
Definition splines.c:1388
pointf edgeMidpoint(graph_t *g, edge_t *e)
Definition splines.c:1295
graph or subgraph
Definition cgraph.h:424
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:651
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:368
boxf bb
Definition postproc.c:367
boxf bb
Definition constraint.c:622
bool force
if true, all labels must be placed
Definition xlabels.h:37
xlabel_t * lbl
Definition xlabels.h:32
pointf pos
Definition xlabels.h:30
pointf sz
Definition xlabels.h:31
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:25
unsigned char set
Definition xlabels.h:26
pointf sz
Definition xlabels.h:23
pointf pos
Definition xlabels.h:24
#define UNREACHABLE()
Definition unreachable.h:30
#define MAX(a, b)
Definition write.c:32
int placeLabels(object_t *objs, size_t n_objs, xlabel_t *lbls, size_t n_lbls, label_params_t *params)
Definition xlabels.c:547