Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
output.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 <gvc/gvc.h>
15#include <stdarg.h>
16#include <stdbool.h>
17#include <stddef.h>
18#include <string.h>
19#include <util/agxbuf.h>
20#include <util/prisize_t.h>
21
23typedef struct {
24 double Y;
25 double YF;
26} offsets_t;
27
28static double YFDIR(offsets_t offsets, double y) {
29 return Y_invert ? offsets.YF - y : y;
30}
31
32double yDir(double y, double Y_off) {
33 return Y_invert ? Y_off - y : y;
34}
35
36static void agputs(int (*putstr)(void *chan, const char *str), const char* s,
37 FILE* fp) {
38 putstr(fp, s);
39}
40
41static void agputc(int (*putstr)(void *chan, const char *str), char c,
42 FILE *fp) {
43 char buf[] = {c, '\0'};
44 putstr(fp, buf);
45}
46
47static void printstring(int (*putstr)(void *chan, const char *str), FILE *f,
48 char *prefix, char *s) {
49 if (prefix) agputs(putstr, prefix, f);
50 agputs(putstr, s, f);
51}
52
53static void printint(int (*putstr)(void *chan, const char *str), FILE *f,
54 char *prefix, size_t i) {
55 agxbuf buf = {0};
56
57 if (prefix) agputs(putstr, prefix, f);
58 agxbprint(&buf, "%" PRISIZE_T, i);
59 agputs(putstr, agxbuse(&buf), f);
60 agxbfree(&buf);
61}
62
63static void printdouble(int (*putstr)(void *chan, const char *str), FILE *f,
64 char *prefix, double v) {
65 agxbuf buf = {0};
66
67 if (prefix) agputs(putstr, prefix, f);
68 agxbprint(&buf, "%.5g", v);
69 agputs(putstr, agxbuse(&buf), f);
70 agxbfree(&buf);
71}
72
73static void printpoint(int (*putstr)(void *chan, const char *str), FILE *f,
74 pointf p, double yOff) {
75 printdouble(putstr, f, " ", PS2INCH(p.x));
76 printdouble(putstr, f, " ", PS2INCH(yDir(p.y, yOff)));
77}
78
79/* setYInvert:
80 * Set parameters used to flip coordinate system (y=0 at top).
81 * Values do not need to be unset, since if Y_invert is set, it's
82 * set for * all graphs during current run, so each will
83 * reinitialize the values for its bbox.
84 */
86 offsets_t rv = {0};
87 if (Y_invert) {
88 rv.Y = GD_bb(g).UR.y + GD_bb(g).LL.y;
89 rv.YF = PS2INCH(rv.Y);
90 }
91 return rv;
92}
93
94/* canon:
95 * Canonicalize a string which may not have been allocated using agstrdup.
96 */
97static char* canon (graph_t *g, char* s)
98{
99 char* ns = agstrdup (g, s);
100 char* cs = agcanonStr (ns);
101 agstrfree (g, ns);
102 return cs;
103}
104
105static void writenodeandport(int (*putstr)(void *chan, const char *str),
106 FILE *f, node_t *node, char *portname) {
107 char *name;
108 if (IS_CLUST_NODE(node))
109 name = canon (agraphof(node), strchr(agnameof(node), ':') + 1);
110 else
111 name = agcanonStr (agnameof(node));
112 printstring(putstr, f, " ", name); /* slimey i know */
113 if (portname && *portname)
114 printstring(putstr, f, ":", agcanonStr(portname));
115}
116
117void write_plain(GVJ_t *job, graph_t *g, FILE *f, bool extend) {
118 char *tport, *hport;
119 node_t *n;
120 edge_t *e;
121 bezier bz;
122 pointf pt;
123 char *lbl;
124 char* fillcolor;
125
126 int (*putstr)(void *chan, const char *str) = g->clos->disc.io->putstr;
127 const offsets_t offsets = setYInvert(g);
128 pt = GD_bb(g).UR;
129 printdouble(putstr, f, "graph ", job->zoom);
130 printdouble(putstr, f, " ", PS2INCH(pt.x));
131 printdouble(putstr, f, " ", PS2INCH(pt.y));
132 agputc(putstr, '\n', f);
133 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
134 if (IS_CLUST_NODE(n))
135 continue;
136 printstring(putstr, f, "node ", agcanonStr(agnameof(n)));
137 printpoint(putstr, f, ND_coord(n), offsets.Y);
138 if (ND_label(n)->html) /* if html, get original text */
139 lbl = agcanonStr (agxget(n, N_label));
140 else
141 lbl = canon(agraphof(n),ND_label(n)->text);
142 printdouble(putstr, f, " ", ND_width(n));
143 printdouble(putstr, f, " ", ND_height(n));
144 printstring(putstr, f, " ", lbl);
145 printstring(putstr, f, " ", late_nnstring(n, N_style, "solid"));
146 printstring(putstr, f, " ", ND_shape(n)->name);
147 printstring(putstr, f, " ", late_nnstring(n, N_color, DEFAULT_COLOR));
148 fillcolor = late_nnstring(n, N_fillcolor, "");
149 if (fillcolor[0] == '\0')
150 fillcolor = late_nnstring(n, N_color, DEFAULT_FILL);
151 printstring(putstr, f, " ", fillcolor);
152 agputc(putstr, '\n', f);
153 }
154 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
155 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
156
157 if (extend) { //assuming these two attrs have already been created by cgraph
158 if (!(tport = agget(e,"tailport")))
159 tport = "";
160 if (!(hport = agget(e,"headport")))
161 hport = "";
162 }
163 else
164 tport = hport = "";
165 if (ED_spl(e)) {
166 size_t splinePoints = 0;
167 for (size_t i = 0; i < ED_spl(e)->size; i++) {
168 bz = ED_spl(e)->list[i];
169 splinePoints += bz.size;
170 }
171 printstring(putstr, f, NULL, "edge");
172 writenodeandport(putstr, f, agtail(e), tport);
173 writenodeandport(putstr, f, aghead(e), hport);
174 printint(putstr, f, " ", splinePoints);
175 for (size_t i = 0; i < ED_spl(e)->size; i++) {
176 bz = ED_spl(e)->list[i];
177 for (size_t j = 0; j < bz.size; j++)
178 printpoint(putstr, f, bz.list[j], offsets.Y);
179 }
180 }
181 if (ED_label(e)) {
182 printstring(putstr, f, " ", canon(agraphof(agtail(e)),ED_label(e)->text));
183 printpoint(putstr, f, ED_label(e)->pos, offsets.Y);
184 }
185 printstring(putstr, f, " ", late_nnstring(e, E_style, "solid"));
186 printstring(putstr, f, " ", late_nnstring(e, E_color, DEFAULT_COLOR));
187 agputc(putstr, '\n', f);
188 }
189 }
190 agputs(putstr, "stop\n", f);
191}
192
193static void set_record_rects(node_t *n, field_t *f, agxbuf *xb, double yOff) {
194 int i;
195
196 if (f->n_flds == 0) {
197 agxbprint(xb, "%.5g,%.5g,%.5g,%.5g ",
198 f->b.LL.x + ND_coord(n).x,
199 yDir(f->b.LL.y + ND_coord(n).y, yOff),
200 f->b.UR.x + ND_coord(n).x,
201 yDir(f->b.UR.y + ND_coord(n).y, yOff));
202 }
203 for (i = 0; i < f->n_flds; i++)
204 set_record_rects(n, f->fld[i], xb, yOff);
205}
206
207static void rec_attach_bb(graph_t *g, Agsym_t *bbsym, Agsym_t *lpsym,
208 Agsym_t *lwsym, Agsym_t *lhsym, double yOff) {
209 int c;
210 agxbuf buf = {0};
211 pointf pt;
212
213 agxbprint(&buf, "%.5g,%.5g,%.5g,%.5g", GD_bb(g).LL.x,
214 yDir(GD_bb(g).LL.y, yOff), GD_bb(g).UR.x,
215 yDir(GD_bb(g).UR.y, yOff));
216 agxset(g, bbsym, agxbuse(&buf));
217 if (GD_label(g) && GD_label(g)->text[0]) {
218 pt = GD_label(g)->pos;
219 agxbprint(&buf, "%.5g,%.5g", pt.x, yDir(pt.y, yOff));
220 agxset(g, lpsym, agxbuse(&buf));
221 pt = GD_label(g)->dimen;
222 agxbprint(&buf, "%.2f", PS2INCH(pt.x));
223 agxset(g, lwsym, agxbuse(&buf));
224 agxbprint(&buf, "%.2f", PS2INCH(pt.y));
225 agxset(g, lhsym, agxbuse(&buf));
226 }
227 for (c = 1; c <= GD_n_cluster(g); c++)
228 rec_attach_bb(GD_clust(g)[c], bbsym, lpsym, lwsym, lhsym, yOff);
229 agxbfree(&buf);
230}
231
232double attach_attrs_and_arrows(graph_t *g, bool *sp, bool *ep) {
233 node_t *n;
234 edge_t *e;
235 pointf ptf;
236 int dim3 = (GD_odim(g) >= 3);
237 Agsym_t* bbsym = NULL;
238 Agsym_t* lpsym = NULL;
239 Agsym_t* lwsym = NULL;
240 Agsym_t* lhsym = NULL;
241
242 gv_fixLocale (1);
243 bool e_arrows = false; // graph has edges with end arrows
244 bool s_arrows = false; // graph has edges with start arrows
245 const offsets_t offsets = setYInvert(g);
246 agxbuf xb = {0};
247 safe_dcl(g, AGNODE, "pos", "");
248 safe_dcl(g, AGNODE, "rects", "");
249 N_width = safe_dcl(g, AGNODE, "width", "");
250 N_height = safe_dcl(g, AGNODE, "height", "");
251 safe_dcl(g, AGEDGE, "pos", "");
252 if (GD_has_labels(g) & NODE_XLABEL)
253 safe_dcl(g, AGNODE, "xlp", "");
254 if (GD_has_labels(g) & EDGE_LABEL)
255 safe_dcl(g, AGEDGE, "lp", "");
256 if (GD_has_labels(g) & EDGE_XLABEL)
257 safe_dcl(g, AGEDGE, "xlp", "");
258 if (GD_has_labels(g) & HEAD_LABEL)
259 safe_dcl(g, AGEDGE, "head_lp", "");
260 if (GD_has_labels(g) & TAIL_LABEL)
261 safe_dcl(g, AGEDGE, "tail_lp", "");
262 if (GD_has_labels(g) & GRAPH_LABEL) {
263 lpsym = safe_dcl(g, AGRAPH, "lp", "");
264 lwsym = safe_dcl(g, AGRAPH, "lwidth", "");
265 lhsym = safe_dcl(g, AGRAPH, "lheight", "");
266 }
267 bbsym = safe_dcl(g, AGRAPH, "bb", "");
268 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
269 if (dim3) {
270 int k;
271
272 agxbprint(&xb, "%.5g,%.5g,%.5g", ND_coord(n).x,
273 yDir(ND_coord(n).y, offsets.Y),
274 POINTS_PER_INCH * ND_pos(n)[2]);
275 for (k = 3; k < GD_odim(g); k++) {
276 agxbprint(&xb, ",%.5g", POINTS_PER_INCH*(ND_pos(n)[k]));
277 }
278 agset(n, "pos", agxbuse(&xb));
279 } else {
280 agxbprint(&xb, "%.5g,%.5g", ND_coord(n).x, yDir(ND_coord(n).y, offsets.Y));
281 agset(n, "pos", agxbuse(&xb));
282 }
283 agxbprint(&xb, "%.5g", PS2INCH(ND_ht(n)));
284 agxset(n, N_height, agxbuse(&xb));
285 agxbprint(&xb, "%.5g", PS2INCH(ND_lw(n) + ND_rw(n)));
286 agxset(n, N_width, agxbuse(&xb));
287 if (ND_xlabel(n) && ND_xlabel(n)->set) {
288 ptf = ND_xlabel(n)->pos;
289 agxbprint(&xb, "%.5g,%.5g", ptf.x, yDir(ptf.y, offsets.Y));
290 agset(n, "xlp", agxbuse(&xb));
291 }
292 if (strcmp(ND_shape(n)->name, "record") == 0) {
293 set_record_rects(n, ND_shape_info(n), &xb, offsets.Y);
294 agxbpop(&xb); /* get rid of last space */
295 agset(n, "rects", agxbuse(&xb));
296 } else {
298 if (N_vertices && isPolygon(n)) {
299 poly = ND_shape_info(n);
300 size_t sides = poly->sides;
301 if (sides < 3) {
302 char *p = agget(n, "samplepoints");
303 if (p)
304 sides = strtoul(p, NULL, 0);
305 else
306 sides = 8;
307 if (sides < 3)
308 sides = 8;
309 }
310 for (size_t i = 0; i < sides; i++) {
311 if (i > 0)
312 agxbputc(&xb, ' ');
313 if (poly->sides >= 3)
314 agxbprint(&xb, "%.5g %.5g",
315 PS2INCH(poly->vertices[i].x),
316 YFDIR(offsets, PS2INCH(poly->vertices[i].y)));
317 else
318 agxbprint(&xb, "%.5g %.5g",
319 ND_width(n) / 2.0 * cos((double)i / (double)sides * M_PI * 2.0),
320 YFDIR(offsets,
321 ND_height(n) / 2.0 * sin((double)i / (double)sides * M_PI * 2.0)));
322 }
323 agxset(n, N_vertices, agxbuse(&xb));
324 }
325 }
326 if (State >= GVSPLINES) {
327 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
328 if (ED_edge_type(e) == IGNORED)
329 continue;
330 if (ED_spl(e) == NULL)
331 continue; /* reported in postproc */
332 for (size_t i = 0; i < ED_spl(e)->size; i++) {
333 if (i > 0)
334 agxbputc(&xb, ';');
335 if (ED_spl(e)->list[i].sflag) {
336 s_arrows = true;
337 agxbprint(&xb, "s,%.5g,%.5g ",
338 ED_spl(e)->list[i].sp.x,
339 yDir(ED_spl(e)->list[i].sp.y, offsets.Y));
340 }
341 if (ED_spl(e)->list[i].eflag) {
342 e_arrows = true;
343 agxbprint(&xb, "e,%.5g,%.5g ",
344 ED_spl(e)->list[i].ep.x,
345 yDir(ED_spl(e)->list[i].ep.y, offsets.Y));
346 }
347 for (size_t j = 0; j < ED_spl(e)->list[i].size; j++) {
348 if (j > 0)
349 agxbputc(&xb, ' ');
350 ptf = ED_spl(e)->list[i].list[j];
351 agxbprint(&xb, "%.5g,%.5g", ptf.x, yDir(ptf.y, offsets.Y));
352 }
353 }
354 agset(e, "pos", agxbuse(&xb));
355 if (ED_label(e)) {
356 ptf = ED_label(e)->pos;
357 agxbprint(&xb, "%.5g,%.5g", ptf.x, yDir(ptf.y, offsets.Y));
358 agset(e, "lp", agxbuse(&xb));
359 }
360 if (ED_xlabel(e) && ED_xlabel(e)->set) {
361 ptf = ED_xlabel(e)->pos;
362 agxbprint(&xb, "%.5g,%.5g", ptf.x, yDir(ptf.y, offsets.Y));
363 agset(e, "xlp", agxbuse(&xb));
364 }
365 if (ED_head_label(e)) {
366 ptf = ED_head_label(e)->pos;
367 agxbprint(&xb, "%.5g,%.5g", ptf.x, yDir(ptf.y, offsets.Y));
368 agset(e, "head_lp", agxbuse(&xb));
369 }
370 if (ED_tail_label(e)) {
371 ptf = ED_tail_label(e)->pos;
372 agxbprint(&xb, "%.5g,%.5g", ptf.x, yDir(ptf.y, offsets.Y));
373 agset(e, "tail_lp", agxbuse(&xb));
374 }
375 }
376 }
377 }
378 rec_attach_bb(g, bbsym, lpsym, lwsym, lhsym, offsets.Y);
379 agxbfree(&xb);
380
381 if (HAS_CLUST_EDGE(g))
383
384 if (sp != NULL) {
385 *sp = s_arrows;
386 }
387 if (ep != NULL) {
388 *ep = e_arrows;
389 }
390 gv_fixLocale (0);
391 return offsets.Y;
392}
393
395{
397}
398
static int agxbpop(agxbuf *xb)
removes last character added, if any
Definition agxbuf.h:111
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:78
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:234
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:307
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:277
#define M_PI
Definition arith.h:41
void undoClusterEdges(graph_t *g)
Definition utils.c:1035
char * late_nnstring(void *obj, attrsym_t *attr, char *defaultValue)
Definition utils.c:84
attrsym_t * safe_dcl(graph_t *g, int obj_kind, char *name, char *defaultValue)
Definition utils.c:1070
#define HEAD_LABEL
Definition const.h:177
#define EDGE_XLABEL
Definition const.h:181
#define GRAPH_LABEL
Definition const.h:179
#define TAIL_LABEL
Definition const.h:178
#define EDGE_LABEL
Definition const.h:176
#define IGNORED
Definition const.h:30
#define DEFAULT_COLOR
Definition const.h:48
#define DEFAULT_FILL
Definition const.h:69
#define GVSPLINES
Definition const.h:173
#define NODE_XLABEL
Definition const.h:180
void gv_fixLocale(int set)
Definition emit.c:3869
#define PS2INCH(a_points)
Definition geom.h:70
#define POINTS_PER_INCH
Definition geom.h:64
Agsym_t * N_width
Definition globals.h:73
int State
Definition globals.h:62
Agsym_t * E_style
Definition globals.h:83
Agsym_t * N_style
Definition globals.h:75
Agsym_t * E_color
Definition globals.h:81
Agsym_t * N_label
Definition globals.h:75
Agsym_t * N_fillcolor
Definition globals.h:73
Agsym_t * N_vertices
Definition globals.h:78
bool Y_invert
invert y in dot & plain output
Definition globals.h:66
Agsym_t * N_color
Definition globals.h:73
Agsym_t * N_height
Definition globals.h:73
require define api prefix
Definition gmlparse.y:17
node NULL
Definition grammar.y:163
int agset(void *obj, char *name, const char *value)
Definition attr.c:466
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:478
char * agget(void *obj, char *name)
Definition attr.c:439
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:455
#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
#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_n_cluster(g)
Definition types.h:389
#define GD_label(g)
Definition types.h:374
#define GD_odim(g)
Definition types.h:391
#define ND_ht(n)
Definition types.h:500
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_label(n)
Definition types.h:502
#define ND_rw(n)
Definition types.h:525
#define ND_height(n)
Definition types.h:498
#define ND_width(n)
Definition types.h:536
#define ND_lw(n)
Definition types.h:506
#define ND_xlabel(n)
Definition types.h:503
#define ND_shape_info(n)
Definition types.h:529
#define ND_pos(n)
Definition types.h:520
#define ND_coord(n)
Definition types.h:490
#define ND_shape(n)
Definition types.h:528
Agraph_t * agraphof(void *obj)
Definition obj.c:185
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:158
@ AGEDGE
Definition cgraph.h:207
@ AGNODE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
int agstrfree(Agraph_t *, const char *)
Definition refstr.c:139
char * agstrdup(Agraph_t *, const char *)
returns a pointer to a reference-counted copy of the argument string, creating one if necessary
Definition refstr.c:131
char * agcanonStr(char *str)
Definition write.c:239
void attach_attrs(graph_t *g)
Definition output.c:394
Graphviz context library.
textitem scanner parser str
Definition htmlparse.y:224
#define IS_CLUST_NODE(n)
Definition macros.h:23
#define HAS_CLUST_EDGE(g)
Definition macros.h:24
static void agputc(int(*putstr)(void *chan, const char *str), char c, FILE *fp)
Definition output.c:41
static void writenodeandport(int(*putstr)(void *chan, const char *str), FILE *f, node_t *node, char *portname)
Definition output.c:105
static void rec_attach_bb(graph_t *g, Agsym_t *bbsym, Agsym_t *lpsym, Agsym_t *lwsym, Agsym_t *lhsym, double yOff)
Definition output.c:207
static void printstring(int(*putstr)(void *chan, const char *str), FILE *f, char *prefix, char *s)
Definition output.c:47
static double YFDIR(offsets_t offsets, double y)
Definition output.c:28
double attach_attrs_and_arrows(graph_t *g, bool *sp, bool *ep)
Definition output.c:232
double yDir(double y, double Y_off)
Definition output.c:32
static void printint(int(*putstr)(void *chan, const char *str), FILE *f, char *prefix, size_t i)
Definition output.c:53
static void printpoint(int(*putstr)(void *chan, const char *str), FILE *f, pointf p, double yOff)
Definition output.c:73
static char * canon(graph_t *g, char *s)
Definition output.c:97
static void set_record_rects(node_t *n, field_t *f, agxbuf *xb, double yOff)
Definition output.c:193
void write_plain(GVJ_t *job, graph_t *g, FILE *f, bool extend)
Definition output.c:117
static void printdouble(int(*putstr)(void *chan, const char *str), FILE *f, char *prefix, double v)
Definition output.c:63
static offsets_t setYInvert(graph_t *g)
Definition output.c:85
static void agputs(int(*putstr)(void *chan, const char *str), const char *s, FILE *fp)
Definition output.c:36
#define PRISIZE_T
PRIu64 alike for printing size_t
Definition prisize_t.h:27
bool isPolygon(node_t *)
Definition shapes.c:1926
Agdisc_t disc
Definition cgraph.h:412
Agiodisc_t * io
Definition cgraph.h:339
int(* putstr)(void *chan, const char *str)
Definition cgraph.h:329
graph or subgraph
Definition cgraph.h:425
Agclos_t * clos
shared resources
Definition cgraph.h:435
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:637
double zoom
Definition gvcjob.h:318
Definition types.h:89
size_t size
Definition types.h:91
pointf * list
Definition types.h:90
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
int n_flds
Definition types.h:238
boxf b
Definition types.h:237
struct field_t ** fld
Definition types.h:240
state for offset calculations
Definition output.c:23
double YF
Y in inches
Definition output.c:25
double Y
ymin + ymax
Definition output.c:24
double x
Definition geom.h:29
double y
Definition geom.h:29
struct poly_s poly
Definition grammar.c:93