Graphviz  2.41.20170921.2350
output.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 #include "render.h"
15 #include "agxbuf.h"
16 #include <stdarg.h>
17 #include <string.h>
18 
19 #define YDIR(y) (Y_invert ? (Y_off - (y)) : (y))
20 #define YFDIR(y) (Y_invert ? (YF_off - (y)) : (y))
21 
22 static double Y_off; /* ymin + ymax */
23 static double YF_off; /* Y_off in inches */
24 
25 double yDir (double y)
26 {
27  return YDIR(y);
28 }
29 
30 static int (*putstr) (void *chan, const char *str);
31 
32 static void agputs (const char* s, FILE* fp)
33 {
34  putstr ((void*)fp, s);
35 }
36 static void agputc (int c, FILE* fp)
37 {
38  static char buf[2] = {'\0','\0'};
39  buf[0] = c;
40  putstr ((void*)fp, buf);
41 }
42 
43 
44 static void printstring(FILE * f, char *prefix, char *s)
45 {
46  if (prefix) agputs(prefix, f);
47  agputs(s, f);
48 }
49 
50 static void printint(FILE * f, char *prefix, int i)
51 {
52  char buf[BUFSIZ];
53 
54  if (prefix) agputs(prefix, f);
55  sprintf(buf, "%d", i);
56  agputs(buf, f);
57 }
58 
59 static void printdouble(FILE * f, char *prefix, double v)
60 {
61  char buf[BUFSIZ];
62 
63  if (prefix) agputs(prefix, f);
64  sprintf(buf, "%.5g", v);
65  agputs(buf, f);
66 }
67 
68 static void printpoint(FILE * f, pointf p)
69 {
70  printdouble(f, " ", PS2INCH(p.x));
71  printdouble(f, " ", PS2INCH(YDIR(p.y)));
72 }
73 
74 /* setYInvert:
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.
79  */
80 static void setYInvert(graph_t * g)
81 {
82  if (Y_invert) {
83  Y_off = GD_bb(g).UR.y + GD_bb(g).LL.y;
84  YF_off = PS2INCH(Y_off);
85  }
86 }
87 
88 /* canon:
89  * Canonicalize a string which may not have been allocated using agstrdup.
90  */
91 static char* canon (graph_t *g, char* s)
92 {
93  char* ns = agstrdup (g, s);
94  char* cs = agcanonStr (ns);
95  agstrfree (g, ns);
96  return cs;
97 }
98 
99 static void writenodeandport(FILE * f, node_t * node, char *port)
100 {
101  char *name;
102  if (IS_CLUST_NODE(node))
103  name = canon (agraphof(node), strchr(agnameof(node), ':') + 1);
104  else
105  name = agcanonStr (agnameof(node));
106  printstring(f, " ", name); /* slimey i know */
107  if (port && *port)
108  printstring(f, ":", agcanonStr(port));
109 }
110 
111 /* _write_plain:
112  */
113 void write_plain(GVJ_t * job, graph_t * g, FILE * f, boolean extend)
114 {
115  int i, j, splinePoints;
116  char *tport, *hport;
117  node_t *n;
118  edge_t *e;
119  bezier bz;
120  pointf pt;
121  char *lbl;
122  char* fillcolor;
123 
124  putstr = g->clos->disc.io->putstr;
125 // setup_graph(job, g);
126  setYInvert(g);
127  pt = GD_bb(g).UR;
128  printdouble(f, "graph ", job->zoom);
129  printdouble(f, " ", PS2INCH(pt.x));
130  printdouble(f, " ", PS2INCH(pt.y));
131  agputc('\n', f);
132  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
133  if (IS_CLUST_NODE(n))
134  continue;
135  printstring(f, "node ", agcanonStr(agnameof(n)));
136  printpoint(f, ND_coord(n));
137  if (ND_label(n)->html) /* if html, get original text */
138  lbl = agcanonStr (agxget(n, N_label));
139  else
140  lbl = canon(agraphof(n),ND_label(n)->text);
141  printdouble(f, " ", ND_width(n));
142  printdouble(f, " ", ND_height(n));
143  printstring(f, " ", lbl);
144  printstring(f, " ", late_nnstring(n, N_style, "solid"));
145  printstring(f, " ", ND_shape(n)->name);
146  printstring(f, " ", late_nnstring(n, N_color, DEFAULT_COLOR));
147  fillcolor = late_nnstring(n, N_fillcolor, "");
148  if (fillcolor[0] == '\0')
149  fillcolor = late_nnstring(n, N_color, DEFAULT_FILL);
150  printstring(f, " ", fillcolor);
151  agputc('\n', f);
152  }
153  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
154  for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
155 
156  if (extend) { //assuming these two attrs have already been created by cgraph
157  if (!(tport = agget(e,"tailport")))
158  tport = "";
159  if (!(hport = agget(e,"headport")))
160  hport = "";
161  }
162  else
163  tport = hport = "";
164  if (ED_spl(e)) {
165  splinePoints = 0;
166  for (i = 0; i < ED_spl(e)->size; i++) {
167  bz = ED_spl(e)->list[i];
168  splinePoints += bz.size;
169  }
170  printstring(f, NULL, "edge");
171  writenodeandport(f, agtail(e), tport);
172  writenodeandport(f, aghead(e), hport);
173  printint(f, " ", splinePoints);
174  for (i = 0; i < ED_spl(e)->size; i++) {
175  bz = ED_spl(e)->list[i];
176  for (j = 0; j < bz.size; j++)
177  printpoint(f, bz.list[j]);
178  }
179  }
180  if (ED_label(e)) {
181  printstring(f, " ", canon(agraphof(agtail(e)),ED_label(e)->text));
182  printpoint(f, ED_label(e)->pos);
183  }
184  printstring(f, " ", late_nnstring(e, E_style, "solid"));
185  printstring(f, " ", late_nnstring(e, E_color, DEFAULT_COLOR));
186  agputc('\n', f);
187  }
188  }
189  agputs("stop\n", f);
190 }
191 
192 static void set_record_rects(node_t * n, field_t * f, agxbuf * xb)
193 {
194  int i;
195  char buf[BUFSIZ];
196 
197  if (f->n_flds == 0) {
198  sprintf(buf, "%.5g,%.5g,%.5g,%.5g ",
199  f->b.LL.x + ND_coord(n).x,
200  YDIR(f->b.LL.y + ND_coord(n).y),
201  f->b.UR.x + ND_coord(n).x,
202  YDIR(f->b.UR.y + ND_coord(n).y));
203  agxbput(xb, buf);
204  }
205  for (i = 0; i < f->n_flds; i++)
206  set_record_rects(n, f->fld[i], xb);
207 }
208 
209 static void rec_attach_bb(graph_t * g, Agsym_t* bbsym, Agsym_t* lpsym, Agsym_t* lwsym, Agsym_t* lhsym)
210 {
211  int c;
212  char buf[BUFSIZ];
213  pointf pt;
214 
215  sprintf(buf, "%.5g,%.5g,%.5g,%.5g", GD_bb(g).LL.x, YDIR(GD_bb(g).LL.y),
216  GD_bb(g).UR.x, YDIR(GD_bb(g).UR.y));
217  agxset(g, bbsym, buf);
218  if (GD_label(g) && GD_label(g)->text[0]) {
219  pt = GD_label(g)->pos;
220  sprintf(buf, "%.5g,%.5g", pt.x, YDIR(pt.y));
221  agxset(g, lpsym, buf);
222  pt = GD_label(g)->dimen;
223  sprintf(buf, "%.2f", PS2INCH(pt.x));
224  agxset (g, lwsym, buf);
225  sprintf(buf, "%.2f", PS2INCH(pt.y));
226  agxset (g, lhsym, buf);
227  }
228  for (c = 1; c <= GD_n_cluster(g); c++)
229  rec_attach_bb(GD_clust(g)[c], bbsym, lpsym, lwsym, lhsym);
230 }
231 
232 void attach_attrs_and_arrows(graph_t* g, int* sp, int* ep)
233 {
234  int e_arrows; /* graph has edges with end arrows */
235  int s_arrows; /* graph has edges with start arrows */
236  int i, j, sides;
237  char buf[BUFSIZ]; /* Used only for small strings */
238  unsigned char xbuffer[BUFSIZ]; /* Initial buffer for xb */
239  agxbuf xb;
240  node_t *n;
241  edge_t *e;
242  pointf ptf;
243  int dim3 = (GD_odim(g) >= 3);
244  Agsym_t* bbsym = NULL;
245  Agsym_t* lpsym = NULL;
246  Agsym_t* lwsym = NULL;
247  Agsym_t* lhsym = NULL;
248 
249  gv_fixLocale (1);
250  e_arrows = s_arrows = 0;
251  setYInvert(g);
252  agxbinit(&xb, BUFSIZ, xbuffer);
253  safe_dcl(g, AGNODE, "pos", "");
254  safe_dcl(g, AGNODE, "rects", "");
255  N_width = safe_dcl(g, AGNODE, "width", "");
256  N_height = safe_dcl(g, AGNODE, "height", "");
257  safe_dcl(g, AGEDGE, "pos", "");
258  if (GD_has_labels(g) & NODE_XLABEL)
259  safe_dcl(g, AGNODE, "xlp", "");
260  if (GD_has_labels(g) & EDGE_LABEL)
261  safe_dcl(g, AGEDGE, "lp", "");
262  if (GD_has_labels(g) & EDGE_XLABEL)
263  safe_dcl(g, AGEDGE, "xlp", "");
264  if (GD_has_labels(g) & HEAD_LABEL)
265  safe_dcl(g, AGEDGE, "head_lp", "");
266  if (GD_has_labels(g) & TAIL_LABEL)
267  safe_dcl(g, AGEDGE, "tail_lp", "");
268  if (GD_has_labels(g) & GRAPH_LABEL) {
269  lpsym = safe_dcl(g, AGRAPH, "lp", "");
270  lwsym = safe_dcl(g, AGRAPH, "lwidth", "");
271  lhsym = safe_dcl(g, AGRAPH, "lheight", "");
272  }
273  bbsym = safe_dcl(g, AGRAPH, "bb", "");
274  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
275  if (dim3) {
276  int k;
277 
278  sprintf(buf, "%.5g,%.5g,%.5g", ND_coord(n).x, YDIR(ND_coord(n).y), POINTS_PER_INCH*(ND_pos(n)[2]));
279  agxbput (&xb, buf);
280  for (k = 3; k < GD_odim(g); k++) {
281  sprintf(buf, ",%.5g", POINTS_PER_INCH*(ND_pos(n)[k]));
282  agxbput (&xb, buf);
283  }
284  agset(n, "pos", agxbuse(&xb));
285  } else {
286  sprintf(buf, "%.5g,%.5g", ND_coord(n).x, YDIR(ND_coord(n).y));
287  agset(n, "pos", buf);
288  }
289  sprintf(buf, "%.5g", PS2INCH(ND_ht(n)));
290  agxset(n, N_height, buf);
291  sprintf(buf, "%.5g", PS2INCH(ND_lw(n) + ND_rw(n)));
292  agxset(n, N_width, buf);
293  if (ND_xlabel(n) && ND_xlabel(n)->set) {
294  ptf = ND_xlabel(n)->pos;
295  sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
296  agset(n, "xlp", buf);
297  }
298  if (strcmp(ND_shape(n)->name, "record") == 0) {
299  set_record_rects(n, ND_shape_info(n), &xb);
300  agxbpop(&xb); /* get rid of last space */
301  agset(n, "rects", agxbuse(&xb));
302  } else {
303  polygon_t *poly;
304  int i;
305  if (N_vertices && isPolygon(n)) {
306  poly = (polygon_t *) ND_shape_info(n);
307  sides = poly->sides;
308  if (sides < 3) {
309  char *p = agget(n, "samplepoints");
310  if (p)
311  sides = atoi(p);
312  else
313  sides = 8;
314  if (sides < 3)
315  sides = 8;
316  }
317  for (i = 0; i < sides; i++) {
318  if (i > 0)
319  agxbputc(&xb, ' ');
320  if (poly->sides >= 3)
321  sprintf(buf, "%.5g %.5g",
322  PS2INCH(poly->vertices[i].x),
323  YFDIR(PS2INCH(poly->vertices[i].y)));
324  else
325  sprintf(buf, "%.5g %.5g",
326  ND_width(n) / 2.0 * cos(i / (double) sides * M_PI * 2.0),
327  YFDIR(ND_height(n) / 2.0 * sin(i / (double) sides * M_PI * 2.0)));
328  agxbput(&xb, buf);
329  }
330  agxset(n, N_vertices, agxbuse(&xb));
331  }
332  }
333  if (State >= GVSPLINES) {
334  for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
335  if (ED_edge_type(e) == IGNORED)
336  continue;
337  if (ED_spl(e) == NULL)
338  continue; /* reported in postproc */
339  for (i = 0; i < ED_spl(e)->size; i++) {
340  if (i > 0)
341  agxbputc(&xb, ';');
342  if (ED_spl(e)->list[i].sflag) {
343  s_arrows = 1;
344  sprintf(buf, "s,%.5g,%.5g ",
345  ED_spl(e)->list[i].sp.x,
346  YDIR(ED_spl(e)->list[i].sp.y));
347  agxbput(&xb, buf);
348  }
349  if (ED_spl(e)->list[i].eflag) {
350  e_arrows = 1;
351  sprintf(buf, "e,%.5g,%.5g ",
352  ED_spl(e)->list[i].ep.x,
353  YDIR(ED_spl(e)->list[i].ep.y));
354  agxbput(&xb, buf);
355  }
356  for (j = 0; j < ED_spl(e)->list[i].size; j++) {
357  if (j > 0)
358  agxbputc(&xb, ' ');
359  ptf = ED_spl(e)->list[i].list[j];
360  sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
361  agxbput(&xb, buf);
362  }
363  }
364  agset(e, "pos", agxbuse(&xb));
365  if (ED_label(e)) {
366  ptf = ED_label(e)->pos;
367  sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
368  agset(e, "lp", buf);
369  }
370  if (ED_xlabel(e) && ED_xlabel(e)->set) {
371  ptf = ED_xlabel(e)->pos;
372  sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
373  agset(e, "xlp", buf);
374  }
375  if (ED_head_label(e)) {
376  ptf = ED_head_label(e)->pos;
377  sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
378  agset(e, "head_lp", buf);
379  }
380  if (ED_tail_label(e)) {
381  ptf = ED_tail_label(e)->pos;
382  sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
383  agset(e, "tail_lp", buf);
384  }
385  }
386  }
387  }
388  rec_attach_bb(g, bbsym, lpsym, lwsym, lhsym);
389  agxbfree(&xb);
390 
391  if (HAS_CLUST_EDGE(g))
392  undoClusterEdges(g);
393 
394  *sp = s_arrows;
395  *ep = e_arrows;
396  gv_fixLocale (0);
397 }
398 
400 {
401  int e, s;
402  attach_attrs_and_arrows (g, &s, &e);
403 }
404 
#define GD_label(g)
Definition: types.h:381
Definition: types.h:67
#define GD_has_labels(g)
Definition: types.h:372
attrsym_t * safe_dcl(graph_t *g, int obj_kind, char *name, char *def)
Definition: utils.c:1333
#define GRAPH_LABEL
Definition: const.h:187
#define ND_xlabel(n)
Definition: types.h:510
#define agxbuse(X)
Definition: agxbuf.h:83
int size
Definition: types.h:110
#define YDIR(y)
Definition: output.c:19
void gv_fixLocale(int set)
Definition: emit.c:4070
char * late_nnstring(void *obj, attrsym_t *attr, char *def)
Definition: utils.c:129
CGRAPH_API char * agcanonStr(char *str)
Definition: write.c:207
#define GD_n_cluster(g)
Definition: types.h:396
EXTERN int State
Definition: globals.h:80
Definition: types.h:245
EXTERN Agsym_t * N_label
Definition: globals.h:95
int agxset(void *obj, Agsym_t *sym, char *value)
Definition: attr.c:468
#define YFDIR(y)
Definition: output.c:20
EXTERN Agsym_t * N_height
Definition: globals.h:95
void undoClusterEdges(graph_t *g)
Definition: utils.c:1295
Definition: geom.h:28
size_t agxbput(agxbuf *xb, const char *s)
Definition: agxbuf.c:84
struct field_t ** fld
Definition: types.h:250
#define ED_label(e)
Definition: types.h:592
EXTERN int Y_invert
Definition: globals.h:84
#define GVSPLINES
Definition: const.h:181
#define ND_pos(n)
Definition: types.h:526
boxf b
Definition: types.h:247
Definition: gvcjob.h:271
CGRAPH_API Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition: edge.c:25
#define ND_shape_info(n)
Definition: types.h:535
#define ED_tail_label(e)
Definition: types.h:599
#define ND_label(n)
Definition: types.h:509
#define POINTS_PER_INCH
Definition: geom.h:62
EXTERN Agsym_t * N_style
Definition: globals.h:95
#define agxbputc(X, C)
Definition: agxbuf.h:77
#define PS2INCH(a_points)
Definition: geom.h:69
char * agget(void *obj, char *name)
Definition: attr.c:428
EXTERN Agsym_t * E_style
Definition: globals.h:107
CGRAPH_API Agraph_t * agraphof(void *obj)
Definition: obj.c:185
CGRAPH_API Agnode_t * agtail(Agedge_t *e)
Definition: edge.c:525
#define GD_odim(g)
Definition: types.h:399
void write_plain(GVJ_t *job, graph_t *g, FILE *f, boolean extend)
Definition: output.c:113
Agdisc_t disc
Definition: cgraph.h:229
int agxbpop(agxbuf *xb)
Definition: agxbuf.c:103
void attach_attrs_and_arrows(graph_t *g, int *sp, int *ep)
Definition: output.c:232
int agset(void *obj, char *name, char *value)
Definition: attr.c:455
CGRAPH_API Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition: node.c:45
int
Definition: grammar.c:1264
#define ED_spl(e)
Definition: types.h:598
#define TAIL_LABEL
Definition: const.h:186
#define ND_ht(n)
Definition: types.h:506
CGRAPH_API Agnode_t * aghead(Agedge_t *e)
Definition: edge.c:533
#define ND_shape(n)
Definition: types.h:534
#define NODE_XLABEL
Definition: const.h:188
double y
Definition: geom.h:28
CGRAPH_API char * agnameof(void *)
Definition: id.c:143
#define ND_height(n)
Definition: types.h:504
#define DEFAULT_COLOR
Definition: const.h:51
EXTERN Agsym_t * N_vertices
Definition: globals.h:95
htmllabel_t * lbl
Definition: htmlparse.c:81
int n_flds
Definition: types.h:248
#define ND_rw(n)
Definition: types.h:531
CGRAPH_API int agstrfree(Agraph_t *, char *)
Definition: refstr.c:149
double yDir(double y)
Definition: output.c:25
CGRAPH_API char * agstrdup(Agraph_t *, char *)
Definition: refstr.c:97
int sides
Definition: types.h:149
void agxbinit(agxbuf *xb, unsigned int hint, unsigned char *init)
Definition: agxbuf.c:25
pointf * list
Definition: types.h:109
CGRAPH_API Agnode_t * agfstnode(Agraph_t *g)
Definition: node.c:38
Definition: grammar.c:79
#define GD_clust(g)
Definition: types.h:364
#define AGNODE
Definition: cgraph.h:101
#define DEFAULT_FILL
Definition: const.h:72
EXTERN Agsym_t * N_color
Definition: globals.h:95
#define ND_width(n)
Definition: types.h:542
#define ND_lw(n)
Definition: types.h:513
#define NULL
Definition: logic.h:39
#define HEAD_LABEL
Definition: const.h:185
#define ED_head_label(e)
Definition: types.h:590
double x
Definition: geom.h:28
#define ED_xlabel(e)
Definition: types.h:593
#define ND_coord(n)
Definition: types.h:496
Definition: types.h:108
#define IGNORED
Definition: const.h:33
EXTERN Agsym_t * E_color
Definition: globals.h:107
Agnode_t * node(Agraph_t *g, char *name)
Definition: gv.cpp:103
pointf LL
Definition: geom.h:35
Agiodisc_t * io
Definition: cgraph.h:192
#define IS_CLUST_NODE(n)
Definition: macros.h:31
#define EDGE_XLABEL
Definition: const.h:189
pointf * vertices
Definition: types.h:154
#define GD_bb(g)
Definition: types.h:357
#define M_PI
Definition: arith.h:77
#define HAS_CLUST_EDGE(g)
Definition: macros.h:32
agxbuf * str
Definition: htmlparse.c:85
EXTERN Agsym_t * N_width
Definition: globals.h:95
int(* putstr)(void *chan, const char *str)
Definition: cgraph.h:184
Definition: agxbuf.h:34
boolean isPolygon(node_t *)
Definition: shapes.c:1840
char * agxget(void *obj, Agsym_t *sym)
Definition: attr.c:444
CGRAPH_API Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition: edge.c:40
Agclos_t * clos
Definition: cgraph.h:248
#define EDGE_LABEL
Definition: const.h:184
#define AGEDGE
Definition: cgraph.h:104
void attach_attrs(graph_t *g)
Definition: output.c:399
double zoom
Definition: gvcjob.h:327
#define ED_edge_type(e)
Definition: types.h:585
pointf UR
Definition: geom.h:35
void agxbfree(agxbuf *xb)
Definition: agxbuf.c:94
EXTERN Agsym_t * N_fillcolor
Definition: globals.h:95
#define AGRAPH
Definition: cgraph.h:100