/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/plugin/core/gvrender_core_fig.c

Go to the documentation of this file.
00001 /* $Id: gvrender_core_fig.c,v 1.21 2008/03/03 23:01:52 ellson Exp $ $Revision: 1.21 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 #ifdef HAVE_CONFIG_H
00018 #include "config.h"
00019 #endif
00020 
00021 #include <stdarg.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <ctype.h>
00025 
00026 #ifdef WIN32
00027 #include <io.h>
00028 #include "compat.h"
00029 #endif
00030 
00031 #include "macros.h"
00032 #include "const.h"
00033 
00034 #include "gvplugin_render.h"
00035 #include "graph.h"
00036 #include "agxbuf.h"
00037 #include "utils.h"
00038 #include "color.h"
00039 
00040 /* Number of points to split splines into */
00041 #define BEZIERSUBDIVISION 6
00042 
00043 typedef enum { FORMAT_FIG, } format_type;
00044 
00045 static int Depth;
00046 
00047 static void figptarray(GVJ_t *job, pointf * A, int n, int close)
00048 {
00049     int i;
00050     point p;
00051 
00052     for (i = 0; i < n; i++) {
00053         PF2P(A[i],p);
00054         gvdevice_printf(job, " %d %d", p.x, p.y);
00055     }
00056     if (close) {
00057         PF2P(A[0],p);
00058         gvdevice_printf(job, " %d %d", p.x, p.y);
00059     }
00060     gvdevice_fputs(job, "\n");
00061 }
00062 
00063 static char *fig_string(char *s)
00064 {
00065     static char *buf = NULL;
00066     static int bufsize = 0;
00067     int pos = 0;
00068     char *p;
00069     unsigned char c;
00070 
00071     if (!buf) {
00072         bufsize = 64;
00073         buf = malloc(bufsize * sizeof(char));
00074     }
00075 
00076     p = buf;
00077     while ((c = *s++)) {
00078         if (pos > (bufsize - 8)) {
00079             bufsize *= 2;
00080             buf = realloc(buf, bufsize * sizeof(char));
00081             p = buf + pos;
00082         }
00083         if (isascii(c)) {
00084             if (c == '\\') {
00085                 *p++ = '\\';
00086                 pos++;
00087             }
00088             *p++ = c;
00089             pos++;
00090         } else {
00091             *p++ = '\\';
00092             sprintf(p, "%03o", c);
00093             p += 3;
00094             pos += 4;
00095         }
00096     }
00097     *p = '\0';
00098     return buf;
00099 }
00100 
00101 static int figColorResolve(int *new, int r, int g, int b)
00102 {
00103 #define maxColors 256
00104     static int top = 0;
00105     static short red[maxColors], green[maxColors], blue[maxColors];
00106     int c;
00107     int ct = -1;
00108     long rd, gd, bd, dist;
00109     long mindist = 3 * 255 * 255;       /* init to max poss dist */
00110 
00111     *new = 0;                   /* in case it is not a new color */
00112     for (c = 0; c < top; c++) {
00113         rd = (long) (red[c] - r);
00114         gd = (long) (green[c] - g);
00115         bd = (long) (blue[c] - b);
00116         dist = rd * rd + gd * gd + bd * bd;
00117         if (dist < mindist) {
00118             if (dist == 0)
00119                 return c;       /* Return exact match color */
00120             mindist = dist;
00121             ct = c;
00122         }
00123     }
00124     /* no exact match.  We now know closest, but first try to allocate exact */
00125     if (top++ == maxColors)
00126         return ct;              /* Return closest available color */
00127     red[c] = r;
00128     green[c] = g;
00129     blue[c] = b;
00130     *new = 1;                   /* flag new color */
00131     return c;                   /* Return newly allocated color */
00132 }
00133 
00134 /* this table is in xfig color index order */
00135 static char *figcolor[] = {
00136     "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL
00137 };
00138 
00139 static void fig_resolve_color(GVJ_t *job, gvcolor_t * color)
00140 {
00141     int object_code = 0;        /* always 0 for color */
00142     int i, new;
00143 
00144     switch (color->type) {
00145         case COLOR_STRING:
00146             for (i = 0; figcolor[i]; i++) {
00147                 if (streq(figcolor[i], color->u.string)) {
00148                     color->u.index = i;
00149                     break;
00150                 }
00151             }
00152             break;
00153         case RGBA_BYTE:
00154             i = 32 + figColorResolve(&new,
00155                         color->u.rgba[0],
00156                         color->u.rgba[1],
00157                         color->u.rgba[2]);
00158             if (new)
00159                 gvdevice_printf(job, "%d %d #%02x%02x%02x\n",
00160                         object_code, i,
00161                         color->u.rgba[0],
00162                         color->u.rgba[1],
00163                         color->u.rgba[2]);
00164             color->u.index = i;
00165             break;
00166         default:
00167             assert(0);  /* internal error */
00168     }
00169 
00170     color->type = COLOR_INDEX;
00171 }
00172 
00173 static void fig_line_style(obj_state_t *obj, int *line_style, double *style_val)
00174 {
00175     switch (obj->pen) {
00176         case PEN_DASHED: 
00177             *line_style = 1;
00178             *style_val = 10.;
00179             break;
00180         case PEN_DOTTED:
00181             *line_style = 2;
00182             *style_val = 10.;
00183             break;
00184         case PEN_SOLID:
00185         default:
00186             *line_style = 0;
00187             *style_val = 0.;
00188             break;
00189     }
00190 }
00191 
00192 static void fig_comment(GVJ_t *job, char *str)
00193 {
00194     gvdevice_printf(job, "# %s\n", str);
00195 }
00196 
00197 static void fig_begin_graph(GVJ_t * job)
00198 {
00199     obj_state_t *obj = job->obj;
00200 
00201     gvdevice_fputs(job, "#FIG 3.2\n");
00202     gvdevice_printf(job, "# Generated by %s version %s (%s)\n",
00203         job->common->info[0], job->common->info[1], job->common->info[2]);
00204     gvdevice_printf(job, "# For: %s\n", job->common->user);
00205     gvdevice_printf(job, "# Title: %s\n", obj->u.g->name);
00206     gvdevice_printf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
00207     gvdevice_fputs(job, "Portrait\n"); /* orientation */
00208     gvdevice_fputs(job, "Center\n");   /* justification */
00209     gvdevice_fputs(job, "Inches\n");   /* units */
00210     gvdevice_fputs(job, "Letter\n");   /* papersize */
00211     gvdevice_fputs(job, "100.00\n");   /* magnification % */
00212     gvdevice_fputs(job, "Single\n");   /* multiple-page */
00213     gvdevice_fputs(job, "-2\n");       /* transparent color (none) */
00214     gvdevice_fputs(job, "1200");             /* resolution */
00215     gvdevice_fputs(job, " 2\n");       /* coordinate system (upper left) */
00216 }
00217 
00218 static void fig_end_graph(GVJ_t * job)
00219 {
00220     gvdevice_fputs(job, "# end of FIG file\n");
00221 }
00222 
00223 static void fig_begin_page(GVJ_t * job)
00224 {
00225     Depth = 2;
00226 }
00227 
00228 static void fig_begin_node(GVJ_t * job)
00229 {
00230     Depth = 1;
00231 }
00232 
00233 static void fig_end_node(GVJ_t * job)
00234 {
00235     Depth = 2;
00236 }
00237 
00238 static void fig_begin_edge(GVJ_t * job)
00239 {
00240     Depth = 0;
00241 }
00242 
00243 static void fig_end_edge(GVJ_t * job)
00244 {
00245     Depth = 2;
00246 }
00247 
00248 static void fig_textpara(GVJ_t * job, pointf p, textpara_t * para)
00249 {
00250     obj_state_t *obj = job->obj;
00251 
00252     int object_code = 4;        /* always 4 for text */
00253     int sub_type = 0;           /* text justification */
00254     int color = obj->pencolor.u.index;
00255     int depth = Depth;
00256     int pen_style = 0;          /* not used */
00257     int font = -1;              /* init to xfig's default font */
00258     double font_size = para->fontsize * job->zoom;
00259     double angle = job->rotation ? (M_PI / 2.0) : 0.0;
00260     int font_flags = 6;         /* PostScript font + Special text */
00261 /* Special text indicates that latex markup may exist
00262  * in the output - but note that dot knows nothing about latex,
00263  * so the node sizes may be wrong.
00264  */
00265     double height = 0.0;
00266     double length = 0.0;
00267 
00268     if (para->postscript_alias) /* if it is a standard postscript font */
00269         font = para->postscript_alias->xfig_code; 
00270 
00271     switch (para->just) {
00272     case 'l':
00273         sub_type = 0;
00274         break;
00275     case 'r':
00276         sub_type = 2;
00277         break;
00278     default:
00279     case 'n':
00280         sub_type = 1;
00281         break;
00282     }
00283 
00284     gvdevice_printf(job,
00285             "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n",
00286             object_code, sub_type, color, depth, pen_style, font,
00287             font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y),
00288             fig_string(para->str));
00289 }
00290 
00291 static void fig_ellipse(GVJ_t * job, pointf * A, int filled)
00292 {
00293     obj_state_t *obj = job->obj;
00294 
00295     int object_code = 1;        /* always 1 for ellipse */
00296     int sub_type = 1;           /* ellipse defined by radii */
00297     int line_style;             /* solid, dotted, dashed */
00298     int thickness = obj->penwidth;
00299     int pen_color = obj->pencolor.u.index;
00300     int fill_color = obj->fillcolor.u.index;
00301     int depth = Depth;
00302     int pen_style = 0;          /* not used */
00303     int area_fill = filled ? 20 : -1;
00304     double style_val;
00305     int direction = 0;
00306     double angle = 0.0;
00307     int center_x, center_y, radius_x, radius_y;
00308     int start_x, start_y, end_x, end_y;
00309 
00310     fig_line_style(obj, &line_style, &style_val);
00311 
00312     start_x = center_x = ROUND(A[0].x);
00313     start_y = center_y = ROUND(A[0].y);
00314     radius_x = ROUND(A[1].x - A[0].x);
00315     radius_y = ROUND(A[1].y - A[0].y);
00316     end_x = ROUND(A[1].x);
00317     end_y = ROUND(A[1].y);
00318 
00319     gvdevice_printf(job,
00320             "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n",
00321             object_code, sub_type, line_style, thickness, pen_color,
00322             fill_color, depth, pen_style, area_fill, style_val, direction,
00323             angle, center_x, center_y, radius_x, radius_y, start_x,
00324             start_y, end_x, end_y);
00325 }
00326 
00327 static void fig_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
00328               int arrow_at_end, int filled)
00329 {
00330     obj_state_t *obj = job->obj;
00331 
00332     int object_code = 3;        /* always 3 for spline */
00333     int sub_type;
00334     int line_style;             /* solid, dotted, dashed */
00335     int thickness = obj->penwidth;
00336     int pen_color = obj->pencolor.u.index;
00337     int fill_color = obj->fillcolor.u.index;
00338     int depth = Depth;
00339     int pen_style = 0;          /* not used */
00340     int area_fill;
00341     double style_val;
00342     int cap_style = 0;
00343     int forward_arrow = 0;
00344     int backward_arrow = 0;
00345     int npoints = n;
00346     int i;
00347 
00348     pointf pf, V[4];
00349     point p;
00350     int j, step;
00351     int count = 0;
00352     int size;
00353 
00354     char *buffer;
00355     char *buf;
00356     buffer =
00357         malloc((npoints + 1) * (BEZIERSUBDIVISION +
00358                                 1) * 20 * sizeof(char));
00359     buf = buffer;
00360 
00361     fig_line_style(obj, &line_style, &style_val);
00362 
00363     if (filled) {
00364         sub_type = 5;     /* closed X-spline */
00365         area_fill = 20;   /* fully saturated color */
00366         fill_color = job->obj->fillcolor.u.index;
00367     }
00368     else {
00369         sub_type = 4;     /* opened X-spline */
00370         area_fill = -1;
00371         fill_color = 0;
00372     }
00373     V[3].x = A[0].x;
00374     V[3].y = A[0].y;
00375     /* Write first point in line */
00376     count++;
00377     PF2P(A[0], p);
00378     size = sprintf(buf, " %d %d", p.x, p.y);
00379     buf += size;
00380     /* write subsequent points */
00381     for (i = 0; i + 3 < n; i += 3) {
00382         V[0] = V[3];
00383         for (j = 1; j <= 3; j++) {
00384             V[j].x = A[i + j].x;
00385             V[j].y = A[i + j].y;
00386         }
00387         for (step = 1; step <= BEZIERSUBDIVISION; step++) {
00388             count++;
00389             pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
00390             PF2P(pf, p);
00391             size = sprintf(buf, " %d %d", p.x, p.y);
00392             buf += size;
00393         }
00394     }
00395 
00396     gvdevice_printf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
00397             object_code,
00398             sub_type,
00399             line_style,
00400             thickness,
00401             pen_color,
00402             fill_color,
00403             depth,
00404             pen_style,
00405             area_fill,
00406             style_val, cap_style, forward_arrow, backward_arrow, count);
00407 
00408     gvdevice_printf(job, " %s\n", buffer);      /* print points */
00409     free(buffer);
00410     for (i = 0; i < count; i++) {
00411         gvdevice_printf(job, " %d", i % (count - 1) ? 1 : 0);   /* -1 on all */
00412     }
00413     gvdevice_fputs(job, "\n");
00414 }
00415 
00416 static void fig_polygon(GVJ_t * job, pointf * A, int n, int filled)
00417 {
00418     obj_state_t *obj = job->obj;
00419 
00420     int object_code = 2;        /* always 2 for polyline */
00421     int sub_type = 3;           /* always 3 for polygon */
00422     int line_style;             /* solid, dotted, dashed */
00423     int thickness = obj->penwidth;
00424     int pen_color = obj->pencolor.u.index;
00425     int fill_color = obj->fillcolor.u.index;
00426     int depth = Depth;
00427     int pen_style = 0;          /* not used */
00428     int area_fill = filled ? 20 : -1;
00429     double style_val;
00430     int join_style = 0;
00431     int cap_style = 0;
00432     int radius = 0;
00433     int forward_arrow = 0;
00434     int backward_arrow = 0;
00435     int npoints = n + 1;
00436 
00437     fig_line_style(obj, &line_style, &style_val);
00438 
00439     gvdevice_printf(job,
00440             "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
00441             object_code, sub_type, line_style, thickness, pen_color,
00442             fill_color, depth, pen_style, area_fill, style_val, join_style,
00443             cap_style, radius, forward_arrow, backward_arrow, npoints);
00444     figptarray(job, A, n, 1);        /* closed shape */
00445 }
00446 
00447 static void fig_polyline(GVJ_t * job, pointf * A, int n)
00448 {
00449     obj_state_t *obj = job->obj;
00450 
00451     int object_code = 2;        /* always 2 for polyline */
00452     int sub_type = 1;           /* always 1 for polyline */
00453     int line_style;             /* solid, dotted, dashed */
00454     int thickness = obj->penwidth;
00455     int pen_color = obj->pencolor.u.index;
00456     int fill_color = 0;
00457     int depth = Depth;
00458     int pen_style = 0;          /* not used */
00459     int area_fill = 0;
00460     double style_val;
00461     int join_style = 0;
00462     int cap_style = 0;
00463     int radius = 0;
00464     int forward_arrow = 0;
00465     int backward_arrow = 0;
00466     int npoints = n;
00467 
00468     fig_line_style(obj, &line_style, &style_val);
00469 
00470     gvdevice_printf(job,
00471             "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
00472             object_code, sub_type, line_style, thickness, pen_color,
00473             fill_color, depth, pen_style, area_fill, style_val, join_style,
00474             cap_style, radius, forward_arrow, backward_arrow, npoints);
00475     figptarray(job, A, n, 0);        /* open shape */
00476 }
00477 
00478 gvrender_engine_t fig_engine = {
00479     0,                          /* fig_begin_job */
00480     0,                          /* fig_end_job */
00481     fig_begin_graph,
00482     fig_end_graph,
00483     0,                          /* fig_begin_layer */
00484     0,                          /* fig_end_layer */
00485     fig_begin_page,
00486     0,                          /* fig_end_page */
00487     0,                          /* fig_begin_cluster */
00488     0,                          /* fig_end_cluster */
00489     0,                          /* fig_begin_nodes */
00490     0,                          /* fig_end_nodes */
00491     0,                          /* fig_begin_edges */
00492     0,                          /* fig_end_edges */
00493     fig_begin_node,
00494     fig_end_node,
00495     fig_begin_edge,
00496     fig_end_edge,
00497     0,                          /* fig_begin_anchor */
00498     0,                          /* fig_end_anchor */
00499     fig_textpara,
00500     fig_resolve_color,
00501     fig_ellipse,
00502     fig_polygon,
00503     fig_bezier,
00504     fig_polyline,
00505     fig_comment,
00506     0,                          /* fig_library_shape */
00507 };
00508 
00509 
00510 /* NB.  List must be LANG_C sorted */
00511 static char *fig_knowncolors[] = {
00512     "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow",
00513 };
00514 
00515 
00516 gvrender_features_t render_features_fig = {
00517     EMIT_COLORS
00518         | GVRENDER_Y_GOES_DOWN, /* flags */
00519     4.,                         /* default pad - graph units */
00520     fig_knowncolors,            /* knowncolors */
00521     sizeof(fig_knowncolors) / sizeof(char *), /* sizeof knowncolors */
00522     RGBA_BYTE,                  /* color_type */
00523 };
00524 
00525 gvdevice_features_t device_features_fig = {
00526     EMIT_COLORS
00527         | GVRENDER_Y_GOES_DOWN, /* flags */
00528     {0.,0.},                    /* default margin - points */
00529     {0.,0.},                    /* default page width, height - points */
00530     {1440.,1440.},              /* default dpi */
00531          /* FIXME - this default dpi is a very strange number!!!
00532           * It was picked to make .png usershapes the right size on my screen.
00533           * It happens to be 1.2 * 1200, but I can't explain the 1.2.
00534           * (I was expecting 1.3333 which is 96/72, but thats too big.)
00535           * Also 1200 is hardcoded in fig_begin_graph() instead of using job->dpi 
00536           */
00537 
00538          /* It may be TWIPS, i.e. 20 * POINT_PER_INCH 
00539           *    but that doesn't explain what the 1200 is? */
00540 };
00541 
00542 gvplugin_installed_t gvrender_fig_types[] = {
00543     {FORMAT_FIG, "fig", 1, &fig_engine, &render_features_fig},
00544     {0, NULL, 0, NULL, NULL}
00545 };
00546 
00547 gvplugin_installed_t gvdevice_fig_types[] = {
00548     {FORMAT_FIG, "fig:fig", 1, NULL, &device_features_fig},
00549     {0, NULL, 0, NULL, NULL}
00550 };

Generated on Mon Mar 31 19:03:28 2008 for Graphviz by  doxygen 1.5.1