1
/* $Id: output.c,v 1.71 2009/10/15 17:28:19 erg Exp $ $Revision: 1.71 $ */
2
/* vim:set shiftwidth=4 ts=8: */
4
/**********************************************************
5
* This software is part of the graphviz package *
6
* http://www.graphviz.org/ *
8
* Copyright (c) 1994-2004 AT&T Corp. *
9
* and is licensed under the *
10
* Common Public License, Version 1.0 *
13
* Information and Software Systems Research *
14
* AT&T Research, Florham Park NJ *
15
**********************************************************/
22
#define YDIR(y) (Y_invert ? (Y_off - (y)) : (y))
23
#define YFDIR(y) (Y_invert ? (YF_off - (y)) : (y))
25
int Y_off; /* ymin + ymax */
26
double YF_off; /* Y_off in inches */
29
static int (*putstr) (void *chan, const char *str);
31
static void agputs (const char* s, FILE* fp)
33
putstr ((void*)fp, s);
35
static void agputc (int c, FILE* fp)
37
static char buf[2] = {'\0','\0'};
39
putstr ((void*)fp, buf);
44
static void printstring(FILE * f, char *prefix, char *s)
46
if (prefix) agputs(prefix, f);
50
static void printint(FILE * f, char *prefix, int i)
54
if (prefix) agputs(prefix, f);
55
sprintf(buf, "%d", i);
59
static void printdouble(FILE * f, char *prefix, double v)
63
if (prefix) agputs(prefix, f);
64
sprintf(buf, "%.5g", v);
68
static void printpoint(FILE * f, pointf p)
70
printdouble(f, " ", PS2INCH(p.x));
71
printdouble(f, " ", PS2INCH(YDIR(p.y)));
75
* Set parameters used to flip coordinate system (y=0 at top).
76
* Values do not need to be unset, since if Y_invert is set, it's
77
* set for * all graphs during current run, so each will
78
* reinitialize the values for its bbox.
80
static void setYInvert(graph_t * g)
83
Y_off = ROUND(GD_bb(g).UR.y + GD_bb(g).LL.y);
84
YF_off = PS2INCH(Y_off);
89
* Canonicalize a string which may not have been allocated using agstrdup.
91
static char* canon (graph_t *g, char* s)
94
char* ns = agstrdup (s);
95
char* cs = agcanonStr (ns);
98
char* ns = agstrdup (g, s);
99
char* cs = agcanonStr (ns);
105
static void writenodeandport(FILE * f, node_t * node, char *port)
108
if (IS_CLUST_NODE(node))
109
name = canon (agraphof(node), strchr(agnameof(node), ':') + 1);
111
name = agcanonStr (agnameof(node));
112
printstring(f, " ", name); /* slimey i know */
114
printstring(f, ":", agcanonStr(port));
119
void write_plain(GVJ_t * job, graph_t * g, FILE * f, boolean extend)
121
int i, j, splinePoints;
130
putstr = g->clos->disc.io->putstr;
132
// setup_graph(job, g);
135
printdouble(f, "graph ", job->zoom);
136
printdouble(f, " ", PS2INCH(pt.x));
137
printdouble(f, " ", PS2INCH(pt.y));
139
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
140
if (IS_CLUST_NODE(n))
142
printstring(f, "node ", agcanonStr(agnameof(n)));
143
printpoint(f, ND_coord(n));
144
if (ND_label(n)->html) /* if html, get original text */
146
lbl = agcanonStr (agxget(n, N_label->index));
148
lbl = agcanonStr (agxget(n, N_label));
151
lbl = canon(agraphof(n),ND_label(n)->text);
152
printdouble(f, " ", ND_width(n));
153
printdouble(f, " ", ND_height(n));
154
printstring(f, " ", lbl);
155
printstring(f, " ", late_nnstring(n, N_style, "solid"));
156
printstring(f, " ", ND_shape(n)->name);
157
printstring(f, " ", late_nnstring(n, N_color, DEFAULT_COLOR));
158
printstring(f, " ", late_nnstring(n, N_fillcolor, DEFAULT_FILL));
161
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
162
for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
165
/* FIXME - there must be a proper way to get port info - these are
166
* supposed to be private to libgraph - from libgraph.h */
170
if (extend && e->attr) {
171
tport = e->attr[TAILX];
172
hport = e->attr[HEADX];
174
#else /* WITH_CGRAPH */
175
if (extend) { //assuming these two attrs have already been created by cgraph
176
if (!(tport = agget(e,"tailport")))
178
if (!(hport = agget(e,"headport")))
181
#endif /* WITH_CGRAPH */
186
for (i = 0; i < ED_spl(e)->size; i++) {
187
bz = ED_spl(e)->list[i];
188
splinePoints += bz.size;
190
printstring(f, NULL, "edge");
191
writenodeandport(f, agtail(e), tport);
192
writenodeandport(f, aghead(e), hport);
193
printint(f, " ", splinePoints);
194
for (i = 0; i < ED_spl(e)->size; i++) {
195
bz = ED_spl(e)->list[i];
196
for (j = 0; j < bz.size; j++)
197
printpoint(f, bz.list[j]);
201
printstring(f, " ", canon(agraphof(agtail(e)),ED_label(e)->text));
202
printpoint(f, ED_label(e)->pos);
204
printstring(f, " ", late_nnstring(e, E_style, "solid"));
205
printstring(f, " ", late_nnstring(e, E_color, DEFAULT_COLOR));
212
static void set_record_rects(node_t * n, field_t * f, agxbuf * xb)
217
if (f->n_flds == 0) {
218
sprintf(buf, "%.5g,%.5g,%.5g,%.5g ",
219
f->b.LL.x + ND_coord(n).x,
220
YFDIR(f->b.LL.y + ND_coord(n).y),
221
f->b.UR.x + ND_coord(n).x,
222
YFDIR(f->b.UR.y + ND_coord(n).y));
225
for (i = 0; i < f->n_flds; i++)
226
set_record_rects(n, f->fld[i], xb);
229
static void rec_attach_bb(graph_t * g, Agsym_t* bbsym)
235
sprintf(buf, "%.5g,%.5g,%.5g,%.5g", GD_bb(g).LL.x, YFDIR(GD_bb(g).LL.y),
236
GD_bb(g).UR.x, YFDIR(GD_bb(g).UR.y));
238
agxset(g, bbsym->index, buf);
240
agxset(g, bbsym, buf);
242
if (GD_label(g) && GD_label(g)->text[0]) {
243
pt = GD_label(g)->pos;
244
sprintf(buf, "%.5g,%.5g", pt.x, YFDIR(pt.y));
247
for (c = 1; c <= GD_n_cluster(g); c++)
248
rec_attach_bb(GD_clust(g)[c], bbsym);
251
void attach_attrs_and_arrows(graph_t* g, int* sp, int* ep)
253
int e_arrows; /* graph has edges with end arrows */
254
int s_arrows; /* graph has edges with start arrows */
256
char buf[BUFSIZ]; /* Used only for small strings */
257
unsigned char xbuffer[BUFSIZ]; /* Initial buffer for xb */
262
int dim3 = (GD_odim(g) >= 3);
266
e_arrows = s_arrows = 0;
268
agxbinit(&xb, BUFSIZ, xbuffer);
270
safe_dcl(g, g->proto->n, "pos", "", agnodeattr);
271
safe_dcl(g, g->proto->n, "rects", "", agnodeattr);
272
N_width = safe_dcl(g, g->proto->n, "width", "", agnodeattr);
273
N_height = safe_dcl(g, g->proto->n, "height", "", agnodeattr);
274
safe_dcl(g, g->proto->e, "pos", "", agedgeattr);
275
if (GD_has_labels(g) & NODE_XLABEL)
276
safe_dcl(g, g->proto->n, "xlp", "", agnodeattr);
277
if (GD_has_labels(g) & EDGE_LABEL)
278
safe_dcl(g, g->proto->e, "lp", "", agedgeattr);
279
if (GD_has_labels(g) & EDGE_XLABEL)
280
safe_dcl(g, g->proto->e, "xlp", "", agedgeattr);
281
if (GD_has_labels(g) & HEAD_LABEL)
282
safe_dcl(g, g->proto->e, "head_lp", "", agedgeattr);
283
if (GD_has_labels(g) & TAIL_LABEL)
284
safe_dcl(g, g->proto->e, "tail_lp", "", agedgeattr);
286
safe_dcl(g, g, "lp", "", agraphattr);
287
if (GD_label(g)->text[0]) {
288
ptf = GD_label(g)->pos;
289
sprintf(buf, "%.5g,%.5g", ptf.x, YFDIR(ptf.y));
293
bbsym = safe_dcl(g, g, "bb", "", agraphattr);
295
safe_dcl(g, AGNODE, "pos", "");
296
safe_dcl(g, AGNODE, "rects", "");
297
N_width = safe_dcl(g, AGNODE, "width", "");
298
N_height = safe_dcl(g, AGNODE, "height", "");
299
safe_dcl(g, AGEDGE, "pos", "");
300
if (GD_has_labels(g) & NODE_XLABEL)
301
safe_dcl(g, AGNODE, "xlp", "");
302
if (GD_has_labels(g) & EDGE_LABEL)
303
safe_dcl(g, AGEDGE, "lp", "");
304
if (GD_has_labels(g) & EDGE_XLABEL)
305
safe_dcl(g, AGEDGE, "xlp", "");
306
if (GD_has_labels(g) & HEAD_LABEL)
307
safe_dcl(g, AGEDGE, "head_lp", "");
308
if (GD_has_labels(g) & TAIL_LABEL)
309
safe_dcl(g, AGEDGE, "tail_lp", "");
311
safe_dcl(g, AGRAPH, "lp", "");
312
if (GD_label(g)->text[0]) {
313
ptf = GD_label(g)->pos;
314
sprintf(buf, "%.5g,%.5g", ptf.x, YFDIR(ptf.y));
318
bbsym = safe_dcl(g, AGRAPH, "bb", "");
320
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
322
sprintf(buf, "%.5g,%.5g,%.5g", ND_coord(n).x, YDIR(ND_coord(n).y), POINTS_PER_INCH*(ND_pos(n)[2]));
324
sprintf(buf, "%.5g,%.5g", ND_coord(n).x, YDIR(ND_coord(n).y));
326
agset(n, "pos", buf);
327
sprintf(buf, "%.5g", PS2INCH(ND_ht(n)));
329
agxset(n, N_height->index, buf);
330
sprintf(buf, "%.5g", PS2INCH(ND_lw(n) + ND_rw(n)));
331
agxset(n, N_width->index, buf);
333
agxset(n, N_height, buf);
334
sprintf(buf, "%.5g", PS2INCH(ND_lw(n) + ND_rw(n)));
335
agxset(n, N_width, buf);
338
ptf = ND_xlabel(n)->pos;
339
sprintf(buf, "%.5g,%.5g", ptf.x, YFDIR(ptf.y));
340
agset(n, "xlp", buf);
342
if (strcmp(ND_shape(n)->name, "record") == 0) {
343
set_record_rects(n, ND_shape_info(n), &xb);
344
agxbpop(&xb); /* get rid of last space */
345
agset(n, "rects", agxbuse(&xb));
349
if (N_vertices && isPolygon(n)) {
350
poly = (polygon_t *) ND_shape_info(n);
353
char *p = agget(n, "samplepoints");
361
for (i = 0; i < sides; i++) {
364
if (poly->sides >= 3)
365
sprintf(buf, "%.5g %.5g",
366
PS2INCH(poly->vertices[i].x),
367
YFDIR(PS2INCH(poly->vertices[i].y)));
369
sprintf(buf, "%.5g %.5g",
370
ND_width(n) / 2.0 * cos(i / (double) sides * M_PI * 2.0),
371
YFDIR(ND_height(n) / 2.0 * sin(i / (double) sides * M_PI * 2.0)));
375
agxset(n, N_vertices->index, agxbuse(&xb));
376
#else /* WITH_CGRAPH */
377
agxset(n, N_vertices, agxbuse(&xb));
378
#endif /* WITH_CGRAPH */
381
if (State >= GVSPLINES) {
382
for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
383
if (ED_edge_type(e) == IGNORED)
385
if (ED_spl(e) == NULL)
386
continue; /* reported in postproc */
387
for (i = 0; i < ED_spl(e)->size; i++) {
390
if (ED_spl(e)->list[i].sflag) {
392
sprintf(buf, "s,%.5g,%.5g ",
393
ED_spl(e)->list[i].sp.x,
394
YFDIR(ED_spl(e)->list[i].sp.y));
397
if (ED_spl(e)->list[i].eflag) {
399
sprintf(buf, "e,%.5g,%.5g ",
400
ED_spl(e)->list[i].ep.x,
401
YFDIR(ED_spl(e)->list[i].ep.y));
404
for (j = 0; j < ED_spl(e)->list[i].size; j++) {
407
ptf = ED_spl(e)->list[i].list[j];
408
sprintf(buf, "%.5g,%.5g", ptf.x, YFDIR(ptf.y));
412
agset(e, "pos", agxbuse(&xb));
414
ptf = ED_label(e)->pos;
415
sprintf(buf, "%.5g,%.5g", ptf.x, YFDIR(ptf.y));
419
ptf = ED_xlabel(e)->pos;
420
sprintf(buf, "%.5g,%.5g", ptf.x, YFDIR(ptf.y));
421
agset(e, "xlp", buf);
423
if (ED_head_label(e)) {
424
ptf = ED_head_label(e)->pos;
425
sprintf(buf, "%.5g,%.5g", ptf.x, YFDIR(ptf.y));
426
agset(e, "head_lp", buf);
428
if (ED_tail_label(e)) {
429
ptf = ED_tail_label(e)->pos;
430
sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
431
agset(e, "tail_lp", buf);
436
rec_attach_bb(g, bbsym);
439
if (HAS_CLUST_EDGE(g))
447
void attach_attrs(graph_t * g)
450
attach_attrs_and_arrows (g, &s, &e);
453
void output_point(agxbuf *xbuf, pointf p)
456
sprintf(buf, "%d %d ", ROUND(p.x), YDIR(ROUND(p.y)));