Graphviz 12.0.1~dev.20240715.2254
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 <cgraph/alloc.h>
14#include <cgraph/agxbuf.h>
15#include <cgraph/prisize_t.h>
16#include <cgraph/unreachable.h>
17#include <common/render.h>
18#include <label/xlabels.h>
19#include <stdbool.h>
20#include <stddef.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->sz.x = 0;
303 objp->sz.y = 0;
304 objp->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/* addXLabels:
397 * Position xlabels and any unpositioned edge labels using
398 * a map placement algorithm to avoid overlap.
399 *
400 * TODO: interaction with spline=ortho
401 */
402 /* True if edges geometries were computed and this edge has a geometry */
403#define HAVE_EDGE(ep) ((et != EDGETYPE_NONE) && (ED_spl(ep) != NULL))
404
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 label_params_t params;
416 object_t* objs;
417 xlabel_t* lbls;
418 Agsym_t* force;
419 int et = EDGE_TYPE(gp);
420
421 if (!(GD_has_labels(gp) & NODE_XLABEL) &&
422 !(GD_has_labels(gp) & EDGE_XLABEL) &&
423 !(GD_has_labels(gp) & TAIL_LABEL) &&
424 !(GD_has_labels(gp) & HEAD_LABEL) &&
426 return;
427
428 for (np = agfstnode(gp); np; np = agnxtnode(gp, np)) {
429 if (ND_xlabel(np)) {
430 if (ND_xlabel(np)->set)
431 n_set_lbls++;
432 else
433 n_nlbls++;
434 }
435 for (ep = agfstout(gp, np); ep; ep = agnxtout(gp, ep)) {
436 if (ED_xlabel(ep)) {
437 if (ED_xlabel(ep)->set)
438 n_set_lbls++;
439 else if (HAVE_EDGE(ep))
440 n_elbls++;
441 }
442 if (ED_head_label(ep)) {
443 if (ED_head_label(ep)->set)
444 n_set_lbls++;
445 else if (HAVE_EDGE(ep))
446 n_elbls++;
447 }
448 if (ED_tail_label(ep)) {
449 if (ED_tail_label(ep)->set)
450 n_set_lbls++;
451 else if (HAVE_EDGE(ep))
452 n_elbls++;
453 }
454 if (ED_label(ep)) {
455 if (ED_label(ep)->set)
456 n_set_lbls++;
457 else if (HAVE_EDGE(ep))
458 n_elbls++;
459 }
460 }
461 }
462 if (GD_has_labels(gp) & GRAPH_LABEL)
463 n_clbls = countClusterLabels (gp);
464
465 /* A label for each unpositioned external label */
466 size_t n_lbls = n_nlbls + n_elbls;
467 if (n_lbls == 0) return;
468
469 /* An object for each node, each positioned external label, any cluster label,
470 * and all unset edge labels and xlabels.
471 */
472 size_t n_objs = (size_t)agnnodes(gp) + n_set_lbls + n_clbls + n_elbls;
473 object_t* objp = objs = gv_calloc(n_objs, sizeof(object_t));
474 xlabel_t* xlp = lbls = gv_calloc(n_lbls, sizeof(xlabel_t));
475 bb.LL = (pointf){INT_MAX, INT_MAX};
476 bb.UR = (pointf){-INT_MAX, -INT_MAX};
477
478 for (np = agfstnode(gp); np; np = agnxtnode(gp, np)) {
479
480 bb = addNodeObj (np, objp, bb);
481 if ((lp = ND_xlabel(np))) {
482 if (lp->set) {
483 objp++;
484 bb = addLabelObj (lp, objp, bb);
485 }
486 else {
487 pointf ignored = { 0.0, 0.0 };
488 addXLabel (lp, objp, xlp, 0, ignored);
489 xlp++;
490 }
491 }
492 objp++;
493 for (ep = agfstout(gp, np); ep; ep = agnxtout(gp, ep)) {
494 if ((lp = ED_label(ep))) {
495 if (lp->set) {
496 bb = addLabelObj (lp, objp, bb);
497 }
498 else if (HAVE_EDGE(ep)) {
499 addXLabel (lp, objp, xlp, 1, edgeMidpoint(gp, ep));
500 xlp++;
501 }
502 else {
503 agwarningf("no position for edge with label %s\n",
504 ED_label(ep)->text);
505 continue;
506 }
507 objp++;
508 }
509 if ((lp = ED_tail_label(ep))) {
510 if (lp->set) {
511 bb = addLabelObj (lp, objp, bb);
512 }
513 else if (HAVE_EDGE(ep)) {
514 addXLabel (lp, objp, xlp, 1, edgeTailpoint(ep));
515 xlp++;
516 }
517 else {
518 agwarningf("no position for edge with tail label %s\n",
519 ED_tail_label(ep)->text);
520 continue;
521 }
522 objp++;
523 }
524 if ((lp = ED_head_label(ep))) {
525 if (lp->set) {
526 bb = addLabelObj (lp, objp, bb);
527 }
528 else if (HAVE_EDGE(ep)) {
529 addXLabel (lp, objp, xlp, 1, edgeHeadpoint(ep));
530 xlp++;
531 }
532 else {
533 agwarningf("no position for edge with head label %s\n",
534 ED_head_label(ep)->text);
535 continue;
536 }
537 objp++;
538 }
539 if ((lp = ED_xlabel(ep))) {
540 if (lp->set) {
541 bb = addLabelObj (lp, objp, bb);
542 }
543 else if (HAVE_EDGE(ep)) {
544 addXLabel (lp, objp, xlp, 1, edgeMidpoint(gp, ep));
545 xlp++;
546 }
547 else {
548 agwarningf("no position for edge with xlabel %s\n",
549 ED_xlabel(ep)->text);
550 continue;
551 }
552 objp++;
553 }
554 }
555 }
556 if (n_clbls) {
558 info.bb = bb;
559 info.objp = objp;
560 info = addClusterObj (gp, info);
561 bb = info.bb;
562 }
563
564 force = agfindgraphattr(gp, "forcelabels");
565
566 params.force = late_bool(gp, force, true);
567 params.bb = bb;
568 placeLabels(objs, n_objs, lbls, n_lbls, &params);
569 if (Verbose)
570 printData(objs, n_objs, lbls, n_lbls, &params);
571
572 xlp = lbls;
573 size_t cnt = 0;
574 for (size_t i = 0; i < n_lbls; i++) {
575 if (xlp->set) {
576 cnt++;
577 lp = (textlabel_t *)xlp->lbl;
578 lp->set = 1;
579 lp->pos = centerPt(xlp);
580 updateBB (gp, lp);
581 }
582 xlp++;
583 }
584 if (Verbose)
585 fprintf(stderr, "%" PRISIZE_T " out of %" PRISIZE_T " labels positioned.\n",
586 cnt, n_lbls);
587 else if (cnt != n_lbls)
588 agwarningf("%" PRISIZE_T " out of %" PRISIZE_T " exterior labels positioned.\n",
589 cnt, n_lbls);
590 free(objs);
591 free(lbls);
592}
593
594/* gv_postprocess:
595 * Set graph and cluster label positions.
596 * Add space for root graph label and translate graph accordingly.
597 * Set final nodesize using ns.
598 * Assumes the boxes of all clusters have been computed.
599 * When done, the bounding box of g has LL at origin.
600 */
601void gv_postprocess(Agraph_t * g, int allowTranslation)
602{
603 double diff;
604 pointf dimen = { 0., 0. };
605
606
607 Rankdir = GD_rankdir(g);
608 Flip = GD_flip(g);
609 /* Handle cluster labels */
610 if (Flip)
612 else
614
615 /* Everything has been placed except the root graph label, if any.
616 * The graph positions have not yet been rotated back if necessary.
617 */
618 addXLabels(g);
619
620 /* Add space for graph label if necessary */
621 if (GD_label(g) && !GD_label(g)->set) {
622 dimen = GD_label(g)->dimen;
623 PAD(dimen);
624 if (Flip) {
625 if (GD_label_pos(g) & LABEL_AT_TOP) {
626 GD_bb(g).UR.x += dimen.y;
627 } else {
628 GD_bb(g).LL.x -= dimen.y;
629 }
630
631 if (dimen.x > GD_bb(g).UR.y - GD_bb(g).LL.y) {
632 diff = dimen.x - (GD_bb(g).UR.y - GD_bb(g).LL.y);
633 diff = diff / 2.;
634 GD_bb(g).LL.y -= diff;
635 GD_bb(g).UR.y += diff;
636 }
637 } else {
638 if (GD_label_pos(g) & LABEL_AT_TOP) {
639 if (Rankdir == RANKDIR_TB)
640 GD_bb(g).UR.y += dimen.y;
641 else
642 GD_bb(g).LL.y -= dimen.y;
643 } else {
644 if (Rankdir == RANKDIR_TB)
645 GD_bb(g).LL.y -= dimen.y;
646 else
647 GD_bb(g).UR.y += dimen.y;
648 }
649
650 if (dimen.x > GD_bb(g).UR.x - GD_bb(g).LL.x) {
651 diff = dimen.x - (GD_bb(g).UR.x - GD_bb(g).LL.x);
652 diff = diff / 2.;
653 GD_bb(g).LL.x -= diff;
654 GD_bb(g).UR.x += diff;
655 }
656 }
657 }
658 if (allowTranslation) {
659 switch (Rankdir) {
660 case RANKDIR_TB:
661 Offset = GD_bb(g).LL;
662 break;
663 case RANKDIR_LR:
664 Offset = (pointf){-GD_bb(g).UR.y, GD_bb(g).LL.x};
665 break;
666 case RANKDIR_BT:
667 Offset = (pointf){GD_bb(g).LL.x, -GD_bb(g).UR.y};
668 break;
669 case RANKDIR_RL:
670 Offset = (pointf){GD_bb(g).LL.y, GD_bb(g).LL.x};
671 break;
672 default:
673 UNREACHABLE();
674 }
676 }
677 if (GD_label(g) && !GD_label(g)->set)
678 place_root_label(g, dimen);
679
680 if (!show_boxes_is_empty(&Show_boxes)) {
681 agxbuf buf = {0};
682 if (Flip)
683 agxbprint(&buf, M2, Offset.x, Offset.y, Offset.x, Offset.y);
684 else
686 -Offset.x, -Offset.y);
687 show_boxes_append(&Show_boxes, agxbdisown(&buf));
688 }
689}
690
691/* dotneato_postprocess:
692 */
694{
695 gv_postprocess(g, 1);
696}
697
698/* place_flip_graph_label:
699 * Put cluster labels recursively in the flip case.
700 */
702{
703 int c;
704 pointf p, d;
705
706 if (g != agroot(g) && GD_label(g) && !GD_label(g)->set) {
707 if (GD_label_pos(g) & LABEL_AT_TOP) {
708 d = GD_border(g)[RIGHT_IX];
709 p.x = GD_bb(g).UR.x - d.x / 2;
710 } else {
711 d = GD_border(g)[LEFT_IX];
712 p.x = GD_bb(g).LL.x + d.x / 2;
713 }
714
715 if (GD_label_pos(g) & LABEL_AT_RIGHT) {
716 p.y = GD_bb(g).LL.y + d.y / 2;
717 } else if (GD_label_pos(g) & LABEL_AT_LEFT) {
718 p.y = GD_bb(g).UR.y - d.y / 2;
719 } else {
720 p.y = (GD_bb(g).LL.y + GD_bb(g).UR.y) / 2;
721 }
722 GD_label(g)->pos = p;
723 GD_label(g)->set = true;
724 }
725
726 for (c = 1; c <= GD_n_cluster(g); c++)
728}
729
730/* place_graph_label:
731 * Put cluster labels recursively in the non-flip case.
732 * The adjustments to the bounding boxes should no longer
733 * be necessary, since we now guarantee the label fits in
734 * the cluster.
735 */
737{
738 int c;
739 pointf p, d;
740
741 if (g != agroot(g) && GD_label(g) && !GD_label(g)->set) {
742 if (GD_label_pos(g) & LABEL_AT_TOP) {
743 d = GD_border(g)[TOP_IX];
744 p.y = GD_bb(g).UR.y - d.y / 2;
745 } else {
746 d = GD_border(g)[BOTTOM_IX];
747 p.y = GD_bb(g).LL.y + d.y / 2;
748 }
749
750 if (GD_label_pos(g) & LABEL_AT_RIGHT) {
751 p.x = GD_bb(g).UR.x - d.x / 2;
752 } else if (GD_label_pos(g) & LABEL_AT_LEFT) {
753 p.x = GD_bb(g).LL.x + d.x / 2;
754 } else {
755 p.x = (GD_bb(g).LL.x + GD_bb(g).UR.x) / 2;
756 }
757 GD_label(g)->pos = p;
758 GD_label(g)->set = true;
759 }
760
761 for (c = 1; c <= GD_n_cluster(g); c++)
763}
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:213
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:299
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:620
void gv_nodesize(node_t *n, bool flip)
Definition utils.c:1556
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:65
bool Concentrate
Definition globals.h:61
int EdgeLabelsDone
Definition globals.h:66
show_boxes_t Show_boxes
Definition globals.h:59
static int Verbose
Definition gml2gv.c:22
void free(void *)
node NULL
Definition grammar.y:149
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:199
int agnnodes(Agraph_t *g)
Definition graph.c:158
#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:23
#define ED_spl(e)
Definition types.h:595
#define agtail(e)
Definition cgraph.h:889
#define ED_edge_type(e)
Definition types.h:582
#define ED_tail_label(e)
Definition types.h:596
#define aghead(e)
Definition cgraph.h:890
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:38
#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:167
#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:403
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:701
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:94
void place_graph_label(graph_t *g)
Definition postproc.c:736
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:203
void dotneato_postprocess(Agraph_t *g)
Definition postproc.c:693
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:405
void gv_postprocess(Agraph_t *g, int allowTranslation)
Definition postproc.c:601
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:326
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:639
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: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