Graphviz  2.29.20120524.0446
lib/common/vtxgen.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 
00015 /*
00016  * vtxgen.c generates graph diagrams in the format for
00017  *  Confluents's Visual Thought
00018  */
00019 
00020 /*
00021  * If this time code is a pain to port, then just comment out the
00022  * next line.  It only provides an optional information field
00023  * in the (header...) block 
00024  */
00025 #define SUPPORT_WRITEDATE
00026 
00027 #include "render.h"
00028 #ifdef SUPPORT_WRITEDATE
00029 #include <time.h>
00030 #endif
00031 
00032 
00033 /* VTX font modifiers */
00034 #define REGULAR 0
00035 #define BOLD    1
00036 #define ITALIC  2
00037 #define UNDERSORE 4
00038 #define STRIKE 8
00039 
00040 /* VTX patterns */
00041 #define P_NONE  0
00042 #define P_SOLID 1
00043 #define P_DOTTED 2
00044 #define P_DASHED 3
00045 
00046 /* VTX bold line constant */
00047 #define WIDTH_NORMAL 1
00048 #define WIDTH_BOLD 3
00049 
00050 /* VTX shape mappings */
00051 typedef struct shapemap_s {
00052     char *shape;
00053     char *vtxshape;
00054 } shapemap_t;
00055 
00056 static shapemap_t shapemap[] = {
00057     {"box", "\"Rectangle\""},
00058     {"ellipse", "\"Ellipse\""},
00059     {"circle", "\"Ellipse\""},
00060     {"triangle", "\"Triangle\""},
00061     {"diamond", "\"Diamond\""},
00062     {"trapezium", "\"Trapezoid\""},
00063     {"parallelogram", "\"Parallelogram\""},
00064     {"hexagon", "\"Hexagon\""},
00065     {NULL, "\"Ellipse\""}       /* default */
00066 };
00067 
00068 
00069 static point Pages;
00070 static double Scale;
00071 static int Rot;
00072 /* static       box             PB; */
00073 static int onetime = TRUE;
00074 
00075 typedef struct context_t {
00076     int color_r, color_g, color_b;
00077     char *fontfam, fontopt, font_was_set;
00078     char pen, fill, penwidth, style_was_set;
00079     double fontsz;
00080 } context_t;
00081 
00082 #define MAXNEST 4
00083 static context_t cstk[MAXNEST];
00084 static int SP;
00085 
00086 static void vtx_reset(void)
00087 {
00088     onetime = TRUE;
00089 }
00090 
00091 
00092 static void init_vtx(void)
00093 {
00094     SP = 0;
00095     cstk[0].color_r = cstk[0].color_g = cstk[0].color_b = 0;
00096     cstk[0].fontfam = "Times";  /* font family name */
00097     cstk[0].fontopt = REGULAR;  /* modifier: REGULAR, BOLD or ITALIC */
00098     cstk[0].pen = P_SOLID;      /* pen pattern style, default is solid */
00099     cstk[0].fill = P_NONE;
00100     cstk[0].penwidth = WIDTH_NORMAL;
00101 }
00102 
00103 static pointf vtx_pt(pointf p)
00104 {
00105     pointf rv;
00106 
00107     if (Rot == 0) {
00108         rv.x = p.x;
00109         rv.y = p.y;
00110     } else {
00111         rv.x = p.y;
00112         rv.y = p.x;
00113     }
00114     return rv;
00115 }
00116 
00117 static void vtx_ptarray(point * A, int n)
00118 {
00119     int i;
00120     pointf p;
00121 
00122     fprintf(Output_file, "    (points\n");
00123     for (i = 0; i < n; i++) {
00124         p.x = (double) A[i].x;
00125         p.y = (double) A[i].y;
00126         p = vtx_pt(p);
00127         fprintf(Output_file, "      (%g %g)\n", p.x, p.y);
00128     }
00129     fprintf(Output_file, "    )\n");
00130 }
00131 
00132 static void vtx_bzptarray(point * A, int start, int end)
00133 {
00134     pointf p;
00135     int qx = 0, qy = 0;
00136     int i, j, incr = (start > end) ? -1 : 1;
00137 
00138     fprintf(Output_file, "    (points\n");
00139     for (i = start, j = 1; i != end; i += incr, j++) {
00140         switch (j % 3) {
00141         case 0:
00142             p.x = (double) A[i].x;
00143             p.y = (double) A[i].y;
00144             p = vtx_pt(p);
00145             fprintf(Output_file, "      (%g %g)\n", p.x, p.y);
00146             break;
00147         case 1:
00148 #if 1
00149             qx = A[i].x;
00150             qy = A[i].y;
00151 #else
00152             p.x = (double) A[i].x;
00153             p.y = (double) A[i].y;
00154             p = vtx_pt(p);
00155             fprintf(Output_file, "      (%g %g)\n", p.x, p.y);
00156 #endif
00157             break;
00158         case 2:
00159 #if 1
00160             /* undo EK's strange coding of straight segments */
00161             if (A[i].x == qx && A[i].y == qy) {
00162                 if ((A[i - 2].x == qx && A[i - 2].y == qy)
00163                     || (A[i + 1].x == qx && A[i + 1].y == qy)) {
00164                     p.x = (A[i + 1].x + A[i - 2].x) / 2.0;
00165                     p.y = (A[i + 1].y + A[i - 2].y) / 2.0;
00166                 } else {
00167                     p.x = (double) qx;
00168                     p.y = (double) qy;
00169                 }
00170             } else {
00171                 p.x = (A[i].x + qx) / 2.0;
00172                 p.y = (A[i].y + qy) / 2.0;
00173             }
00174 #else
00175             p.x = (double) A[i].x;
00176             p.y = (double) A[i].y;
00177 #endif
00178             p = vtx_pt(p);
00179             fprintf(Output_file, "      (%g %g)\n", p.x, p.y);
00180             break;
00181         }
00182     }
00183     fprintf(Output_file, "    )\n");
00184 }
00185 
00186 static void vtx_font(context_t * cp)
00187 {
00188 /* FIX
00189         char    *fw,*fa;
00190 
00191         fw = fa = "Regular";
00192         switch (cp->fontopt) {
00193                 case BOLD: fw = "Bold"; break;
00194                 case ITALIC: fa = "Italic"; break;
00195         }
00196 */
00197 }
00198 
00199 static void vtx_comment(char *str)
00200 {
00201     fprintf(Output_file, "; %s\n", str);
00202 }
00203 
00204 static void
00205 vtx_begin_job(FILE * ofp, graph_t * g, const char **lib, char *info[], point pages)
00206 {
00207     char *date = "";
00208 #ifdef SUPPORT_WRITEDATE
00209     time_t when;
00210     struct tm *tm;
00211     size_t date_length = 200;
00212 
00213     time(&when);
00214     tm = localtime(&when);
00215     date = N_GNEW(date_length, char);
00216     strftime(date, date_length, "%a %b %e %H:%M:%S %Z %Y", tm);
00217 #endif
00218 
00219     Pages = pages;
00220     /* N_pages = pages.x * pages.y; */
00221 
00222     fprintf(Output_file, "; Visual Thought 1.0\n"
00223             "\n"
00224             "(header\n"
00225             "  (program \"%s\")\n"
00226             "  (version \"%s\")\n"
00227             "  (buildDate \"%s\")\n"
00228             "  (writeDate \"%s\")\n"
00229             "  (documentPath \"\")\n"
00230             ")\n" "\n", info[0], info[1], info[2], date);
00231 
00232     free(date);
00233 }
00234 
00235 static void vtx_begin_graph(GVC_t * gvc, graph_t * g, box bb, point pb)
00236 {
00237     /* PB = bb; */
00238     if (onetime) {
00239         init_vtx();
00240         onetime = FALSE;
00241     }
00242 }
00243 
00244 static void
00245 vtx_begin_page(graph_t * g, point page, double scale, int rot,
00246                point offset)
00247 {
00248     int page_number;
00249     /* point        sz; */
00250 
00251     Scale = scale;
00252     Rot = rot;
00253     page_number = page.x + page.y * Pages.x + 1;
00254     /* sz = sub_points(PB.UR,PB.LL); */
00255 
00256     fprintf(Output_file, "(document\n"
00257             "  (palette F)\n"
00258             "  (layout\n"
00259             "    (page \"Letter\")\n"
00260             "    (units \"Inches\")\n"
00261             "    (orientation \"portrait\")\n"
00262             "    (numberOfPages %d %d)\n"
00263             "    (scale %g)\n"
00264             "    (margins 18 18 18 18)\n"
00265             "  )\n"
00266             ")\n"
00267             "\n"
00268             "(views\n"
00269             "  (view\n"
00270             "    (location 269 49)\n"
00271             "    (size 632 723)\n"
00272             "    (zoom %g)\n"
00273             "    (documentLocation 0 119)\n"
00274             "    (gridSnap T)\n"
00275             "    (gridVisibility F)\n"
00276             "    (gridSpacing 9)\n"
00277             "    (pageBreaks T)\n"
00278             "    (toolVisibility T)\n"
00279             "    (rulerVisibility T)\n"
00280             "  )\n"
00281             ")\n"
00282             "\n", page_number, Pages.x * Pages.y, scale * 100, scale);
00283 }
00284 
00285 static void vtx_begin_nodes(void)
00286 {
00287     fprintf(Output_file, "(shapes\n");
00288 }
00289 
00290 static void vtx_end_nodes(void)
00291 {
00292     fprintf(Output_file, ")\n" "\n");
00293 }
00294 
00295 static void vtx_begin_edges(void)
00296 {
00297     fprintf(Output_file, "(connections\n");
00298 }
00299 
00300 static void vtx_end_edges(void)
00301 {
00302     fprintf(Output_file, ")\n" "\n" "(groups\n" ")\n");
00303 }
00304 
00305 static void vtx_begin_node(node_t * n)
00306 {
00307     shapemap_t *p;
00308 
00309     for (p = shapemap; p->shape; p++) {
00310         if (streq(ND_shape(n)->name, p->shape)) {
00311             break;
00312         }
00313     }
00314 #ifndef WITH_CGRAPH
00315     fprintf(Output_file, "  (shape\n"
00316             "    (id %d)\n"
00317             "    (layer %d)\n"
00318             "    (type %s)\n", AGID(n) + 1, AGID(n), p->vtxshape);
00319 #else
00320     fprintf(Output_file, "  (shape\n"
00321             "    (id %ld)\n"
00322             "    (layer %ld)\n"
00323             "    (type %s)\n", AGID(n) + 1, AGID(n), p->vtxshape);
00324 #endif
00325 }
00326 
00327 static void vtx_end_node(void)
00328 {
00329     fprintf(Output_file, "  )\n");
00330 }
00331 
00332 static void vtx_begin_edge(edge_t * e)
00333 {
00334 #ifndef WITH_CGRAPH
00335     fprintf(Output_file, "  (connection\n"
00336             "    (id %d)\n"
00337             "    (layer %d)\n"
00338             "    (rotation 0)\n"
00339             "    (textRotation 0)\n"
00340             "    (locked F)\n"
00341             "    (start %d)\n"
00342             "    (end %d)\n",
00343             AGID(e) + 1, AGID(e), AGID(agtail(e)) + 1, AGID(aghead(e)) + 1);
00344 #else
00345     fprintf(Output_file, "  (connection\n"
00346             "    (id %ld)\n"
00347             "    (layer %ld)\n"
00348             "    (rotation 0)\n"
00349             "    (textRotation 0)\n"
00350             "    (locked F)\n"
00351             "    (start %ld)\n"
00352             "    (end %ld)\n",
00353             AGID(e) + 1, AGID(e), AGID(agtail(e)) + 1, AGID(aghead(e)) + 1);
00354 #endif
00355 }
00356 
00357 static void vtx_end_edge(void)
00358 {
00359     fprintf(Output_file, "  )\n");
00360 }
00361 
00362 static void vtx_begin_context(void)
00363 {
00364     assert(SP + 1 < MAXNEST);
00365     cstk[SP + 1] = cstk[SP];
00366     SP++;
00367 }
00368 
00369 static void vtx_end_context(void)
00370 {
00371     int psp = SP - 1;
00372 
00373     assert(SP > 0);
00374     SP = psp;
00375 }
00376 
00377 static void vtx_set_font(char *name, double size)
00378 {
00379     char *p, *q;
00380     context_t *cp;
00381 
00382     cp = &(cstk[SP]);
00383     cp->font_was_set = TRUE;
00384     cp->fontsz = size;
00385     p = strdup(name);
00386     if ((q = strchr(p, '-'))) {
00387         *q++ = 0;
00388         if (strcasecmp(q, "italic") == 0)
00389             cp->fontopt = ITALIC;
00390         else if (strcasecmp(q, "bold") == 0)
00391             cp->fontopt = BOLD;
00392     }
00393     cp->fontfam = p;
00394     vtx_font(&cstk[SP]);
00395 }
00396 
00397 static void vtx_style(void)
00398 {
00399     context_t *cp;
00400 
00401     cp = &(cstk[SP]);
00402     fprintf(Output_file, "    (style\n"
00403             "      (filled %s)\n"
00404             "      (fillColor %d %d %d)\n"
00405             "      (stroked T)\n"
00406             "      (strokeColor %d %d %d)\n"
00407             "      (lineWidth %d)\n"
00408             "      (shadowed F)\n"
00409             "      (shadowColor 39321 39321 39321)\n"
00410             "    )\n",
00411             cp->fill ? "T" : "F",
00412             cp->color_r, cp->color_g, cp->color_b,
00413             cp->color_r, cp->color_g, cp->color_b, cp->penwidth);
00414 }
00415 
00416 static void vtx_node_style(void)
00417 {
00418     fprintf(Output_file, "    (rotation 0)\n" "    (locked F)\n");
00419     vtx_style();
00420     fprintf(Output_file, "    (flipHorizontal F)\n"
00421             "    (flipVertical F)\n");
00422 }
00423 
00424 static void vtx_set_color(char *name)
00425 {
00426     gvcolor_t color;
00427     context_t *cp;
00428 
00429     cp = &(cstk[SP]);
00430     colorxlate(name, &color, RGBA_WORD);
00431     cp->color_r = color.u.rrggbbaa[0];
00432     cp->color_g = color.u.rrggbbaa[1];
00433     cp->color_b = color.u.rrggbbaa[2];
00434 }
00435 
00436 static void vtx_set_style(char **s)
00437 {
00438     char *line;
00439     context_t *cp;
00440 
00441     cp = &(cstk[SP]);
00442     while ((line = *s++)) {
00443         if (streq(line, "solid"))
00444             cp->pen = P_SOLID;
00445         else if (streq(line, "dashed"))
00446             cp->pen = P_DASHED;
00447         else if (streq(line, "dotted"))
00448             cp->pen = P_DOTTED;
00449         else if (streq(line, "invis"))
00450             cp->pen = P_NONE;
00451         else if (streq(line, "bold"))
00452             cp->penwidth = WIDTH_BOLD;
00453         else if (streq(line, "filled"))
00454             cp->fill = P_SOLID;
00455         else if (streq(line, "unfilled"))
00456             cp->fill = P_NONE;
00457         else {
00458             agerr(AGERR,
00459                   "vtx_set_style: unsupported style %s - ignoring\n",
00460                   line);
00461         }
00462         cp->style_was_set = TRUE;
00463     }
00464 }
00465 
00466 static char *vtx_string(char *s)
00467 {
00468     static char *buf = NULL;
00469     static int bufsize = 0;
00470     int pos = 0;
00471     char *p, esc;
00472 
00473     if (!buf) {
00474         bufsize = 64;
00475         buf = N_GNEW(bufsize, char);
00476     }
00477 
00478     p = buf;
00479     while (*s) {
00480         if (pos > (bufsize - 8)) {
00481             bufsize *= 2;
00482             buf = grealloc(buf, bufsize);
00483             p = buf + pos;
00484         }
00485         esc = 0;
00486         switch (*s) {
00487         case '\t':
00488             esc = 't';
00489             break;
00490         case '{':
00491         case '}':
00492         case '\\':
00493             esc = *s;
00494             break;
00495         }
00496         if (esc) {
00497             *p++ = '\\';
00498             *p++ = esc;
00499             pos += 2;
00500         } else {
00501             *p++ = *s;
00502             pos++;
00503         }
00504         s++;
00505     }
00506     *p = '\0';
00507     return buf;
00508 }
00509 
00510 static void vtx_textpara(point p, textpara_t * para)
00511 {
00512     pointf mp;
00513     double fontsz = Scale * cstk[SP].fontsz;
00514 
00515     if (cstk[SP].pen == P_NONE) {
00516         /* its invisible, don't draw */
00517         return;
00518     }
00519 
00520     mp.x = (double) p.x;
00521     mp.y = (double) (p.y - fontsz / 2 + 2);
00522     mp = vtx_pt(mp);
00523     if (Obj == EDGE) {
00524         fprintf(Output_file, "    (showText T)\n"
00525                 "    (textDistancePercentage 0.5)\n"
00526                 "    (textWidth 72)\n"
00527                 "    (textOffset 0)\n"
00528                 "    (rtfText{\\rtf1\\ansi\\deff0\n"
00529                 "{\\fonttbl{\\f0\\fnil helvetica medium;}}\n"
00530                 "{\\colortbl\\red0\\green0\\blue0;}\n"
00531                 "\\cf0\\plain\\pard {\\fs%d %s}})\n",
00532                 (int) ((fontsz * 2) - 8), vtx_string(para->str));
00533     } else {
00534         fprintf(Output_file, "    (showText T)\n"
00535                 "    (textVerticalAlignment \"left\")\n"
00536                 "    (rtfText{\\rtf1\\ansi\\deff0\n"
00537                 "{\\fonttbl{\\f0\\fnil helvetica medium;}}\n"
00538                 "{\\colortbl\\red0\\green0\\blue0;}\n"
00539                 "\\cf0\\plain\\pard {\\fs%d %s}})\n",
00540                 (int) ((fontsz * 2) - 8), vtx_string(para->str));
00541     }
00542 }
00543 
00544 static void vtx_bezier(point * A, int n, int arrow_at_start,
00545                        int arrow_at_end, int filled)
00546 {
00547     if (arrow_at_start) {
00548         vtx_bzptarray(A, n - 2, 0);
00549         fprintf(Output_file, "    (curved T)\n");
00550         vtx_style();
00551         fprintf(Output_file, "    (drawStartArrowhead %s)\n"
00552                 "    (drawEndArrowhead %s)\n"
00553                 "    (startArrowhead \"StandardArrow\")\n"
00554                 "    (endArrowhead \"StandardArrow\")\n",
00555                 arrow_at_end ? "T" : "F", arrow_at_start ? "T" : "F");
00556     } else {
00557         vtx_bzptarray(A, 1, n - 1);
00558         fprintf(Output_file, "    (curved T)\n");
00559         vtx_style();
00560         fprintf(Output_file, "    (drawStartArrowhead %s)\n"
00561                 "    (drawEndArrowhead %s)\n"
00562                 "    (startArrowhead \"StandardArrow\")\n"
00563                 "    (endArrowhead \"StandardArrow\")\n",
00564                 arrow_at_start ? "T" : "F", arrow_at_end ? "T" : "F");
00565     }
00566 }
00567 
00568 static void vtx_polygon(point * A, int n, int filled)
00569 {
00570     int i;
00571     pointf mp, max, min;
00572 
00573     mp.x = 0;
00574     mp.y = 0;
00575     max.x = min.x = (double) A[0].x;
00576     max.y = min.y = (double) A[0].y;
00577     for (i = 0; i < n; i++) {
00578         mp.x += (double) A[i].x;
00579         mp.y += (double) A[i].y;
00580         max.x = MAX(max.x, (double) A[i].x);
00581         max.y = MAX(max.y, (double) A[i].y);
00582         min.x = MIN(min.x, (double) A[i].x);
00583         min.y = MIN(min.y, (double) A[i].y);
00584     }
00585     mp.x /= n;
00586     mp.y /= n;
00587     mp = vtx_pt(mp);
00588     max = vtx_pt(max);
00589     min = vtx_pt(min);
00590     fprintf(Output_file, "    (location %g %g)\n"
00591             "    (size %g %g)\n",
00592             mp.x, mp.y, max.x - min.x, max.y - min.y);
00593     vtx_node_style();
00594 }
00595 
00596 static void vtx_ellipse(point p, int rx, int ry, int filled)
00597 {
00598     pointf mp;
00599 
00600     mp.x = (double) p.x;
00601     mp.y = (double) p.y;
00602     mp = vtx_pt(mp);
00603     fprintf(Output_file, "    (location %g %g)\n"
00604             "    (size %g %g)\n",
00605             mp.x, mp.y, (double) (rx + rx), (double) (ry + ry));
00606     vtx_node_style();
00607 }
00608 
00609 static void vtx_polyline(point * A, int n)
00610 {
00611     vtx_ptarray(A, n);
00612     fprintf(Output_file, "    (curved F)\n");
00613     vtx_style();
00614 }
00615 
00616 static void vtx_usershape(usershape_t *us, boxf b, point *A, int n, boolean filled)
00617 {
00618 /* FIXME */
00619     int i;
00620     pointf mp, max, min;
00621 
00622     mp.x = 0;
00623     mp.y = 0;
00624     max.x = min.x = (double) A[0].x;
00625     max.y = min.y = (double) A[0].y;
00626     for (i = 0; i < n; i++) {
00627         mp.x += (double) A[i].x;
00628         mp.y += (double) A[i].y;
00629         max.x = MAX(max.x, (double) A[i].x);
00630         max.y = MAX(max.y, (double) A[i].y);
00631         min.x = MIN(min.x, (double) A[i].x);
00632         min.y = MIN(min.y, (double) A[i].y);
00633     }
00634     mp.x /= n;
00635     mp.y /= n;
00636     mp = vtx_pt(mp);
00637     max = vtx_pt(max);
00638     min = vtx_pt(min);
00639     fprintf(Output_file, "    (location %g %g)\n"
00640             "    (size %g %g)\n",
00641             mp.x, mp.y, max.x - min.x, max.y - min.y);
00642     vtx_node_style();
00643 }
00644 
00645 codegen_t VTX_CodeGen = {
00646     vtx_reset,
00647     vtx_begin_job, 0,           /* vtx_end_job */
00648     vtx_begin_graph, 0,         /* vtx_end_graph */
00649     vtx_begin_page, 0,          /* vtx_end_page */
00650     0, /* vtx_begin_layer */ 0, /* vtx_end_layer */
00651     0, /* vtx_begin_cluster */ 0,       /* vtx_end_cluster */
00652     vtx_begin_nodes, vtx_end_nodes,
00653     vtx_begin_edges, vtx_end_edges,
00654     vtx_begin_node, vtx_end_node,
00655     vtx_begin_edge, vtx_end_edge,
00656     vtx_begin_context, vtx_end_context,
00657     0, /* vtx_begin_anchor */ 0,        /* vtx_end_anchor */
00658     vtx_set_font, vtx_textpara,
00659     vtx_set_color, vtx_set_color, vtx_set_style,
00660     vtx_ellipse, vtx_polygon,
00661     vtx_bezier, vtx_polyline,
00662     1,                          /* bezier_has_arrows */
00663     vtx_comment,
00664     vtx_usershape
00665 };