Graphviz  2.35.20130930.0449
ptest.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 <assert.h>
15 #include "render.h"
16 #include "neatoprocs.h"
17 #include "pack.h"
18 
19 /* Test driver for libpack library.
20  * Input consists of graphs in dot format.
21  * If -c is not specified, the graphs must have pos information,
22  * typically the output of one of the layout programs using -Tdot.
23  * -c computes connected components of input graphs
24  * Otherwise, ptest packs the input graphs.
25  * -s causes all the input graphs to be combined
26  * into a single output graph, ready to be sent to neato -s -n2.
27  * Otherwise, each graph is output separately, but with the
28  * appropriately adjusted coordinates.
29  * -e causes the packing to not use edge splines, if any.
30  * If any input graph does not have spline info, -e goes into
31  * effect automatically.
32  * -m <i> specifies the margin, in points, about each graph.
33  */
34 char *Info[] = {
35  "ptest", /* Program */
36  "1.0", /* Version */
37  DATE /* Build Date */
38 };
39 
40 static int margin = 8;
41 static int doEdges = 1;
42 static int doComps = 0;
43 static int verbose = 0;
44 static char **Files = 0;
45 static int nFiles = 0;
46 static int single = 0;
47 
48 static char *useString = "Usage: ptest [-cesv?] [-m <margine>] <files>\n\
49  -c - components\n\
50  -e - no edges\n\
51  -m n - set margine\n\
52  -v - verbose\n\
53  -s - single graph\n\
54  -? - print usage\n\
55 If no files are specified, stdin is used\n";
56 
57 static void usage(int v)
58 {
59  printf(useString);
60  exit(v);
61 }
62 
63 static void init(int argc, char *argv[])
64 {
65  int c;
66 
67  aginit();
68  while ((c = getopt(argc, argv, ":escvm:?")) != -1) {
69  switch (c) {
70  case 'e':
71  doEdges = 0;
72  break;
73  case 'c':
74  doComps = 1;
75  break;
76  case 'm':
77  margin = atoi(optarg);
78  break;
79  case 's':
80  single = 1;
81  break;
82  case 'v':
83  verbose = 1;
84  Verbose = 1;
85  break;
86  case '?':
87  if (optopt == '?')
88  usage(0);
89  else
90  fprintf(stderr,
91  "ptest: option -%c unrecognized - ignored\n", c);
92  break;
93  }
94  }
95  argv += optind;
96  argc -= optind;
97 
98  if (argc) {
99  Files = argv;
100  nFiles = argc;
101  }
102 
103 }
104 
105 static int numFields(char *pos)
106 {
107  int cnt = 0;
108  char c;
109 
110  while (isspace(*pos))
111  pos++;
112  while (*pos) {
113  cnt++;
114  while ((c = *pos) && !isspace(c))
115  pos++; /* skip token */
116  while (isspace(*pos))
117  pos++;
118  }
119  return cnt;
120 }
121 
122 static point *user_spline(attrsym_t * symptr, edge_t * e, int *np)
123 {
124  char *pos;
125  int i, n, nc;
126  point *ps = 0;
127  point *pp;
128  double x, y;
129 
130  if (symptr == NULL)
131  return 0;
132  pos = agxget(e, symptr->index);
133  if (*pos == '\0')
134  return 0;
135  n = numFields(pos);
136  *np = n;
137  if (n > 1) {
138  ps = ALLOC(n, 0, point);
139  pp = ps;
140  while (n) {
141  i = sscanf(pos, "%lf,%lf%n", &x, &y, &nc);
142  if (i < 2) {
143  free(ps);
144  ps = 0;
145  break;
146  }
147  pos = pos + nc;
148  pp->x = (int) x;
149  pp->y = (int) y;
150  pp++;
151  n--;
152  }
153  }
154  return ps;
155 }
156 
157 static void initPos(Agraph_t * g)
158 {
159  Agnode_t *n;
160  Agedge_t *e;
161  double *pvec;
162  char *p;
163  point *sp;
164  int pn;
165  attrsym_t *N_pos = agfindnodeattr(g, "pos");
166  attrsym_t *E_pos = agfindedgeattr(g, "pos");
167 
168  assert(N_pos);
169  if (!E_pos) {
170  if (doEdges)
171  fprintf(stderr, "Warning: turning off doEdges, graph %s\n",
172  g->name);
173  doEdges = 0;
174  }
175  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
176  pvec = ND_pos(n);
177  p = agxget(n, N_pos->index);
178  if (p[0] && (sscanf(p, "%lf,%lf", pvec, pvec + 1) == 2)) {
179  int i;
180  for (i = 0; i < NDIM; i++)
181  pvec[i] = pvec[i] / PSinputscale;
182  } else {
183  fprintf(stderr, "could not find pos for node %s in graph %s\n",
184  n->name, g->name);
185  exit(1);
186  }
187  ND_coord_i(n).x = POINTS(ND_pos(n)[0]);
188  ND_coord_i(n).y = POINTS(ND_pos(n)[1]);
189  }
190 
191  if (doEdges) {
192  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
193  for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
194  if ((sp = user_spline(E_pos, e, &pn)) != 0) {
195  clip_and_install(e, sp, pn);
196  free(sp);
197  } else {
198  fprintf(stderr,
199  "Missing edge pos for edge %s - %s in graph %s\n",
200  n->name, e->head->name, g->name);
201  exit(1);
202  }
203  }
204  }
205  }
206 }
207 
208 static void ptest_nodesize(node_t * n, boolean flip)
209 {
210  int w;
211 
212  w = ND_xsize(n) = POINTS(ND_width(n));
213  ND_lw(n) = ND_rw(n) = w / 2;
214  ND_ht(n) = ND_ysize(n) = POINTS(ND_height(n));
215 }
216 
217 
218 static void ptest_initNode(node_t * n)
219 {
220  char *str;
221  ND_width(n) =
223  ND_height(n) =
225  if (N_label == NULL)
226  str = NODENAME_ESC;
227  else
228  str = agxget(n, N_label->index);
229  str = strdup_and_subst(str, NODENAME_ESC, n->name);
230  ND_label(n) = make_label(str,
233  N_fontname,
236  n->graph);
238  ND_shape(n)->initfn(n); /* ### need to quantize ? */
239  ptest_nodesize(n, n->GD_flip(graph));
240 
241 
242 }
243 
244 static void ptest_initGraph(graph_t * g)
245 {
246  node_t *n;
247  /* edge_t *e; */
248 
249  for (n = agfstnode(g); n; n = agnxtnode(g, n))
250  ptest_initNode(n);
251 /*
252  for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
253  for (e = agfstout(g,n); e; e = agnxtout(g,e)) ptest_initEdge(e);
254  }
255 */
256 }
257 
258 static void dumpG(graph_t * g)
259 {
260  node_t *n;
261  /* point p; */
262  edge_t *e;
263 
264  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
265  fprintf(stderr, " node %s \n", n->name);
266 
267  for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
268  fprintf(stderr, " %s - %s \n", e->tail->name, e->head->name);
269  }
270 #ifdef OLD
271  p = coord(n);
272  fprintf(stderr, " %s pos (%f,%f) (%d,%d)\n",
273  n->name, ND_pos(n)[0], ND_pos(n)[1], p.x, p.y);
274  fprintf(stderr, " width %f height %f xsize %d ysize %d\n",
275  ND_width(n), ND_height(n), ND_xsize(n), ND_ysize(n));
276 #endif
277  }
278 }
279 
280 static void copyPos(Agraph_t * g)
281 {
282  Agnode_t *n;
283  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
284  ND_coord_i(n).x = POINTS(ND_pos(n)[0]);
285  ND_coord_i(n).y = POINTS(ND_pos(n)[1]);
286  }
287 }
288 
289 main(int argc, char *argv[])
290 {
291  Agraph_t **gs;
292  Agraph_t **ccs;
293  Agraph_t *g;
294  Agraph_t *gp;
295  char *fname;
296  FILE *fp;
297  int cnt;
298  int i;
299 
300  init(argc, argv);
301  if (!Files) {
302  fprintf(stderr, "No input files given\n");
303  exit(1);
304  }
305 
306  PSinputscale = POINTS_PER_INCH;
307  if (doComps) {
308  if (verbose)
309  fprintf(stderr, "do Comps\n");
310  while (fname = *Files++) {
311  fp = fopen(fname, "r");
312  if (!fp) {
313  fprintf(stderr, "Could not open %s\n", fname);
314  continue;
315  }
316  g = agread(fp);
317  fclose(fp);
318  if (!g) {
319  fprintf(stderr, "Could not read graph\n");
320  continue;
321  }
322  printf("%s %d nodes %d edges %sconnected\n",
323  g->name, agnnodes(g), agnedges(g),
324  (isConnected(g) ? "" : "not "));
325  gs = ccomps(g, &cnt, "abc");
326  for (i = 0; i < cnt; i++) {
327  gp = gs[i];
328  printf(" %s %d nodes %d edges\n", gp->name, agnnodes(gp),
329  agnedges(gp));
330  }
331  }
332  } else {
333  gs = N_GNEW(nFiles, Agraph_t *);
334  cnt = 0;
335  while (fname = Files[cnt]) {
336  fp = fopen(fname, "r");
337  if (!fp) {
338  fprintf(stderr, "Could not open %s\n", fname);
339  exit(1);
340  }
341  g = agread(fp);
342  fclose(fp);
343  if (!g) {
344  fprintf(stderr, "Could not read graph\n");
345  exit(1);
346  }
347  if (!single) {
348  graph_init(g);
349  ptest_initGraph(g);
350  }
351  initPos(g);
352  /* if (Verbose) dumpG (g); */
353  gs[cnt++] = g;
354  }
355  if (single) {
356  Agraph_t *root;
357  Agnode_t *n;
358  Agnode_t *np;
359  Agnode_t *tp;
360  Agnode_t *hp;
361  Agedge_t *e;
362  Agedge_t *ep;
363  root = agopen("root", 0);
364  agedgeattr(root, "pos", "");
365  for (i = 0; i < cnt; i++) {
366  g = gs[i];
367  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
368  if (agfindnode(root, n->name)) {
369  fprintf(stderr,
370  "Error: node %s in graph %d (%s) previously added\n",
371  n->name, i, Files[i]);
372  exit(1);
373  }
374  np = agnode(root, n->name);
375  ND_pos(np)[0] = ND_pos(n)[0];
376  ND_pos(np)[1] = ND_pos(n)[1];
377  ND_coord_i(np).x = ND_coord_i(n).x;
378  ND_coord_i(np).y = ND_coord_i(n).y;
379  }
380  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
381  tp = agfindnode(root, n->name);
382  for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
383  hp = agfindnode(root, e->head->name);
384  ep = agedge(root, tp, hp);
385  ED_spl(ep) = ED_spl(e);
386  }
387  }
388  }
389  graph_init(root);
390  ptest_initGraph(root);
391  ccs = ccomps(root, &cnt, 0);
392  packGraphs(cnt, ccs, root, margin, doEdges);
393  if (!doEdges)
394  copyPos(root);
395  else
396  State = GVSPLINES;
397  attach_attrs(root);
398  for (i = 0; i < cnt; i++) {
399  agdelete(root, ccs[i]);
400  }
401  agwrite(root, stdout);
402  } else {
403  packGraphs(cnt, gs, 0, margin, doEdges);
404  if (doEdges)
405  State = GVSPLINES;
406  for (i = 0; i < cnt; i++) {
407  if (!doEdges)
408  copyPos(gs[i]);
409  attach_attrs(gs[i]);
410  agwrite(gs[i], stdout);
411  }
412  }
413  }
414 }