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