Graphviz 2.29.20120208.0545
lib/common/output.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 "render.h"
00015 #include "agxbuf.h"
00016 #include <stdarg.h>
00017 #include <string.h>
00018 
00019 #define YDIR(y) (Y_invert ? (Y_off - (y)) : (y))
00020 #define YFDIR(y) (Y_invert ? (YF_off - (y)) : (y))
00021 
00022 double Y_off;        /* ymin + ymax */
00023 double YF_off;       /* Y_off in inches */
00024 
00025 #ifdef WITH_CGRAPH
00026 static int (*putstr) (void *chan, const char *str);
00027 
00028 static void agputs (const char* s, FILE* fp)
00029 {
00030     putstr ((void*)fp, s);
00031 }
00032 static void agputc (int c, FILE* fp)
00033 {
00034     static char buf[2] = {'\0','\0'};
00035     buf[0] = c;
00036     putstr ((void*)fp, buf);
00037 }
00038 
00039 #endif
00040 
00041 static void printstring(FILE * f, char *prefix, char *s)
00042 {
00043     if (prefix) agputs(prefix, f);
00044     agputs(s, f);
00045 }
00046 
00047 static void printint(FILE * f, char *prefix, int i)
00048 {
00049     char buf[BUFSIZ];
00050     
00051     if (prefix) agputs(prefix, f);
00052     sprintf(buf, "%d", i);
00053     agputs(buf, f);
00054 }
00055 
00056 static void printdouble(FILE * f, char *prefix, double v)
00057 {
00058     char buf[BUFSIZ];
00059     
00060     if (prefix) agputs(prefix, f);
00061     sprintf(buf, "%.5g", v);
00062     agputs(buf, f);
00063 }
00064 
00065 static void printpoint(FILE * f, pointf p)
00066 {
00067     printdouble(f, " ", PS2INCH(p.x));
00068     printdouble(f, " ", PS2INCH(YDIR(p.y)));
00069 }
00070 
00071 /* setYInvert:
00072  * Set parameters used to flip coordinate system (y=0 at top).
00073  * Values do not need to be unset, since if Y_invert is set, it's
00074  * set for * all graphs during current run, so each will 
00075  * reinitialize the values for its bbox.
00076  */
00077 static void setYInvert(graph_t * g)
00078 {
00079     if (Y_invert) {
00080         Y_off = GD_bb(g).UR.y + GD_bb(g).LL.y;
00081         YF_off = PS2INCH(Y_off);
00082     }
00083 }
00084 
00085 /* canon:
00086  * Canonicalize a string which may not have been allocated using agstrdup.
00087  */
00088 static char* canon (graph_t *g, char* s)
00089 {
00090 #ifndef WITH_CGRAPH
00091     char* ns = agstrdup (s);
00092     char* cs = agcanonStr (ns);
00093     agstrfree (ns);
00094 #else
00095     char* ns = agstrdup (g, s);
00096     char* cs = agcanonStr (ns);
00097     agstrfree (g, ns);
00098 #endif
00099     return cs;
00100 }
00101 
00102 static void writenodeandport(FILE * f, node_t * node, char *port)
00103 {
00104     char *name;
00105     if (IS_CLUST_NODE(node))
00106         name = canon (agraphof(node), strchr(agnameof(node), ':') + 1);
00107     else
00108         name = agcanonStr (agnameof(node));
00109     printstring(f, " ", name); /* slimey i know */
00110     if (port && *port)
00111         printstring(f, ":", agcanonStr(port));
00112 }
00113 
00114 /* _write_plain:
00115  */
00116 void write_plain(GVJ_t * job, graph_t * g, FILE * f, boolean extend)
00117 {
00118     int i, j, splinePoints;
00119     char *tport, *hport;
00120     node_t *n;
00121     edge_t *e;
00122     bezier bz;
00123     pointf pt;
00124     char *lbl;
00125     char* fillcolor;
00126 
00127 #ifdef WITH_CGRAPH
00128     putstr = g->clos->disc.io->putstr;
00129 #endif
00130 //    setup_graph(job, g);
00131     setYInvert(g);
00132     pt = GD_bb(g).UR;
00133     printdouble(f, "graph ", job->zoom);
00134     printdouble(f, " ", PS2INCH(pt.x));
00135     printdouble(f, " ", PS2INCH(pt.y));
00136     agputc('\n', f);
00137     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00138         if (IS_CLUST_NODE(n))
00139             continue;
00140         printstring(f, "node ", agcanonStr(agnameof(n)));
00141         printpoint(f, ND_coord(n));
00142         if (ND_label(n)->html)   /* if html, get original text */
00143 #ifndef WITH_CGRAPH
00144             lbl = agcanonStr (agxget(n, N_label->index));
00145 #else
00146             lbl = agcanonStr (agxget(n, N_label));
00147 #endif
00148         else
00149             lbl = canon(agraphof(n),ND_label(n)->text);
00150         printdouble(f, " ", ND_width(n));
00151         printdouble(f, " ", ND_height(n));
00152         printstring(f, " ", lbl);
00153         printstring(f, " ", late_nnstring(n, N_style, "solid"));
00154         printstring(f, " ", ND_shape(n)->name);
00155         printstring(f, " ", late_nnstring(n, N_color, DEFAULT_COLOR));
00156         fillcolor = late_nnstring(n, N_fillcolor, "");
00157         if (fillcolor[0] == '\0')
00158             fillcolor = late_nnstring(n, N_color, DEFAULT_FILL);
00159         printstring(f, " ", fillcolor);
00160         agputc('\n', f);
00161     }
00162     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00163         for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00164 
00165 #ifndef WITH_CGRAPH
00166 /* FIXME - there must be a proper way to get port info - these are 
00167  * supposed to be private to libgraph - from libgraph.h */
00168 #define TAILX 1
00169 #define HEADX 2
00170 
00171             if (extend && e->attr) {
00172                 tport = e->attr[TAILX];
00173                 hport = e->attr[HEADX];
00174             }
00175 #else /* WITH_CGRAPH */
00176             if (extend) {               //assuming these two attrs have already been created by cgraph
00177                 if (!(tport = agget(e,"tailport")))
00178                     tport = "";
00179                 if (!(hport = agget(e,"headport")))
00180                     hport = "";
00181             }
00182 #endif /* WITH_CGRAPH */
00183             else
00184                 tport = hport = "";
00185             if (ED_spl(e)) {
00186                 splinePoints = 0;
00187                 for (i = 0; i < ED_spl(e)->size; i++) {
00188                     bz = ED_spl(e)->list[i];
00189                     splinePoints += bz.size;
00190                 }
00191                 printstring(f, NULL, "edge");
00192                 writenodeandport(f, agtail(e), tport);
00193                 writenodeandport(f, aghead(e), hport);
00194                 printint(f, " ", splinePoints);
00195                 for (i = 0; i < ED_spl(e)->size; i++) {
00196                     bz = ED_spl(e)->list[i];
00197                     for (j = 0; j < bz.size; j++)
00198                         printpoint(f, bz.list[j]);
00199                 }
00200             }
00201             if (ED_label(e)) {
00202                 printstring(f, " ", canon(agraphof(agtail(e)),ED_label(e)->text));
00203                 printpoint(f, ED_label(e)->pos);
00204             }
00205             printstring(f, " ", late_nnstring(e, E_style, "solid"));
00206             printstring(f, " ", late_nnstring(e, E_color, DEFAULT_COLOR));
00207             agputc('\n', f);
00208         }
00209     }
00210     agputs("stop\n", f);
00211 }
00212 
00213 static void set_record_rects(node_t * n, field_t * f, agxbuf * xb)
00214 {
00215     int i;
00216     char buf[BUFSIZ];
00217 
00218     if (f->n_flds == 0) {
00219         sprintf(buf, "%.5g,%.5g,%.5g,%.5g ",
00220                 f->b.LL.x + ND_coord(n).x,
00221                 YDIR(f->b.LL.y + ND_coord(n).y),
00222                 f->b.UR.x + ND_coord(n).x,
00223                 YDIR(f->b.UR.y + ND_coord(n).y));
00224         agxbput(xb, buf);
00225     }
00226     for (i = 0; i < f->n_flds; i++)
00227         set_record_rects(n, f->fld[i], xb);
00228 }
00229 
00230 static void rec_attach_bb(graph_t * g, Agsym_t* bbsym)
00231 {
00232     int c;
00233     char buf[BUFSIZ];
00234     pointf pt;
00235 
00236     sprintf(buf, "%.5g,%.5g,%.5g,%.5g", GD_bb(g).LL.x, YDIR(GD_bb(g).LL.y),
00237             GD_bb(g).UR.x, YDIR(GD_bb(g).UR.y));
00238 #ifndef WITH_CGRAPH
00239     agxset(g, bbsym->index, buf);
00240 #else
00241     agxset(g, bbsym, buf);
00242 #endif
00243     if (GD_label(g) && GD_label(g)->text[0]) {
00244         pt = GD_label(g)->pos;
00245         sprintf(buf, "%.5g,%.5g", pt.x, YDIR(pt.y));
00246         agset(g, "lp", buf);
00247         pt = GD_label(g)->dimen;
00248         sprintf(buf, "%.2f", PS2INCH(pt.x));
00249         agset (g, "lwidth", buf);
00250         sprintf(buf, "%.2f", PS2INCH(pt.y));
00251         agset (g, "lheight", buf);
00252     }
00253     for (c = 1; c <= GD_n_cluster(g); c++)
00254         rec_attach_bb(GD_clust(g)[c], bbsym);
00255 }
00256 
00257 void attach_attrs_and_arrows(graph_t* g, int* sp, int* ep)
00258 {
00259     int e_arrows;               /* graph has edges with end arrows */
00260     int s_arrows;               /* graph has edges with start arrows */
00261     int i, j, sides;
00262     char buf[BUFSIZ];           /* Used only for small strings */
00263     unsigned char xbuffer[BUFSIZ];      /* Initial buffer for xb */
00264     agxbuf xb;
00265     node_t *n;
00266     edge_t *e;
00267     pointf ptf;
00268     int dim3 = (GD_odim(g) >= 3);
00269     Agsym_t* bbsym;
00270 
00271     gv_fixLocale (1);
00272     e_arrows = s_arrows = 0;
00273     setYInvert(g);
00274     agxbinit(&xb, BUFSIZ, xbuffer);
00275 #ifndef WITH_CGRAPH
00276     safe_dcl(g, g->proto->n, "pos", "", agnodeattr);
00277     safe_dcl(g, g->proto->n, "rects", "", agnodeattr);
00278     N_width = safe_dcl(g, g->proto->n, "width", "", agnodeattr);
00279     N_height = safe_dcl(g, g->proto->n, "height", "", agnodeattr);
00280     safe_dcl(g, g->proto->e, "pos", "", agedgeattr);
00281     if (GD_has_labels(g) & NODE_XLABEL)
00282         safe_dcl(g, g->proto->n, "xlp", "", agnodeattr);
00283     if (GD_has_labels(g) & EDGE_LABEL)
00284         safe_dcl(g, g->proto->e, "lp", "", agedgeattr);
00285     if (GD_has_labels(g) & EDGE_XLABEL)
00286         safe_dcl(g, g->proto->e, "xlp", "", agedgeattr);
00287     if (GD_has_labels(g) & HEAD_LABEL)
00288         safe_dcl(g, g->proto->e, "head_lp", "", agedgeattr);
00289     if (GD_has_labels(g) & TAIL_LABEL)
00290         safe_dcl(g, g->proto->e, "tail_lp", "", agedgeattr);
00291     if (GD_label(g)) {
00292         safe_dcl(g, g, "lp", "", agraphattr);
00293         safe_dcl(g, g, "lwidth", "", agraphattr);
00294         safe_dcl(g, g, "lheight", "", agraphattr);
00295         if (GD_label(g)->text[0]) {
00296             ptf = GD_label(g)->pos;
00297             sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
00298             agset(g, "lp", buf);
00299             ptf = GD_label(g)->dimen;
00300             sprintf(buf, "%.2f", PS2INCH(ptf.x));
00301             agset(g, "lwidth", buf);
00302             sprintf(buf, "%.2f", PS2INCH(ptf.y));
00303             agset(g, "lheight", buf);
00304         }
00305     }
00306     bbsym = safe_dcl(g, g, "bb", "", agraphattr);
00307 #else
00308     safe_dcl(g, AGNODE, "pos", "");
00309     safe_dcl(g, AGNODE, "rects", "");
00310     N_width = safe_dcl(g, AGNODE, "width", "");
00311     N_height = safe_dcl(g, AGNODE, "height", "");
00312     safe_dcl(g, AGEDGE, "pos", "");
00313     if (GD_has_labels(g) & NODE_XLABEL)
00314         safe_dcl(g, AGNODE, "xlp", "");
00315     if (GD_has_labels(g) & EDGE_LABEL)
00316         safe_dcl(g, AGEDGE, "lp", "");
00317     if (GD_has_labels(g) & EDGE_XLABEL)
00318         safe_dcl(g, AGEDGE, "xlp", "");
00319     if (GD_has_labels(g) & HEAD_LABEL)
00320         safe_dcl(g, AGEDGE, "head_lp", "");
00321     if (GD_has_labels(g) & TAIL_LABEL)
00322         safe_dcl(g, AGEDGE, "tail_lp", "");
00323     if (GD_label(g)) {
00324         safe_dcl(g, AGRAPH, "lp", "");
00325         safe_dcl(g, AGRAPH, "lwidth", "");
00326         safe_dcl(g, AGRAPH, "lheight", "");
00327         if (GD_label(g)->text[0]) {
00328             ptf = GD_label(g)->pos;
00329             sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
00330             agset(g, "lp", buf);
00331             ptf = GD_label(g)->dimen;
00332             sprintf(buf, "%.2f", PS2INCH(ptf.x));
00333             agset(g, "lwidth", buf);
00334             sprintf(buf, "%.2f", PS2INCH(ptf.y));
00335             agset(g, "lheight", buf);
00336         }
00337     }
00338     bbsym = safe_dcl(g, AGRAPH, "bb", "");
00339 #endif
00340     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00341         if (dim3) {
00342             int k;
00343 
00344             sprintf(buf, "%.5g,%.5g,%.5g", ND_coord(n).x, YDIR(ND_coord(n).y), POINTS_PER_INCH*(ND_pos(n)[2]));
00345             agxbput (&xb, buf);
00346             for (k = 3; k < GD_odim(g); k++) {
00347                 sprintf(buf, ",%.5g", POINTS_PER_INCH*(ND_pos(n)[k]));
00348                 agxbput (&xb, buf);
00349             }
00350             agset(n, "pos", agxbuse(&xb));
00351         } else {
00352             sprintf(buf, "%.5g,%.5g", ND_coord(n).x, YDIR(ND_coord(n).y));
00353             agset(n, "pos", buf);
00354         }
00355         sprintf(buf, "%.5g", PS2INCH(ND_ht(n)));
00356 #ifndef WITH_CGRAPH
00357         agxset(n, N_height->index, buf);
00358         sprintf(buf, "%.5g", PS2INCH(ND_lw(n) + ND_rw(n)));
00359         agxset(n, N_width->index, buf);
00360 #else
00361         agxset(n, N_height, buf);
00362         sprintf(buf, "%.5g", PS2INCH(ND_lw(n) + ND_rw(n)));
00363         agxset(n, N_width, buf);
00364 #endif
00365         if (ND_xlabel(n) && ND_xlabel(n)->set) {
00366             ptf = ND_xlabel(n)->pos;
00367             sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
00368             agset(n, "xlp", buf);
00369         }
00370         if (strcmp(ND_shape(n)->name, "record") == 0) {
00371             set_record_rects(n, ND_shape_info(n), &xb);
00372             agxbpop(&xb);       /* get rid of last space */
00373             agset(n, "rects", agxbuse(&xb));
00374         } else {
00375             polygon_t *poly;
00376             int i;
00377             if (N_vertices && isPolygon(n)) {
00378                 poly = (polygon_t *) ND_shape_info(n);
00379                 sides = poly->sides;
00380                 if (sides < 3) {
00381                     char *p = agget(n, "samplepoints");
00382                     if (p)
00383                         sides = atoi(p);
00384                     else
00385                         sides = 8;
00386                     if (sides < 3)
00387                         sides = 8;
00388                 }
00389                 for (i = 0; i < sides; i++) {
00390                     if (i > 0)
00391                         agxbputc(&xb, ' ');
00392                     if (poly->sides >= 3)
00393                         sprintf(buf, "%.5g %.5g",
00394                                 PS2INCH(poly->vertices[i].x),
00395                                 YFDIR(PS2INCH(poly->vertices[i].y)));
00396                     else
00397                         sprintf(buf, "%.5g %.5g",
00398                                 ND_width(n) / 2.0 * cos(i / (double) sides * M_PI * 2.0),
00399                                 YFDIR(ND_height(n) / 2.0 * sin(i / (double) sides * M_PI * 2.0)));
00400                     agxbput(&xb, buf);
00401                 }
00402 #ifndef WITH_CGRAPH
00403                 agxset(n, N_vertices->index, agxbuse(&xb));
00404 #else /* WITH_CGRAPH */
00405                 agxset(n, N_vertices, agxbuse(&xb));
00406 #endif /* WITH_CGRAPH */
00407             }
00408         }
00409         if (State >= GVSPLINES) {
00410             for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
00411                 if (ED_edge_type(e) == IGNORED)
00412                     continue;
00413                 if (ED_spl(e) == NULL)
00414                     continue;   /* reported in postproc */
00415                 for (i = 0; i < ED_spl(e)->size; i++) {
00416                     if (i > 0)
00417                         agxbputc(&xb, ';');
00418                     if (ED_spl(e)->list[i].sflag) {
00419                         s_arrows = 1;
00420                         sprintf(buf, "s,%.5g,%.5g ",
00421                                 ED_spl(e)->list[i].sp.x,
00422                                 YDIR(ED_spl(e)->list[i].sp.y));
00423                         agxbput(&xb, buf);
00424                     }
00425                     if (ED_spl(e)->list[i].eflag) {
00426                         e_arrows = 1;
00427                         sprintf(buf, "e,%.5g,%.5g ",
00428                                 ED_spl(e)->list[i].ep.x,
00429                                 YDIR(ED_spl(e)->list[i].ep.y));
00430                         agxbput(&xb, buf);
00431                     }
00432                     for (j = 0; j < ED_spl(e)->list[i].size; j++) {
00433                         if (j > 0)
00434                             agxbputc(&xb, ' ');
00435                         ptf = ED_spl(e)->list[i].list[j];
00436                         sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
00437                         agxbput(&xb, buf);
00438                     }
00439                 }
00440                 agset(e, "pos", agxbuse(&xb));
00441                 if (ED_label(e)) {
00442                     ptf = ED_label(e)->pos;
00443                     sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
00444                     agset(e, "lp", buf);
00445                 }
00446                 if (ED_xlabel(e) && ED_xlabel(e)->set) {
00447                     ptf = ED_xlabel(e)->pos;
00448                     sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
00449                     agset(e, "xlp", buf);
00450                 }
00451                 if (ED_head_label(e)) {
00452                     ptf = ED_head_label(e)->pos;
00453                     sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
00454                     agset(e, "head_lp", buf);
00455                 }
00456                 if (ED_tail_label(e)) {
00457                     ptf = ED_tail_label(e)->pos;
00458                     sprintf(buf, "%.5g,%.5g", ptf.x, YDIR(ptf.y));
00459                     agset(e, "tail_lp", buf);
00460                 }
00461             }
00462         }
00463     }
00464     rec_attach_bb(g, bbsym);
00465     agxbfree(&xb);
00466 
00467     if (HAS_CLUST_EDGE(g))
00468         undoClusterEdges(g);
00469     
00470     *sp = s_arrows;
00471     *ep = e_arrows;
00472     gv_fixLocale (0);
00473 }
00474 
00475 void attach_attrs(graph_t * g)
00476 {
00477     int e, s;
00478     attach_attrs_and_arrows (g, &s, &e);
00479 }
00480 
00481 void output_point(agxbuf *xbuf, pointf p)
00482 {
00483     char buf[BUFSIZ];
00484     sprintf(buf, "%d %d ", ROUND(p.x), ROUND(YDIR(p.y)));
00485     agxbput(xbuf, buf);
00486 }
00487