Graphviz  2.29.20120523.0446
lib/common/diagen.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 #ifdef HAVE_CONFIG_H
00015 #include "config.h"
00016 #endif
00017 
00018 #include "render.h"
00019 
00020 #include <stdarg.h>
00021 #ifdef HAVE_UNISTD_H
00022 #include <unistd.h>
00023 #endif
00024 #ifdef HAVE_LIBZ
00025 #include <zlib.h>
00026 #endif
00027 
00028 /* DIA font modifiers */
00029 #define REGULAR 0
00030 #define BOLD    1
00031 #define ITALIC  2
00032 
00033 /* DIA patterns */
00034 #define P_SOLID 0
00035 #define P_NONE  15
00036 #define P_DOTTED 4              /* i wasn't sure about this */
00037 #define P_DASHED 11             /* or this */
00038 
00039 /* DIA bold line constant */
00040 #define WIDTH_NORMAL 1
00041 #define WIDTH_BOLD 3
00042 
00043 #define DIA_RESOLUTION 1.0
00044 #define SCALE (DIA_RESOLUTION/15.0)
00045 
00046 #define         NODE            1
00047 #define         EDGE            2
00048 #define         CLST            3
00049 
00050 
00051 /* FIXME - these are not used currently - probably something missing */
00052 #if 0
00053 /* DIA dash array */
00054 static char *sdarray = "5,2";
00055 /* DIA dot array */
00056 static char *sdotarray = "1,5";
00057 static int GraphURL, ClusterURL, NodeURL, EdgeURL;
00058 static char *op[] = { "graph", "node", "edge", "graph" };
00059 #endif
00060 
00061 /* static       int             N_pages; */
00062 /* static       point   Pages; */
00063 static double Scale;
00064 static pointf Offset;
00065 static int Rot;
00066 static box PB;
00067 static int onetime = TRUE;
00068 
00069 static node_t *Curnode;
00070 static edge_t *Curedge;
00071 static graph_t *Curgraph, *Rootgraph;
00072 
00073 typedef struct context_t {
00074     char *pencolor, *fillcolor, *fontfam, fontopt, font_was_set;
00075     char pen, fill, penwidth, style_was_set;
00076     double fontsz;
00077 } context_t;
00078 
00079 #define MAXNEST 4
00080 static context_t cstk[MAXNEST];
00081 static int SP;
00082 
00083 #ifdef HAVE_LIBZ
00084 static gzFile Zfile;
00085 #endif
00086 
00087 static int dia_fputs(char *s)
00088 {
00089     int len;
00090 
00091     len = strlen(s);
00092 
00093 #ifdef HAVE_LIBZ
00094     return gzwrite(Zfile, s, (unsigned) len);
00095 #else
00096     return 0;
00097 #endif
00098 }
00099 
00100 
00101 /* dia_printf:
00102  * Note that this function is unsafe due to the fixed buffer size.
00103  * It should only be used when the caller is sure the input will not
00104  * overflow the buffer. In particular, it should be avoided for
00105  * input coming from users. Also, if vsnprintf is available, the
00106  * code should check for return values to use it safely.
00107  */
00108 static int dia_printf(const char *format, ...)
00109 {
00110     char buf[BUFSIZ];
00111     va_list argp;
00112     int len;
00113 
00114     va_start(argp, format);
00115 #ifdef HAVE_VSNPRINTF
00116     (void) vsnprintf(buf, sizeof(buf), format, argp);
00117 #else
00118     (void) vsprintf(buf, format, argp);
00119 #endif
00120     va_end(argp);
00121     len = strlen(buf);
00122 
00123     /* some *sprintf (e.g C99 std)
00124        don't return the number of
00125        bytes actually written */
00126 
00127 #ifdef HAVE_LIBZ
00128     return gzwrite(Zfile, buf, (unsigned) len);
00129 #else
00130     return 0;
00131 #endif
00132 }
00133 
00134 #define SVG_COLORS_P 0
00135 
00136 static int dia_comparestr(const void *s1, const void *s2)
00137 {
00138         return strcmp(*(char **) s1, *(char **) s2);
00139 }
00140 
00141 static char *dia_resolve_color(char *name)
00142 {
00143 /* color names from http://www.w3.org/TR/SVG/types.html */
00144 /* NB.  List must be LANG_C sorted */
00145     static char *svg_known_colors[] = {
00146         "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
00147         "beige", "bisque", "black", "blanchedalmond", "blue",
00148         "blueviolet", "brown", "burlywood",
00149         "cadetblue", "chartreuse", "chocolate", "coral",
00150         "cornflowerblue", "cornsilk", "crimson", "cyan",
00151         "darkblue", "darkcyan", "darkgoldenrod", "darkgray",
00152         "darkgreen", "darkgrey", "darkkhaki", "darkmagenta",
00153         "darkolivegreen", "darkorange", "darkorchid", "darkred",
00154         "darksalmon", "darkseagreen", "darkslateblue", "darkslategray",
00155         "darkslategrey", "darkturquoise", "darkviolet", "deeppink",
00156         "deepskyblue", "dimgray", "dimgrey", "dodgerblue",
00157         "firebrick", "floralwhite", "forestgreen", "fuchsia",
00158         "gainsboro", "ghostwhite", "gold", "goldenrod", "gray",
00159         "green", "greenyellow", "grey",
00160         "honeydew", "hotpink", "indianred",
00161         "indigo", "ivory", "khaki",
00162         "lavender", "lavenderblush", "lawngreen", "lemonchiffon",
00163         "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow",
00164         "lightgray", "lightgreen", "lightgrey", "lightpink",
00165         "lightsalmon", "lightseagreen", "lightskyblue",
00166         "lightslategray", "lightslategrey", "lightsteelblue",
00167         "lightyellow", "lime", "limegreen", "linen",
00168         "magenta", "maroon", "mediumaquamarine", "mediumblue",
00169         "mediumorchid", "mediumpurple", "mediumseagreen",
00170         "mediumslateblue", "mediumspringgreen", "mediumturquoise",
00171         "mediumvioletred", "midnightblue", "mintcream",
00172         "mistyrose", "moccasin",
00173         "navajowhite", "navy", "oldlace",
00174         "olive", "olivedrab", "orange", "orangered", "orchid",
00175         "palegoldenrod", "palegreen", "paleturquoise",
00176         "palevioletred", "papayawhip", "peachpuff", "peru", "pink",
00177         "plum", "powderblue", "purple",
00178         "red", "rosybrown", "royalblue",
00179         "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell",
00180         "sienna", "silver", "skyblue", "slateblue", "slategray",
00181         "slategrey", "snow", "springgreen", "steelblue",
00182         "tan", "teal", "thistle", "tomato", "turquoise",
00183         "violet",
00184         "wheat", "white", "whitesmoke",
00185         "yellow", "yellowgreen",
00186     };
00187 
00188     static char buf[SMALLBUF];
00189     char *tok;
00190     gvcolor_t color;
00191 
00192     tok = canontoken(name);
00193     if (!SVG_COLORS_P || (bsearch(&tok, svg_known_colors,
00194                               sizeof(svg_known_colors) / sizeof(char *),
00195                               sizeof(char *), dia_comparestr) == NULL)) {
00196         /* if tok was not found in known_colors */
00197         if (streq(tok, "transparent")) {
00198             tok = "none";
00199         } else {
00200             colorxlate(name, &color, RGBA_BYTE);
00201             sprintf(buf, "#%02x%02x%02x",
00202                     color.u.rgba[0], color.u.rgba[1], color.u.rgba[2]);
00203             tok = buf;
00204         }
00205     }
00206     return tok;
00207 }
00208 
00209 
00210 static void dia_reset(void)
00211 {
00212     onetime = TRUE;
00213 }
00214 
00215 
00216 static void init_dia(void)
00217 {
00218     SP = 0;
00219     cstk[0].pencolor = DEFAULT_COLOR;   /* DIA pencolor */
00220     cstk[0].fillcolor = "";     /* DIA fillcolor */
00221     cstk[0].fontfam = DEFAULT_FONTNAME; /* font family name */
00222     cstk[0].fontsz = DEFAULT_FONTSIZE;  /* font size */
00223     cstk[0].fontopt = REGULAR;  /* modifier: REGULAR, BOLD or ITALIC */
00224     cstk[0].pen = P_SOLID;      /* pen pattern style, default is solid */
00225     cstk[0].fill = P_NONE;
00226     cstk[0].penwidth = WIDTH_NORMAL;
00227 }
00228 
00229 static pointf diapt(point p)
00230 {
00231     pointf rv;
00232 
00233     if (Rot == 0) {
00234         rv.x = PB.LL.x + p.x * Scale + Offset.x;
00235         rv.y = PB.UR.y - 1 - p.y * Scale - Offset.y;
00236     } else {
00237         rv.x = PB.UR.x - 1 - p.y * Scale - Offset.x;
00238         rv.y = PB.UR.y - 1 - p.x * Scale - Offset.y;
00239     }
00240     return rv;
00241 }
00242 
00243 static pointf diaptf(pointf p)
00244 {
00245     pointf rv;
00246 
00247     if (Rot == 0) {
00248         rv.x = PB.LL.x + p.x * Scale + Offset.x;
00249         rv.y = PB.UR.y - 1 - p.y * Scale - Offset.y;
00250     } else {
00251         rv.x = PB.UR.x - 1 - p.y * Scale - Offset.x;
00252         rv.y = PB.UR.y - 1 - p.x * Scale - Offset.y;
00253     }
00254     return rv;
00255 }
00256 
00257 static void dia_grstyle(context_t * cp)
00258 {
00259     if (strcmp(cp->pencolor, DEFAULT_COLOR)) {
00260         dia_fputs("      <dia:attribute name=\"border_color\">\n");
00261         dia_printf("        <dia:color val=\"%s\"/>\n",
00262                    dia_resolve_color(cp->pencolor));
00263         dia_fputs("      </dia:attribute>\n");
00264     }
00265     if (cp->penwidth != WIDTH_NORMAL) {
00266         dia_fputs("      <dia:attribute name=\"line_width\">\n");
00267         dia_printf("        <dia:real val=\"%g\"/>\n",
00268                    Scale * (cp->penwidth));
00269         dia_fputs("      </dia:attribute>\n");
00270     }
00271     if (cp->pen == P_DASHED) {
00272         dia_fputs("      <dia:attribute name=\"line_style\">\n");
00273         dia_printf("        <dia:real val=\"%d\"/>\n", 1);
00274         dia_fputs("      </dia:attribute>\n");
00275 #if 0
00276     } else if (cp->pen == P_DOTTED) {
00277         dia_printf("stroke-dasharray:%s;", sdotarray);
00278 #endif
00279     }
00280 }
00281 
00282 static void dia_grstylefill(context_t * cp, int filled)
00283 {
00284     if (filled) {
00285         dia_fputs("      <dia:attribute name=\"inner_color\">\n");
00286         dia_printf("        <dia:color val=\"%s\"/>\n",
00287                    dia_resolve_color(cp->fillcolor));
00288         dia_fputs("      </dia:attribute>\n");
00289     } else {
00290         dia_fputs("      <dia:attribute name=\"show_background\">\n");
00291         dia_printf("        <dia:boolean val=\"%s\"/>\n", "true");
00292         dia_fputs("      </dia:attribute>\n");
00293     }
00294 }
00295 
00296 static void dia_comment(char *str)
00297 {
00298     dia_fputs("<!-- ");
00299     dia_fputs(xml_string(str));
00300     dia_fputs(" -->\n");
00301 }
00302 
00303 static void
00304 dia_begin_job(FILE * ofp, graph_t * g, const char **lib, char *info[], point pages)
00305 {
00306 #if HAVE_LIBZ
00307     int fd;
00308 
00309     fd = dup(fileno(Output_file));      /* open dup so can gzclose 
00310                                            independent of FILE close */
00311     Zfile = gzdopen(fd, "wb");
00312     if (!Zfile) {
00313         agerr(AGERR, "Error opening compressed output file\n");
00314         exit(1);
00315     }
00316 #else
00317     agerr(AGERR,
00318           "No support for compressed output. Not compiled with zlib.\n");
00319     exit(1);
00320 #endif
00321 
00322 /*      Pages = pages; */
00323 /*      N_pages = pages.x * pages.y; */
00324     dia_printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
00325 
00326 }
00327 
00328 static void dia_end_job(void)
00329 {
00330 }
00331 
00332 static void dia_begin_graph(GVC_t * gvc, graph_t * g, box bb, point pb)
00333 {
00334     Rootgraph = g;
00335     PB.LL.x = PB.LL.y = 0;
00336     PB.UR.x = (bb.UR.x - bb.LL.x + 2 * GD_drawing(g)->margin.x) * SCALE;
00337     PB.UR.y = (bb.UR.y - bb.LL.y + 2 * GD_drawing(g)->margin.y) * SCALE;
00338     Offset.x = GD_drawing(g)->margin.x * SCALE;
00339     Offset.y = GD_drawing(g)->margin.y * SCALE;
00340     if (onetime) {
00341         init_dia();
00342         onetime = FALSE;
00343     }
00344     dia_fputs
00345         ("<dia:diagram xmlns:dia=\"http://www.lysator.liu.se/~alla/dia/\">\n");
00346     dia_fputs("  <dia:diagramdata>\n");
00347     dia_fputs("    <dia:attribute name=\"background\">\n");
00348     dia_fputs("      <dia:color val=\"#ffffff\"/>\n");
00349     dia_fputs("    </dia:attribute>\n");
00350     dia_fputs("    <dia:attribute name=\"paper\">\n");
00351     dia_fputs("      <dia:composite type=\"paper\">\n");
00352     dia_fputs("        <dia:attribute name=\"name\">\n");
00353     dia_fputs("          <dia:string>#A4#</dia:string>\n");
00354     dia_fputs("        </dia:attribute>\n");
00355     dia_fputs("        <dia:attribute name=\"tmargin\">\n");
00356     dia_fputs("          <dia:real val=\"2.8222\"/>\n");
00357     dia_fputs("        </dia:attribute>\n");
00358     dia_fputs("        <dia:attribute name=\"bmargin\">\n");
00359     dia_fputs("          <dia:real val=\"2.8222\"/>\n");
00360     dia_fputs("        </dia:attribute>\n");
00361     dia_fputs("        <dia:attribute name=\"lmargin\">\n");
00362     dia_fputs("          <dia:real val=\"2.8222\"/>\n");
00363     dia_fputs("        </dia:attribute>\n");
00364     dia_fputs("        <dia:attribute name=\"rmargin\">\n");
00365     dia_fputs("          <dia:real val=\"2.8222\"/>\n");
00366     dia_fputs("        </dia:attribute>\n");
00367     dia_fputs("        <dia:attribute name=\"is_portrait\">\n");
00368     dia_fputs("          <dia:boolean val=\"true\"/>\n");
00369     dia_fputs("        </dia:attribute>\n");
00370     dia_fputs("        <dia:attribute name=\"scaling\">\n");
00371     dia_fputs("          <dia:real val=\"1\"/>\n");
00372     dia_fputs("        </dia:attribute>\n");
00373     dia_fputs("        <dia:attribute name=\"fitto\">\n");
00374     dia_fputs("          <dia:boolean val=\"false\"/>\n");
00375     dia_fputs("        </dia:attribute>\n");
00376     dia_fputs("      </dia:composite>\n");
00377     dia_fputs("    </dia:attribute>\n");
00378     dia_fputs("    <dia:attribute name=\"grid\">\n");
00379     dia_fputs("      <dia:composite type=\"grid\">\n");
00380     dia_fputs("        <dia:attribute name=\"width_x\">\n");
00381     dia_fputs("          <dia:real val=\"1\"/>\n");
00382     dia_fputs("        </dia:attribute>\n");
00383     dia_fputs("        <dia:attribute name=\"width_y\">\n");
00384     dia_fputs("          <dia:real val=\"1\"/>\n");
00385     dia_fputs("        </dia:attribute>\n");
00386     dia_fputs("        <dia:attribute name=\"visible_x\">\n");
00387     dia_fputs("          <dia:int val=\"1\"/>\n");
00388     dia_fputs("        </dia:attribute>\n");
00389     dia_fputs("        <dia:attribute name=\"visible_y\">\n");
00390     dia_fputs("          <dia:int val=\"1\"/>\n");
00391     dia_fputs("        </dia:attribute>\n");
00392     dia_fputs("      </dia:composite>\n");
00393     dia_fputs("    </dia:attribute>\n");
00394     dia_fputs("    <dia:attribute name=\"guides\">\n");
00395     dia_fputs("      <dia:composite type=\"guides\">\n");
00396     dia_fputs("        <dia:attribute name=\"hguides\"/>\n");
00397     dia_fputs("        <dia:attribute name=\"vguides\"/>\n");
00398     dia_fputs("      </dia:composite>\n");
00399     dia_fputs("    </dia:attribute>\n");
00400     dia_fputs("  </dia:diagramdata>\n");
00401 }
00402 
00403 static void dia_end_graph(void)
00404 {
00405     dia_printf("</dia:diagram>\n");
00406 #ifdef HAVE_LIBZ
00407     gzclose(Zfile);
00408 #endif
00409 }
00410 
00411 static void
00412 dia_begin_page(graph_t * g, point page, double scale, int rot,
00413                point offset)
00414 {
00415     /* int          page_number; */
00416     /* point        sz; */
00417 
00418     Scale = scale * SCALE;
00419     Rot = rot;
00420     /* page_number =  page.x + page.y * Pages.x + 1; */
00421     /* sz = sub_points(PB.UR,PB.LL); */
00422 
00423     dia_printf("  <dia:layer name=\"Background\" visible=\"true\">\n");
00424 }
00425 
00426 static void dia_end_page(void)
00427 {
00428     dia_fputs("  </dia:layer>\n");
00429 }
00430 
00431 static void dia_begin_cluster(graph_t * g)
00432 {
00433     dia_printf("<dia:group>\n");
00434     Curgraph = g;
00435 }
00436 
00437 static void dia_end_cluster(void)
00438 {
00439     dia_printf("</dia:group>\n");
00440 }
00441 
00442 static void dia_begin_node(node_t * n)
00443 {
00444     dia_printf("<dia:group>\n");
00445     Curnode = n;
00446 }
00447 
00448 static void dia_end_node(void)
00449 {
00450     dia_printf("</dia:group>\n");
00451 }
00452 
00453 static void dia_begin_edge(edge_t * e)
00454 {
00455     Curedge = e;
00456 }
00457 
00458 static void dia_end_edge(void)
00459 {
00460     Curedge = NULL;
00461 }
00462 
00463 static void dia_begin_context(void)
00464 {
00465     assert(SP + 1 < MAXNEST);
00466     cstk[SP + 1] = cstk[SP];
00467     SP++;
00468 }
00469 
00470 static void dia_end_context(void)
00471 {
00472     int psp = SP - 1;
00473     assert(SP > 0);
00474     /*free(cstk[psp].fontfam); */
00475     SP = psp;
00476 }
00477 
00478 static void dia_set_font(char *name, double size)
00479 {
00480     char *p;
00481     context_t *cp;
00482 
00483     cp = &(cstk[SP]);
00484     cp->font_was_set = TRUE;
00485     cp->fontsz = size;
00486     p = strdup(name);
00487     cp->fontfam = p;
00488 }
00489 
00490 static void dia_set_pencolor(char *name)
00491 {
00492     cstk[SP].pencolor = name;
00493 }
00494 
00495 static void dia_set_fillcolor(char *name)
00496 {
00497     cstk[SP].fillcolor = name;
00498 }
00499 
00500 static void dia_set_style(char **s)
00501 {
00502     char *line, *p;
00503     context_t *cp;
00504 
00505     cp = &(cstk[SP]);
00506     while ((p = line = *s++)) {
00507         if (streq(line, "solid"))
00508             cp->pen = P_SOLID;
00509         else if (streq(line, "dashed"))
00510             cp->pen = P_DASHED;
00511         else if (streq(line, "dotted"))
00512             cp->pen = P_DOTTED;
00513         else if (streq(line, "invis"))
00514             cp->pen = P_NONE;
00515         else if (streq(line, "bold"))
00516             cp->penwidth = WIDTH_BOLD;
00517         else if (streq(line, "setlinewidth")) {
00518             while (*p)
00519                 p++;
00520             p++;
00521             cp->penwidth = atol(p);
00522         } else if (streq(line, "filled"))
00523             cp->fill = P_SOLID;
00524         else if (streq(line, "unfilled"))
00525             cp->fill = P_NONE;
00526         else {
00527             agerr(AGWARN,
00528                   "dia_set_style: unsupported style %s - ignoring\n",
00529                   line);
00530         }
00531         cp->style_was_set = TRUE;
00532     }
00533     /* if (cp->style_was_set) dia_style(cp); */
00534 }
00535 
00536 static void dia_textpara(point p, textpara_t * para)
00537 {
00538     int anchor;
00539     pointf mp;
00540     context_t *cp;
00541 
00542     cp = &(cstk[SP]);
00543     switch (para->just) {
00544     case 'l':
00545         anchor = 0;
00546         break;
00547     case 'r':
00548         anchor = 2;
00549         break;
00550     default:
00551     case 'n':
00552         anchor = 1;
00553         break;
00554     }
00555 
00556     mp = diapt(p);
00557     dia_printf
00558         ("    <dia:object type=\"Standard - Text\" version=\"0\" id=\"%s\">\n",
00559          "0");
00560     dia_fputs("      <dia:attribute name=\"text\">\n");
00561     dia_fputs("        <dia:composite type=\"text\">\n");
00562     dia_fputs("          <dia:attribute name=\"string\">\n");
00563     dia_fputs("            <dia:string>#");
00564     dia_fputs(xml_string(para->str));
00565     dia_fputs("#</dia:string>\n");
00566     dia_fputs("          </dia:attribute>\n");
00567     dia_fputs("          <dia:attribute name=\"font\">\n");
00568     dia_printf("            <dia:font name=\"%s\"/>\n", cp->fontfam);
00569     dia_fputs("          </dia:attribute>\n");
00570     dia_fputs("          <dia:attribute name=\"height\">\n");
00571     dia_printf("            <dia:real val=\"%g\"/>\n",
00572                Scale * (cp->fontsz));
00573     dia_fputs("          </dia:attribute>\n");
00574     dia_fputs("          <dia:attribute name=\"pos\">\n");
00575     dia_printf("            <dia:point val=\"%g,%g\"/>\n", mp.x, mp.y);
00576     dia_fputs("          </dia:attribute>\n");
00577     dia_fputs("          <dia:attribute name=\"color\">\n");
00578     dia_printf("            <dia:color val=\"%s\"/>\n",
00579                dia_resolve_color(cp->pencolor));
00580     dia_fputs("          </dia:attribute>\n");
00581     dia_fputs("          <dia:attribute name=\"alignment\">\n");
00582     dia_printf("            <dia:enum val=\"%d\"/>\n", anchor);
00583     dia_fputs("          </dia:attribute>\n");
00584     dia_fputs("        </dia:composite>\n");
00585     dia_fputs("      </dia:attribute>\n");
00586     dia_fputs("      <dia:attribute name=\"obj_pos\">\n");
00587     dia_printf("        <dia:point val=\"%g,%g\"/>\n", mp.x, mp.y);
00588     dia_fputs("      </dia:attribute>\n");
00589     dia_fputs("      <dia:attribute name=\"obj_bb\">\n");
00590     dia_printf("        <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
00591                mp.x - (Scale * (para->width) / 2.), mp.y - 0.4,
00592                mp.x + (Scale * (para->width) / 2.), mp.y + 0.4);
00593     dia_fputs("      </dia:attribute>\n");
00594     dia_fputs("    </dia:object>\n");
00595 }
00596 
00597 static void dia_ellipse(point p, int rx, int ry, int filled)
00598 {
00599     pointf cp, rp;
00600     int nodeId;
00601 
00602     switch (Obj) {
00603     case NODE:
00604         nodeId = AGID(Curnode);
00605         break;
00606     default:
00607         nodeId = -1;
00608         break;
00609     }
00610 
00611     if (cstk[SP].pen == P_NONE) {
00612         /* its invisible, don't draw */
00613         return;
00614     }
00615     cp = diapt(p);
00616 
00617     if (Rot) {
00618         int t;
00619         t = rx;
00620         rx = ry;
00621         ry = t;
00622     }
00623     rp.x = Scale * rx;
00624     rp.y = Scale * ry;
00625 
00626     dia_printf
00627         ("    <dia:object type=\"Standard - Ellipse\" version=\"0\" id=\"%d\">\n",
00628          nodeId);
00629     dia_fputs("      <dia:attribute name=\"elem_corner\">\n");
00630     dia_printf("        <dia:point val=\"%g,%g\"/>\n", cp.x - rp.x,
00631                cp.y - rp.y);
00632     dia_fputs("      </dia:attribute>\n");
00633     dia_fputs("      <dia:attribute name=\"elem_width\">\n");
00634     dia_printf("        <dia:real val=\"%g\"/>\n", rp.x + rp.x);
00635     dia_fputs("      </dia:attribute>\n");
00636     dia_fputs("      <dia:attribute name=\"elem_height\">\n");
00637     dia_printf("        <dia:real val=\"%g\"/>\n", rp.y + rp.y);
00638     dia_fputs("      </dia:attribute>\n");
00639     dia_fputs("      <dia:attribute name=\"obj_pos\">\n");
00640     dia_printf("        <dia:point val=\"%g,%g\"/>\n", cp.x - rp.x,
00641                cp.y - rp.y);
00642     dia_fputs("      </dia:attribute>\n");
00643     dia_fputs("      <dia:attribute name=\"obj_bb\">\n");
00644     dia_printf("        <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
00645                cp.x - rp.x - .11, cp.y - rp.y - .11, cp.x + rp.x + .11,
00646                cp.y + rp.y + .11);
00647     dia_fputs("      </dia:attribute>\n");
00648     dia_grstyle(&cstk[SP]);
00649     dia_grstylefill(&cstk[SP], filled);
00650     dia_fputs("    </dia:object>\n");
00651 }
00652 
00653 
00654 int ellipse_connection(pointf cp, pointf p)
00655 {
00656     int conn = 0;
00657 
00658     if (cp.x == p.x) {
00659         if (cp.y > p.y)
00660             conn = 1;
00661         else
00662             conn = 6;
00663     } else if (cp.y == p.y) {
00664         if (cp.x > p.x)
00665             conn = 3;
00666         else
00667             conn = 4;
00668     } else if (cp.x < p.x) {
00669         if (cp.y < p.y)
00670             conn = 7;
00671         else
00672             conn = 2;
00673     } else if (cp.x > p.x) {
00674         if (cp.y < p.y)
00675             conn = 5;
00676         else
00677             conn = 0;
00678     }
00679 
00680     return conn;
00681 }
00682 
00683 
00684 int box_connection(node_t * n, pointf p)
00685 {
00686     int i = 0, j, sides, conn = 0, peripheries, z;
00687     double xsize, ysize, mindist2 = 0.0, dist2;
00688     polygon_t *poly;
00689     pointf P, *vertices;
00690     static pointf *A;
00691     static int A_size;
00692 
00693     poly = (polygon_t *) ND_shape_info(n);
00694     vertices = poly->vertices;
00695     sides = poly->sides;
00696     peripheries = poly->peripheries;
00697 
00698     if (A_size < sides) {
00699         A_size = sides + 5;
00700         A = ALLOC(A_size, A, pointf);
00701     }
00702 
00703     xsize = (ND_lw(n) + ND_rw(n)) / POINTS(ND_width(n));
00704     ysize = (ND_ht(n)) / POINTS(ND_height(n));
00705 
00706     for (j = 0; j < peripheries; j++) {
00707         for (i = 0; i < sides; i++) {
00708             P = vertices[i + j * sides];
00709             A[i].x = P.x * xsize;
00710             A[i].y = P.y * ysize;
00711             if (sides > 2) {
00712                 A[i].x += ND_coord(n).x;
00713                 A[i].y += ND_coord(n).y;
00714             }
00715         }
00716     }
00717 
00718     z = 0;
00719     while (z < i) {
00720         dist2 = DIST2(p, diaptf(A[z]));
00721         if (z == 0) {
00722             mindist2 = dist2;
00723             conn = 0;
00724         }
00725         if (dist2 < mindist2) {
00726             mindist2 = dist2;
00727             conn = 2 * z;
00728         }
00729         z++;
00730     }
00731 
00732     z = 0;
00733     while (z < i) {
00734         P.x = (diaptf(A[z]).x + diaptf(A[z + 1]).x) / 2;
00735         P.y = (diaptf(A[z]).y + diaptf(A[z + 1]).y) / 2;
00736         dist2 = DIST2(p, P);
00737         if (dist2 < mindist2) {
00738             mindist2 = dist2;
00739             conn = 2 * z + 1;
00740         }
00741         z++;
00742     }
00743 
00744     return conn;
00745 }
00746 
00747 
00748 static void
00749 dia_bezier(point * A, int n, int arrow_at_start, int arrow_at_end, int filled)
00750 {
00751     int i, conn_h, conn_t;
00752     pointf p, firstp = { 0, 0 }, llp = { 0, 0}, urp = { 0, 0};
00753     node_t *head, *tail;
00754     char *shape_t;
00755     pointf cp_h, cp_t;
00756 
00757     if (cstk[SP].pen == P_NONE) {
00758         /* its invisible, don't draw */
00759         return;
00760     }
00761 
00762     dia_printf
00763         ("    <dia:object type=\"Standard - BezierLine\" version=\"0\" id=\"%s\">\n",
00764          "00");
00765     dia_fputs("       <dia:attribute name=\"bez_points\">\n");
00766     for (i = 0; i < n; i++) {
00767         p = diapt(A[i]);
00768         if (!i)
00769             llp = urp = firstp = p;
00770         if (p.x < llp.x || p.y < llp.y)
00771             llp = p;
00772         if (p.x > urp.x || p.y > urp.y)
00773             urp = p;
00774         dia_printf("        <dia:point val=\"%g,%g\"/>\n", p.x, p.y);
00775     }
00776     dia_fputs("      </dia:attribute>\n");
00777     dia_grstyle(&cstk[SP]);
00778     dia_fputs("      <dia:attribute name=\"obj_pos\">\n");
00779     dia_printf("        <dia:point val=\"%g,%g\"/>\n", firstp.x, firstp.y);
00780     dia_fputs("      </dia:attribute>\n");
00781     dia_fputs("      <dia:attribute name=\"obj_bb\">\n");
00782     dia_printf("        <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
00783                llp.x - .11, llp.y - .11, urp.x + .11, urp.y + .11);
00784     dia_fputs("      </dia:attribute>\n");
00785 
00786     if (Curedge) {
00787         conn_h = conn_t = -1;
00788 
00789         head = aghead(Curedge);
00790         tail = agtail(Curedge);
00791 
00792         shape_t = ND_shape(tail)->name;
00793 
00794         /* arrowheads */
00795         if (arrow_at_start) {
00796             dia_fputs("      <dia:attribute name=\"start_arrow\">\n");
00797             dia_fputs("          <dia:enum val=\"3\"/>\n");
00798             dia_fputs("      </dia:attribute>\n");
00799             dia_fputs("      <dia:attribute name=\"start_arrow_length\">\n");
00800             dia_fputs("         <dia:real val=\"0.8\"/>\n");
00801             dia_fputs("      </dia:attribute>\n");
00802             dia_fputs
00803                 ("               <dia:attribute name=\"start_arrow_width\">\n");
00804             dia_fputs("                 <dia:real val=\"0.8\"/>\n");
00805             dia_fputs("      </dia:attribute>\n");
00806         }
00807         if (arrow_at_end) {
00808             dia_fputs("      <dia:attribute name=\"end_arrow\">\n");
00809             dia_fputs("          <dia:enum val=\"3\"/>\n");
00810             dia_fputs("      </dia:attribute>\n");
00811             dia_fputs("      <dia:attribute name=\"end_arrow_length\">\n");
00812             dia_fputs("         <dia:real val=\"0.8\"/>\n");
00813             dia_fputs("      </dia:attribute>\n");
00814             dia_fputs
00815                 ("               <dia:attribute name=\"end_arrow_width\">\n");
00816             dia_fputs("                 <dia:real val=\"0.8\"/>\n");
00817             dia_fputs("      </dia:attribute>\n");
00818         }
00819     
00820         dia_fputs("      <dia:attribute name=\"conn_endpoints\">\n");
00821         dia_printf("        <dia:point val=\"%g,%g\"/>\n",
00822                 diapt(A[0]).x, diapt(A[0]).y);
00823         dia_printf("        <dia:point val=\"%g,%g\"/>\n",
00824                 diapt(A[n - 1]).x, diapt(A[n - 1]).y);
00825         dia_fputs("      </dia:attribute>\n");
00826         dia_fputs("      <dia:connections>\n");
00827     
00828 /* FIXME !!! - What is this crap!   It should just user the arrow vector. */
00829         if ((strcmp(shape_t, "ellipse") == 0)
00830             || (strcmp(shape_t, "circle") == 0)
00831             || (strcmp(shape_t, "doublecircle") == 0)) {
00832             cp_h = diaptf(ND_coord(head));
00833             if (agisdirected(Rootgraph))
00834 
00835                 conn_h = ellipse_connection(cp_h, diapt(A[n - 1]));
00836             else
00837                 conn_h = ellipse_connection(cp_h, diapt(A[0]));
00838         } else if (strcmp(shape_t, "record") == 0) { 
00839         } else {
00840             if (agisdirected(Rootgraph))
00841                 conn_h = box_connection(head, diapt(A[n - 1]));
00842             else
00843                 conn_h = box_connection(head, diapt(A[0]));
00844         }
00845     
00846         if ((strcmp(shape_t, "ellipse") == 0)
00847             || (strcmp(shape_t, "circle") == 0)
00848             || (strcmp(shape_t, "doublecircle") == 0)) {
00849             cp_t = diaptf(ND_coord(tail));
00850             if (agisdirected(Rootgraph))
00851                 conn_t = ellipse_connection(cp_t, diapt(A[0]));
00852             else
00853                 conn_t = ellipse_connection(cp_t, diapt(A[n - 1]));
00854         } else if (strcmp(shape_t, "record") == 0) {
00855         } else {
00856             if (agisdirected(Rootgraph))
00857                 conn_t = box_connection(tail, diapt(A[0]));
00858             else
00859                 conn_t = box_connection(tail, diapt(A[n - 1]));
00860         }
00861 
00862         if (arrow_at_start) {
00863             dia_printf
00864                 ("        <dia:connection handle=\"0\" to=\"%d\" connection=\"%d\"/>\n",
00865                  AGID(head), conn_h);
00866             dia_printf
00867                 ("        <dia:connection handle=\"%d\" to=\"%d\" connection=\"%d\"/>\n",
00868                  (n - 1), AGID(tail), conn_t);
00869         } else {
00870             dia_printf
00871                 ("        <dia:connection handle=\"0\" to=\"%d\" connection=\"%d\"/>\n",
00872                  AGID(tail), conn_t);
00873             dia_printf
00874                 ("        <dia:connection handle=\"%d\" to=\"%d\" connection=\"%d\"/>\n",
00875                  (n - 1), AGID(head), conn_h);
00876         }
00877     
00878         dia_fputs("      </dia:connections>\n");
00879     }
00880     dia_fputs("    </dia:object>\n");
00881 }
00882 
00883 
00884 
00885 static void dia_polygon(point * A, int n, int filled)
00886 {
00887     int i;
00888     pointf p, firstp = { 0, 0 }, llp = {
00889     0, 0}, urp = {
00890     0, 0};
00891 
00892     if (cstk[SP].pen == P_NONE) {
00893         /* its invisible, don't draw */
00894         return;
00895     }
00896 
00897     switch (Obj) {
00898     case NODE:
00899         dia_printf
00900             ("    <dia:object type=\"Standard - Polygon\" version=\"0\" id=\"%d\">\n",
00901              AGID(Curnode));
00902         break;
00903     case EDGE:
00904         return;
00905         break;
00906     case CLST:
00907         dia_printf
00908             ("    <dia:object type=\"Standard - Polygon\" version=\"0\" id=\"%s\">\n",
00909              agnameof(Curgraph));
00910         break;
00911     default:
00912         dia_printf
00913             ("    <dia:object type=\"Standard - Polygon\" version=\"0\" id=\"%s\">\n",
00914              "polygon");
00915         break;
00916     }
00917     dia_fputs("       <dia:attribute name=\"poly_points\">\n");
00918     for (i = 0; i < n; i++) {
00919         p = diapt(A[i]);
00920         if (!i)
00921             llp = urp = firstp = p;
00922         if (p.x < llp.x || p.y < llp.y)
00923             llp = p;
00924         if (p.x > urp.x || p.y > urp.y)
00925             urp = p;
00926         dia_printf("        <dia:point val=\"%g,%g\"/>\n", p.x, p.y);
00927     }
00928     dia_fputs("      </dia:attribute>\n");
00929     dia_fputs("      <dia:attribute name=\"obj_pos\">\n");
00930     dia_printf("        <dia:point val=\"%g,%g\"/>\n", firstp.x, firstp.y);
00931     dia_fputs("      </dia:attribute>\n");
00932     dia_fputs("      <dia:attribute name=\"obj_bb\">\n");
00933     dia_printf("        <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
00934                llp.x - .11, llp.y - .11, urp.x + .11, urp.y + .11);
00935     dia_fputs("      </dia:attribute>\n");
00936     dia_grstyle(&cstk[SP]);
00937     dia_grstylefill(&cstk[SP], filled);
00938     dia_fputs("    </dia:object>\n");
00939 }
00940 
00941 static void dia_polyline(point * A, int n)
00942 {
00943     int i;
00944     pointf p, firstp = { 0, 0 }, llp = {
00945     0, 0}, urp = {
00946     0, 0};
00947 
00948     if (cstk[SP].pen == P_NONE) {
00949         /* its invisible, don't draw */
00950         return;
00951     }
00952     dia_printf
00953         ("    <dia:object type=\"Standard - PolyLine\" version=\"0\" id=\"%s\">\n",
00954          "0");
00955     dia_fputs("      <dia:attribute name=\"poly_points\">\n");
00956     for (i = 0; i < n; i++) {
00957         p = diapt(A[i]);
00958         if (!i)
00959             llp = urp = firstp = p;
00960         if (p.x < llp.x || p.y < llp.y)
00961             llp = p;
00962         if (p.x > urp.x || p.y > urp.y)
00963             urp = p;
00964         dia_printf("<dia:point val=\"%g,%g\"/>\n", p.x, p.y);
00965     }
00966     dia_fputs("      </dia:attribute>\n");
00967     dia_grstyle(&cstk[SP]);
00968     dia_fputs("      <dia:attribute name=\"obj_pos\">\n");
00969     dia_printf("        <dia:point val=\"%g,%g\"/>\n", firstp.x, firstp.y);
00970     dia_fputs("      </dia:attribute>\n");
00971     dia_fputs("      <dia:attribute name=\"obj_bb\">\n");
00972     dia_printf("        <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
00973                llp.x - .11, llp.y - .11, urp.x + .11, urp.y + .11);
00974     dia_fputs("      </dia:attribute>\n");
00975     dia_fputs("    </dia:object>\n");
00976 }
00977 
00978 static void dia_usershape(usershape_t *us, boxf b, point *A, int n, boolean filled)
00979 {
00980     char *imagefile;
00981 
00982     if (cstk[SP].pen == P_NONE) {
00983         /* its invisible, don't draw */
00984         return;
00985     }
00986 
00987 #if 0
00988 /* FIXME */
00989     imagefile = agget(Curnode, "shapefile");
00990 #else
00991     imagefile = NULL;
00992 #endif
00993 
00994     if (! imagefile) {
00995         dia_polygon(A, n, filled);
00996         return;
00997     }
00998 }
00999 
01000 codegen_t DIA_CodeGen = {
01001     dia_reset,
01002     dia_begin_job, dia_end_job,
01003     dia_begin_graph, dia_end_graph,
01004     dia_begin_page, dia_end_page,
01005     0, /* dia_begin_layer */ 0, /* dia_end_layer */
01006     dia_begin_cluster, dia_end_cluster,
01007     0, /* dia_begin_nodes */ 0, /* dia_end_nodes */
01008     0, /* dia_begin_edges */ 0, /* dia_end_edges */
01009     dia_begin_node, dia_end_node,
01010     dia_begin_edge, dia_end_edge,
01011     dia_begin_context, dia_end_context,
01012     0, /* dia_begin_anchor */ 0,        /* dia_end_anchor */
01013     dia_set_font, dia_textpara,
01014     dia_set_pencolor, dia_set_fillcolor, dia_set_style,
01015     dia_ellipse, dia_polygon,
01016     dia_bezier, dia_polyline,
01017     1,                          /* bezier_has_arrows */
01018     dia_comment,
01019     dia_usershape
01020 };