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