Graphviz  2.29.20120524.0446
lib/pack/ptest.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 #include <assert.h>
00015 #include "render.h"
00016 #include "neatoprocs.h"
00017 #include "pack.h"
00018 
00019 /* Test driver for libpack library.
00020  * Input consists of graphs in dot format.
00021  * If -c is not specified, the graphs must have pos information,
00022  * typically the output of one of the layout programs using -Tdot.
00023  *  -c computes connected components of input graphs
00024  *   Otherwise, ptest packs the input graphs.
00025  *  -s causes all the input graphs to be combined
00026  *   into a single output graph, ready to be sent to neato -s -n2.
00027  *   Otherwise, each graph is output separately, but with the
00028  *   appropriately adjusted coordinates.
00029  *  -e causes the packing to not use edge splines, if any.
00030  *   If any input graph does not have spline info, -e goes into 
00031  *   effect automatically.
00032  *  -m <i> specifies the margin, in points, about each graph.
00033  */
00034 char *Info[] = {
00035     "ptest",                    /* Program */
00036     "1.0",                      /* Version */
00037     DATE                        /* Build Date */
00038 };
00039 
00040 static int margin = 8;
00041 static int doEdges = 1;
00042 static int doComps = 0;
00043 static int verbose = 0;
00044 static char **Files = 0;
00045 static int nFiles = 0;
00046 static int single = 0;
00047 
00048 static char *useString = "Usage: ptest [-cesv?] [-m <margine>] <files>\n\
00049   -c - components\n\
00050   -e - no edges\n\
00051   -m n - set margine\n\
00052   -v - verbose\n\
00053   -s - single graph\n\
00054   -? - print usage\n\
00055 If no files are specified, stdin is used\n";
00056 
00057 static void usage(int v)
00058 {
00059     printf(useString);
00060     exit(v);
00061 }
00062 
00063 static void init(int argc, char *argv[])
00064 {
00065     int c;
00066 
00067     aginit();
00068     while ((c = getopt(argc, argv, ":escvm:?")) != -1) {
00069         switch (c) {
00070         case 'e':
00071             doEdges = 0;
00072             break;
00073         case 'c':
00074             doComps = 1;
00075             break;
00076         case 'm':
00077             margin = atoi(optarg);
00078             break;
00079         case 's':
00080             single = 1;
00081             break;
00082         case 'v':
00083             verbose = 1;
00084             Verbose = 1;
00085             break;
00086         case '?':
00087             if (optopt == '?')
00088                 usage(0);
00089             else
00090                 fprintf(stderr,
00091                         "ptest: option -%c unrecognized - ignored\n", c);
00092             break;
00093         }
00094     }
00095     argv += optind;
00096     argc -= optind;
00097 
00098     if (argc) {
00099         Files = argv;
00100         nFiles = argc;
00101     }
00102 
00103 }
00104 
00105 static int numFields(char *pos)
00106 {
00107     int cnt = 0;
00108     char c;
00109 
00110     while (isspace(*pos))
00111         pos++;
00112     while (*pos) {
00113         cnt++;
00114         while ((c = *pos) && !isspace(c))
00115             pos++;              /* skip token */
00116         while (isspace(*pos))
00117             pos++;
00118     }
00119     return cnt;
00120 }
00121 
00122 static point *user_spline(attrsym_t * symptr, edge_t * e, int *np)
00123 {
00124     char *pos;
00125     int i, n, nc;
00126     point *ps = 0;
00127     point *pp;
00128     double x, y;
00129 
00130     if (symptr == NULL)
00131         return 0;
00132     pos = agxget(e, symptr->index);
00133     if (*pos == '\0')
00134         return 0;
00135     n = numFields(pos);
00136     *np = n;
00137     if (n > 1) {
00138         ps = ALLOC(n, 0, point);
00139         pp = ps;
00140         while (n) {
00141             i = sscanf(pos, "%lf,%lf%n", &x, &y, &nc);
00142             if (i < 2) {
00143                 free(ps);
00144                 ps = 0;
00145                 break;
00146             }
00147             pos = pos + nc;
00148             pp->x = (int) x;
00149             pp->y = (int) y;
00150             pp++;
00151             n--;
00152         }
00153     }
00154     return ps;
00155 }
00156 
00157 static void initPos(Agraph_t * g)
00158 {
00159     Agnode_t *n;
00160     Agedge_t *e;
00161     double *pvec;
00162     char *p;
00163     point *sp;
00164     int pn;
00165     attrsym_t *N_pos = agfindnodeattr(g, "pos");
00166     attrsym_t *E_pos = agfindedgeattr(g, "pos");
00167 
00168     assert(N_pos);
00169     if (!E_pos) {
00170         if (doEdges)
00171             fprintf(stderr, "Warning: turning off doEdges, graph %s\n",
00172                     g->name);
00173         doEdges = 0;
00174     }
00175     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00176         pvec = ND_pos(n);
00177         p = agxget(n, N_pos->index);
00178         if (p[0] && (sscanf(p, "%lf,%lf", pvec, pvec + 1) == 2)) {
00179             int i;
00180             for (i = 0; i < NDIM; i++)
00181                 pvec[i] = pvec[i] / PSinputscale;
00182         } else {
00183             fprintf(stderr, "could not find pos for node %s in graph %s\n",
00184                     n->name, g->name);
00185             exit(1);
00186         }
00187         ND_coord_i(n).x = POINTS(ND_pos(n)[0]);
00188         ND_coord_i(n).y = POINTS(ND_pos(n)[1]);
00189     }
00190 
00191     if (doEdges) {
00192         for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00193             for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00194                 if ((sp = user_spline(E_pos, e, &pn)) != 0) {
00195                     clip_and_install(e, sp, pn);
00196                     free(sp);
00197                 } else {
00198                     fprintf(stderr,
00199                             "Missing edge pos for edge %s - %s in graph %s\n",
00200                             n->name, e->head->name, g->name);
00201                     exit(1);
00202                 }
00203             }
00204         }
00205     }
00206 }
00207 
00208 static void ptest_nodesize(node_t * n, boolean flip)
00209 {
00210     int w;
00211 
00212     w = ND_xsize(n) = POINTS(ND_width(n));
00213     ND_lw(n) = ND_rw(n) = w / 2;
00214     ND_ht(n) = ND_ysize(n) = POINTS(ND_height(n));
00215 }
00216 
00217 
00218 static void ptest_initNode(node_t * n)
00219 {
00220     char *str;
00221     ND_width(n) =
00222         late_double(n, N_width, DEFAULT_NODEWIDTH, MIN_NODEWIDTH);
00223     ND_height(n) =
00224         late_double(n, N_height, DEFAULT_NODEHEIGHT, MIN_NODEWIDTH);
00225     if (N_label == NULL)
00226         str = NODENAME_ESC;
00227     else
00228         str = agxget(n, N_label->index);
00229     str = strdup_and_subst(str, NODENAME_ESC, n->name);
00230     ND_label(n) = make_label(str,
00231                              late_double(n, N_fontsize, DEFAULT_FONTSIZE,
00232                                          MIN_FONTSIZE), late_nnstring(n,
00233                                                                       N_fontname,
00234                                                                       DEFAULT_FONTNAME),
00235                              late_nnstring(n, N_fontcolor, DEFAULT_COLOR),
00236                              n->graph);
00237     ND_shape(n) = bind_shape(late_nnstring(n, N_shape, DEFAULT_NODESHAPE));
00238     ND_shape(n)->initfn(n);     /* ### need to quantize ? */
00239     ptest_nodesize(n, n->GD_flip(graph));
00240 
00241 
00242 }
00243 
00244 static void ptest_initGraph(graph_t * g)
00245 {
00246     node_t *n;
00247     /* edge_t *e; */
00248 
00249     for (n = agfstnode(g); n; n = agnxtnode(g, n))
00250         ptest_initNode(n);
00251 /*
00252   for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
00253     for (e = agfstout(g,n); e; e = agnxtout(g,e)) ptest_initEdge(e);
00254   }
00255 */
00256 }
00257 
00258 static void dumpG(graph_t * g)
00259 {
00260     node_t *n;
00261     /* point  p; */
00262     edge_t *e;
00263 
00264     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00265         fprintf(stderr, " node %s \n", n->name);
00266 
00267         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00268             fprintf(stderr, " %s - %s \n", e->tail->name, e->head->name);
00269         }
00270 #ifdef OLD
00271         p = coord(n);
00272         fprintf(stderr, " %s pos (%f,%f) (%d,%d)\n",
00273                 n->name, ND_pos(n)[0], ND_pos(n)[1], p.x, p.y);
00274         fprintf(stderr, "   width %f height %f xsize %d ysize %d\n",
00275                 ND_width(n), ND_height(n), ND_xsize(n), ND_ysize(n));
00276 #endif
00277     }
00278 }
00279 
00280 static void copyPos(Agraph_t * g)
00281 {
00282     Agnode_t *n;
00283     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00284         ND_coord_i(n).x = POINTS(ND_pos(n)[0]);
00285         ND_coord_i(n).y = POINTS(ND_pos(n)[1]);
00286     }
00287 }
00288 
00289 main(int argc, char *argv[])
00290 {
00291     Agraph_t **gs;
00292     Agraph_t **ccs;
00293     Agraph_t *g;
00294     Agraph_t *gp;
00295     char *fname;
00296     FILE *fp;
00297     int cnt;
00298     int i;
00299 
00300     init(argc, argv);
00301     if (!Files) {
00302         fprintf(stderr, "No input files given\n");
00303         exit(1);
00304     }
00305 
00306     PSinputscale = POINTS_PER_INCH;
00307     if (doComps) {
00308         if (verbose)
00309             fprintf(stderr, "do Comps\n");
00310         while (fname = *Files++) {
00311             fp = fopen(fname, "r");
00312             if (!fp) {
00313                 fprintf(stderr, "Could not open %s\n", fname);
00314                 continue;
00315             }
00316             g = agread(fp);
00317             fclose(fp);
00318             if (!g) {
00319                 fprintf(stderr, "Could not read graph\n");
00320                 continue;
00321             }
00322             printf("%s %d nodes %d edges %sconnected\n",
00323                    g->name, agnnodes(g), agnedges(g),
00324                    (isConnected(g) ? "" : "not "));
00325             gs = ccomps(g, &cnt, "abc");
00326             for (i = 0; i < cnt; i++) {
00327                 gp = gs[i];
00328                 printf(" %s %d nodes %d edges\n", gp->name, agnnodes(gp),
00329                        agnedges(gp));
00330             }
00331         }
00332     } else {
00333         gs = N_GNEW(nFiles, Agraph_t *);
00334         cnt = 0;
00335         while (fname = Files[cnt]) {
00336             fp = fopen(fname, "r");
00337             if (!fp) {
00338                 fprintf(stderr, "Could not open %s\n", fname);
00339                 exit(1);
00340             }
00341             g = agread(fp);
00342             fclose(fp);
00343             if (!g) {
00344                 fprintf(stderr, "Could not read graph\n");
00345                 exit(1);
00346             }
00347             if (!single) {
00348                 graph_init(g);
00349                 ptest_initGraph(g);
00350             }
00351             initPos(g);
00352             /* if (Verbose) dumpG (g); */
00353             gs[cnt++] = g;
00354         }
00355         if (single) {
00356             Agraph_t *root;
00357             Agnode_t *n;
00358             Agnode_t *np;
00359             Agnode_t *tp;
00360             Agnode_t *hp;
00361             Agedge_t *e;
00362             Agedge_t *ep;
00363             root = agopen("root", 0);
00364             agedgeattr(root, "pos", "");
00365             for (i = 0; i < cnt; i++) {
00366                 g = gs[i];
00367                 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00368                     if (agfindnode(root, n->name)) {
00369                         fprintf(stderr,
00370                                 "Error: node %s in graph %d (%s) previously added\n",
00371                                 n->name, i, Files[i]);
00372                         exit(1);
00373                     }
00374                     np = agnode(root, n->name);
00375                     ND_pos(np)[0] = ND_pos(n)[0];
00376                     ND_pos(np)[1] = ND_pos(n)[1];
00377                     ND_coord_i(np).x = ND_coord_i(n).x;
00378                     ND_coord_i(np).y = ND_coord_i(n).y;
00379                 }
00380                 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00381                     tp = agfindnode(root, n->name);
00382                     for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00383                         hp = agfindnode(root, e->head->name);
00384                         ep = agedge(root, tp, hp);
00385                         ED_spl(ep) = ED_spl(e);
00386                     }
00387                 }
00388             }
00389             graph_init(root);
00390             ptest_initGraph(root);
00391             ccs = ccomps(root, &cnt, 0);
00392             packGraphs(cnt, ccs, root, margin, doEdges);
00393             if (!doEdges)
00394                 copyPos(root);
00395             else
00396                 State = GVSPLINES;
00397             attach_attrs(root);
00398             for (i = 0; i < cnt; i++) {
00399                 agdelete(root, ccs[i]);
00400             }
00401             agwrite(root, stdout);
00402         } else {
00403             packGraphs(cnt, gs, 0, margin, doEdges);
00404             if (doEdges)
00405                 State = GVSPLINES;
00406             for (i = 0; i < cnt; i++) {
00407                 if (!doEdges)
00408                     copyPos(gs[i]);
00409                 attach_attrs(gs[i]);
00410                 agwrite(gs[i], stdout);
00411             }
00412         }
00413     }
00414 }