--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+
+typedef enum { FORMAT_DIA, } format_type;
+
+extern char *xml_string(char *str);
+
+/* DIA font modifiers */
+#define REGULAR 0
+#define BOLD 1
+#define ITALIC 2
+
+/* DIA patterns */
+#define P_SOLID 0
+#define P_NONE 15
+#define P_DOTTED 4 /* i wasn't sure about this */
+#define P_DASHED 11 /* or this */
+
+/* DIA bold line constant */
+#define WIDTH_NORMAL 1
+#define WIDTH_BOLD 3
+
+#define DIA_RESOLUTION 1.0
+#define SCALE (DIA_RESOLUTION/15.0)
+
+static double Scale;
+static pointf Offset;
+static int Rot;
+static box PB;
+static int onetime = TRUE;
+
+typedef struct context_t {
+ char *pencolor, *fillcolor, *fontfam, fontopt, font_was_set;
+ char pen, fill, penwidth, style_was_set;
+ double fontsz;
+} context_t;
+
+#define MAXNEST 4
+static context_t cstk[MAXNEST];
+static int SP;
+
+#define SVG_COLORS_P 0
+
+static int dia_comparestr(const void *s1, const void *s2)
+{
+ return strcmp(*(char **) s1, *(char **) s2);
+}
+
+static char *dia_resolve_color(char *name)
+{
+/* color names from http://www.w3.org/TR/SVG/types.html */
+/* NB. List must be LANG_C sorted */
+ static char *svg_known_colors[] = {
+ "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
+ "beige", "bisque", "black", "blanchedalmond", "blue",
+ "blueviolet", "brown", "burlywood",
+ "cadetblue", "chartreuse", "chocolate", "coral",
+ "cornflowerblue", "cornsilk", "crimson", "cyan",
+ "darkblue", "darkcyan", "darkgoldenrod", "darkgray",
+ "darkgreen", "darkgrey", "darkkhaki", "darkmagenta",
+ "darkolivegreen", "darkorange", "darkorchid", "darkred",
+ "darksalmon", "darkseagreen", "darkslateblue", "darkslategray",
+ "darkslategrey", "darkturquoise", "darkviolet", "deeppink",
+ "deepskyblue", "dimgray", "dimgrey", "dodgerblue",
+ "firebrick", "floralwhite", "forestgreen", "fuchsia",
+ "gainsboro", "ghostwhite", "gold", "goldenrod", "gray",
+ "green", "greenyellow", "grey",
+ "honeydew", "hotpink", "indianred",
+ "indigo", "ivory", "khaki",
+ "lavender", "lavenderblush", "lawngreen", "lemonchiffon",
+ "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow",
+ "lightgray", "lightgreen", "lightgrey", "lightpink",
+ "lightsalmon", "lightseagreen", "lightskyblue",
+ "lightslategray", "lightslategrey", "lightsteelblue",
+ "lightyellow", "lime", "limegreen", "linen",
+ "magenta", "maroon", "mediumaquamarine", "mediumblue",
+ "mediumorchid", "mediumpurple", "mediumseagreen",
+ "mediumslateblue", "mediumspringgreen", "mediumturquoise",
+ "mediumvioletred", "midnightblue", "mintcream",
+ "mistyrose", "moccasin",
+ "navajowhite", "navy", "oldlace",
+ "olive", "olivedrab", "orange", "orangered", "orchid",
+ "palegoldenrod", "palegreen", "paleturquoise",
+ "palevioletred", "papayawhip", "peachpuff", "peru", "pink",
+ "plum", "powderblue", "purple",
+ "red", "rosybrown", "royalblue",
+ "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell",
+ "sienna", "silver", "skyblue", "slateblue", "slategray",
+ "slategrey", "snow", "springgreen", "steelblue",
+ "tan", "teal", "thistle", "tomato", "turquoise",
+ "violet",
+ "wheat", "white", "whitesmoke",
+ "yellow", "yellowgreen",
+ };
+
+ static char buf[SMALLBUF];
+ char *tok;
+ gvcolor_t color;
+
+// tok = canontoken(name);
+tok = name;
+ if (!SVG_COLORS_P || (bsearch(&tok, svg_known_colors,
+ sizeof(svg_known_colors) / sizeof(char *),
+ sizeof(char *), dia_comparestr) == NULL)) {
+ /* if tok was not found in known_colors */
+ if (streq(tok, "transparent")) {
+ tok = "none";
+ } else {
+// colorxlate(name, &color, RGBA_BYTE);
+ sprintf(buf, "#%02x%02x%02x",
+ color.u.rgba[0], color.u.rgba[1], color.u.rgba[2]);
+ tok = buf;
+ }
+ }
+ return tok;
+}
+
+
+static void dia_reset(void)
+{
+ onetime = TRUE;
+}
+
+
+static void init_dia(void)
+{
+ SP = 0;
+ cstk[0].pencolor = DEFAULT_COLOR; /* DIA pencolor */
+ cstk[0].fillcolor = ""; /* DIA fillcolor */
+ cstk[0].fontfam = DEFAULT_FONTNAME; /* font family name */
+ cstk[0].fontsz = DEFAULT_FONTSIZE; /* font size */
+ cstk[0].fontopt = REGULAR; /* modifier: REGULAR, BOLD or ITALIC */
+ cstk[0].pen = P_SOLID; /* pen pattern style, default is solid */
+ cstk[0].fill = P_NONE;
+ cstk[0].penwidth = WIDTH_NORMAL;
+}
+
+static pointf dia_pt(pointf p)
+{
+ pointf rv;
+
+ if (Rot == 0) {
+ rv.x = PB.LL.x + p.x * Scale + Offset.x;
+ rv.y = PB.UR.y - 1 - p.y * Scale - Offset.y;
+ } else {
+ rv.x = PB.UR.x - 1 - p.y * Scale - Offset.x;
+ rv.y = PB.UR.y - 1 - p.x * Scale - Offset.y;
+ }
+ return rv;
+}
+
+static void dia_style(GVJ_t * job, context_t * cp)
+{
+ if (cp->pencolor != DEFAULT_COLOR) {
+ gvdevice_fputs(job, " <dia:attribute name=\"border_color\">\n");
+ gvdevice_printf(job, " <dia:color val=\"%s\"/>\n",
+ dia_resolve_color(cp->pencolor));
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ }
+ if (cp->penwidth != WIDTH_NORMAL) {
+ gvdevice_fputs(job, " <dia:attribute name=\"line_width\">\n");
+ gvdevice_printf(job, " <dia:real val=\"%g\"/>\n",
+ Scale * (cp->penwidth));
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ }
+ if (cp->pen == P_DASHED) {
+ gvdevice_fputs(job, " <dia:attribute name=\"line_style\">\n");
+ gvdevice_printf(job, " <dia:real val=\"%d\"/>\n", 1);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+#if 0
+ } else if (cp->pen == P_DOTTED) {
+ gvdevice_printf(job, "stroke-dasharray:%s;", sdotarray);
+#endif
+ }
+}
+
+static void dia_stylefill(GVJ_t * job, context_t * cp, int filled)
+{
+ if (filled) {
+ gvdevice_fputs(job, " <dia:attribute name=\"inner_color\">\n");
+ gvdevice_printf(job, " <dia:color val=\"%s\"/>\n",
+ dia_resolve_color(cp->fillcolor));
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ } else {
+ gvdevice_fputs(job, " <dia:attribute name=\"show_background\">\n");
+ gvdevice_printf(job, " <dia:boolean val=\"%s\"/>\n", "true");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ }
+}
+
+static void dia_comment(GVJ_t * job, char *str)
+{
+ gvdevice_fputs(job, "<!-- ");
+ gvdevice_fputs(job, xml_string(str));
+ gvdevice_fputs(job, " -->\n");
+}
+
+static void
+dia_begin_job(GVJ_t *job)
+{
+ core_init_compression(job, COMPRESSION_ZLIB);
+ gvdevice_printf(job, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+}
+
+static void dia_end_job(GVJ_t *job)
+{
+ core_fini_compression(job);
+}
+
+static void dia_begin_graph(GVJ_t * job)
+{
+ Rootgraph = g;
+ PB.LL.x = PB.LL.y = 0;
+ PB.UR.x = (bb.UR.x - bb.LL.x + 2 * GD_drawing(g)->margin.x) * SCALE;
+ PB.UR.y = (bb.UR.y - bb.LL.y + 2 * GD_drawing(g)->margin.y) * SCALE;
+ Offset.x = GD_drawing(g)->margin.x * SCALE;
+ Offset.y = GD_drawing(g)->margin.y * SCALE;
+ if (onetime) {
+ init_dia();
+ onetime = FALSE;
+ }
+ dia_fputs
+ ("<dia:diagram xmlns:dia=\"http://www.lysator.liu.se/~alla/dia/\">\n");
+ gvdevice_fputs(job, " <dia:diagramdata>\n");
+
+ gvdevice_fputs(job, " <dia:attribute name=\"background\">\n");
+ gvdevice_fputs(job, " <dia:color val=\"#ffffff\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+
+ gvdevice_fputs(job, " <dia:attribute name=\"paper\">\n");
+ gvdevice_fputs(job, " <dia:composite type=\"paper\">\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"name\">\n");
+ gvdevice_fputs(job, " <dia:string>#A4#</dia:string>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"tmargin\">\n");
+ gvdevice_fputs(job, " <dia:real val=\"2.8222\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"bmargin\">\n");
+ gvdevice_fputs(job, " <dia:real val=\"2.8222\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"lmargin\">\n");
+ gvdevice_fputs(job, " <dia:real val=\"2.8222\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"rmargin\">\n");
+ gvdevice_fputs(job, " <dia:real val=\"2.8222\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"is_portrait\">\n");
+ gvdevice_fputs(job, " <dia:boolean val=\"true\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"scaling\">\n");
+ gvdevice_fputs(job, " <dia:real val=\"1\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"fitto\">\n");
+ gvdevice_fputs(job, " <dia:boolean val=\"false\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " </dia:composite>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+
+ gvdevice_fputs(job, " <dia:attribute name=\"grid\">\n");
+ gvdevice_fputs(job, " <dia:composite type=\"grid\">\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"width_x\">\n");
+ gvdevice_fputs(job, " <dia:real val=\"1\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"width_y\">\n");
+ gvdevice_fputs(job, " <dia:real val=\"1\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"visible_x\">\n");
+ gvdevice_fputs(job, " <dia:int val=\"1\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"visible_y\">\n");
+ gvdevice_fputs(job, " <dia:int val=\"1\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " </dia:composite>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+
+ gvdevice_fputs(job, " <dia:attribute name=\"guides\">\n");
+ gvdevice_fputs(job, " <dia:composite type=\"guides\">\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"hguides\"/>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"vguides\"/>\n");
+ gvdevice_fputs(job, " </dia:composite>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+
+ gvdevice_fputs(job, " </dia:diagramdata>\n");
+}
+
+static void dia_end_graph(GVJ_t * job)
+{
+ gvdevice_printf(job, "</dia:diagram>\n");
+}
+
+static void
+dia_begin_page(GVJ_t * job)
+{
+ Scale = scale * SCALE;
+ Rot = rot;
+
+ gvdevice_printf(job, " <dia:layer name=\"Background\" visible=\"true\">\n");
+}
+
+static void dia_end_page(GVJ_t * job)
+{
+ gvdevice_fputs(job, " </dia:layer>\n");
+}
+
+static void dia_begin_cluster(GVJ_t * job)
+{
+ gvdevice_printf(job, "<dia:group>\n");
+}
+
+static void dia_end_cluster(GVJ_t * job)
+{
+ gvdevice_printf(job, "</dia:group>\n");
+}
+
+static void dia_begin_node(GVJ_t * job)
+{
+ gvdevice_printf(job, "<dia:group>\n");
+}
+
+static void dia_end_node(GVJ_t * job)
+{
+ gvdevice_printf(job, "</dia:group>\n");
+}
+
+static void dia_begin_edge(GVJ_t * job)
+{
+}
+
+static void dia_end_edge(GVJ_t * job)
+{
+}
+
+static void dia_begin_context(void)
+{
+ assert(SP + 1 < MAXNEST);
+ cstk[SP + 1] = cstk[SP];
+ SP++;
+}
+
+static void dia_end_context(void)
+{
+ int psp = SP - 1;
+ assert(SP > 0);
+ /*free(cstk[psp].fontfam); */
+ SP = psp;
+}
+
+static void dia_set_font(char *name, double size)
+{
+ char *p;
+ context_t *cp;
+
+ cp = &(cstk[SP]);
+ cp->font_was_set = TRUE;
+ cp->fontsz = size;
+ p = strdup(name);
+ cp->fontfam = p;
+}
+
+static void dia_set_pencolor(char *name)
+{
+ cstk[SP].pencolor = name;
+}
+
+static void dia_set_fillcolor(char *name)
+{
+ cstk[SP].fillcolor = name;
+}
+
+static void dia_set_style(char **s)
+{
+ char *line, *p;
+ context_t *cp;
+
+ cp = &(cstk[SP]);
+ while ((p = line = *s++)) {
+ if (streq(line, "solid"))
+ cp->pen = P_SOLID;
+ else if (streq(line, "dashed"))
+ cp->pen = P_DASHED;
+ else if (streq(line, "dotted"))
+ cp->pen = P_DOTTED;
+ else if (streq(line, "invis"))
+ cp->pen = P_NONE;
+ else if (streq(line, "bold"))
+ cp->penwidth = WIDTH_BOLD;
+ else if (streq(line, "setlinewidth")) {
+ while (*p)
+ p++;
+ p++;
+ cp->penwidth = atol(p);
+ } else if (streq(line, "filled"))
+ cp->fill = P_SOLID;
+ else if (streq(line, "unfilled"))
+ cp->fill = P_NONE;
+ else {
+ agwarn("dia_set_style: unsupported style %s - ignoring\n",
+ line);
+ }
+ cp->style_was_set = TRUE;
+ }
+ /* if (cp->style_was_set) dia_style(cp); */
+}
+
+static void dia_textpara(GVJ_t * job, point p, textpara_t * para)
+{
+ int anchor;
+ pointf mp;
+ context_t *cp;
+
+ cp = &(cstk[SP]);
+ switch (para->just) {
+ case 'l':
+ anchor = 0;
+ break;
+ case 'r':
+ anchor = 2;
+ break;
+ default:
+ case 'n':
+ anchor = 1;
+ break;
+ }
+
+ mp = dia_pt(p);
+ gvdevice_printf(job,
+ " <dia:object type=\"Standard - Text\" version=\"0\" id=\"%s\">\n",
+ "0");
+ gvdevice_fputs(job, " <dia:attribute name=\"text\">\n");
+ gvdevice_fputs(job, " <dia:composite type=\"text\">\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"string\">\n");
+ gvdevice_fputs(job, " <dia:string>#");
+ gvdevice_fputs(job, xml_string(para->str));
+ gvdevice_fputs(job, "#</dia:string>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"font\">\n");
+ gvdevice_printf(job, " <dia:font name=\"%s\"/>\n", cp->fontfam);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"height\">\n");
+ gvdevice_printf(job, " <dia:real val=\"%g\"/>\n",
+ Scale * (cp->fontsz));
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"pos\">\n");
+ gvdevice_printf(job, " <dia:point val=\"%g,%g\"/>\n", mp.x, mp.y);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"color\">\n");
+ gvdevice_printf(job, " <dia:color val=\"%s\"/>\n",
+ dia_resolve_color(cp->pencolor));
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"alignment\">\n");
+ gvdevice_printf(job, " <dia:enum val=\"%d\"/>\n", anchor);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " </dia:composite>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"obj_pos\">\n");
+ gvdevice_printf(job, " <dia:point val=\"%g,%g\"/>\n", mp.x, mp.y);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"obj_bb\">\n");
+ gvdevice_printf(job, " <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
+ mp.x - (Scale * (para->width) / 2.), mp.y - 0.4,
+ mp.x + (Scale * (para->width) / 2.), mp.y + 0.4);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " </dia:object>\n");
+}
+
+static void dia_ellipse(GVJ_t * job, pointf *A, int filled)
+{
+ pointf cp, rp;
+ int nodeId;
+
+ switch (Obj) {
+ case NODE:
+ nodeId = Curnode->id;
+ break;
+ default:
+ nodeId = -1;
+ break;
+ }
+
+ if (cstk[SP].pen == P_NONE) {
+ /* its invisible, don't draw */
+ return;
+ }
+ cp = dia_pt(p);
+
+ if (Rot) {
+ int t;
+ t = rx;
+ rx = ry;
+ ry = t;
+ }
+ rp.x = Scale * rx;
+ rp.y = Scale * ry;
+
+ gvdevice_printf(job,
+ " <dia:object type=\"Standard - Ellipse\" version=\"0\" id=\"%d\">\n",
+ nodeId);
+ gvdevice_fputs(job, " <dia:attribute name=\"elem_corner\">\n");
+ gvdevice_printf(job, " <dia:point val=\"%g,%g\"/>\n", cp.x - rp.x,
+ cp.y - rp.y);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"elem_width\">\n");
+ gvdevice_printf(job, " <dia:real val=\"%g\"/>\n", rp.x + rp.x);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"elem_height\">\n");
+ gvdevice_printf(job, " <dia:real val=\"%g\"/>\n", rp.y + rp.y);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"obj_pos\">\n");
+ gvdevice_printf(job, " <dia:point val=\"%g,%g\"/>\n", cp.x - rp.x,
+ cp.y - rp.y);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"obj_bb\">\n");
+ gvdevice_printf(job, " <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
+ cp.x - rp.x - .11, cp.y - rp.y - .11, cp.x + rp.x + .11,
+ cp.y + rp.y + .11);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ dia_style(job, &cstk[SP]);
+ dia_stylefill(job, &cstk[SP], filled);
+ gvdevice_fputs(job, " </dia:object>\n");
+}
+
+
+int ellipse_connection(pointf cp, pointf p)
+{
+ int conn = 0;
+
+ if (cp.x == p.x) {
+ if (cp.y > p.y)
+ conn = 1;
+ else
+ conn = 6;
+ } else if (cp.y == p.y) {
+ if (cp.x > p.x)
+ conn = 3;
+ else
+ conn = 4;
+ } else if (cp.x < p.x) {
+ if (cp.y < p.y)
+ conn = 7;
+ else
+ conn = 2;
+ } else if (cp.x > p.x) {
+ if (cp.y < p.y)
+ conn = 5;
+ else
+ conn = 0;
+ }
+
+ return conn;
+}
+
+
+int box_connection(node_t * n, pointf p)
+{
+ int i = 0, j, sides, conn = 0, peripheries, z;
+ double xsize, ysize, mindist2 = 0.0, dist2;
+ polygon_t *poly;
+ pointf P, *vertices;
+ static point *A;
+ static int A_size;
+
+ poly = (polygon_t *) ND_shape_info(n);
+ vertices = poly->vertices;
+ sides = poly->sides;
+ peripheries = poly->peripheries;
+
+ if (A_size < sides) {
+ A_size = sides + 5;
+ A = malloc(A_size*sizeof(pointf));
+ }
+
+ xsize = ((ND_lw_i(n) + ND_rw_i(n)) / POINTS(ND_width(n))) * 16.0;
+ ysize = ((ND_ht_i(n)) / POINTS(ND_height(n))) * 16.0;
+
+ for (j = 0; j < peripheries; j++) {
+ for (i = 0; i < sides; i++) {
+ P = vertices[i + j * sides];
+/* simple rounding produces random results around .5
+ * this trick should clip off the random part.
+ * (note xsize/ysize prescaled by 16.0 above) */
+ A[i].x = ROUND(P.x * xsize) / 16;
+ A[i].y = ROUND(P.y * ysize) / 16;
+ if (sides > 2) {
+ A[i].x += ND_coord_i(n).x;
+ A[i].y += ND_coord_i(n).y;
+ }
+ }
+ }
+
+ z = 0;
+ while (z < i) {
+ dist2 = DIST2(p, dia_pt(A[z]));
+ if (z == 0) {
+ mindist2 = dist2;
+ conn = 0;
+ }
+ if (dist2 < mindist2) {
+ mindist2 = dist2;
+ conn = 2 * z;
+ }
+ z++;
+ }
+
+ z = 0;
+ while (z < i) {
+ P.x = (dia_pt(A[z]).x + dia_pt(A[z + 1]).x) / 2;
+ P.y = (dia_pt(A[z]).y + dia_pt(A[z + 1]).y) / 2;
+ dist2 = DIST2(p, P);
+ if (dist2 < mindist2) {
+ mindist2 = dist2;
+ conn = 2 * z + 1;
+ }
+ z++;
+ }
+
+ return conn;
+}
+
+
+static void
+dia_bezier(GVJ_t *job, pointf * A, int n, int arrow_at_start, int arrow_at_end, int filled)
+{
+ int i, conn_h, conn_t;
+ pointf p, firstp = { 0, 0 }, llp = {
+ 0, 0}, urp = {
+ 0, 0};
+ node_t *head, *tail;
+ char *shape_t;
+ pointf cp_h, cp_t;
+
+ if (cstk[SP].pen == P_NONE) {
+ /* its invisible, don't draw */
+ return;
+ }
+
+ gvdevice_printf(job,
+ " <dia:object type=\"Standard - BezierLine\" version=\"0\" id=\"%s\">\n",
+ "00");
+ gvdevice_fputs(job, " <dia:attribute name=\"bez_points\">\n");
+ for (i = 0; i < n; i++) {
+ p = dia_pt(A[i]);
+ if (!i)
+ llp = urp = firstp = p;
+ if (p.x < llp.x || p.y < llp.y)
+ llp = p;
+ if (p.x > urp.x || p.y > urp.y)
+ urp = p;
+ gvdevice_printf(job, " <dia:point val=\"%g,%g\"/>\n", p.x, p.y);
+ }
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ dia_style(job, &cstk[SP]);
+ gvdevice_fputs(job, " <dia:attribute name=\"obj_pos\">\n");
+ gvdevice_printf(job, " <dia:point val=\"%g,%g\"/>\n", firstp.x, firstp.y);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"obj_bb\">\n");
+ gvdevice_printf(job, " <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
+ llp.x - .11, llp.y - .11, urp.x + .11, urp.y + .11);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ if (!Curedge) return;
+
+ conn_h = conn_t = -1;
+
+ head = Curedge->head;
+ tail = Curedge->tail;
+
+ shape_t = ND_shape(tail)->name;
+
+ /* arrowheads */
+ if (arrow_at_start) {
+ gvdevice_fputs(job, " <dia:attribute name=\"start_arrow\">\n");
+ gvdevice_fputs(job, " <dia:enum val=\"3\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"start_arrow_length\">\n");
+ gvdevice_fputs(job, " <dia:real val=\"0.8\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ dia_fputs
+ (" <dia:attribute name=\"start_arrow_width\">\n");
+ gvdevice_fputs(job, " <dia:real val=\"0.8\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ }
+ if (arrow_at_end) {
+ gvdevice_fputs(job, " <dia:attribute name=\"end_arrow\">\n");
+ gvdevice_fputs(job, " <dia:enum val=\"3\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"end_arrow_length\">\n");
+ gvdevice_fputs(job, " <dia:real val=\"0.8\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ dia_fputs
+ (" <dia:attribute name=\"end_arrow_width\">\n");
+ gvdevice_fputs(job, " <dia:real val=\"0.8\"/>\n");
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ }
+
+ gvdevice_fputs(job, " <dia:attribute name=\"conn_endpoints\">\n");
+ gvdevice_printf(job, " <dia:point val=\"%g,%g\"/>\n", dia_pt(A[0]).x,
+ dia_pt(A[0]).y);
+ gvdevice_printf(job, " <dia:point val=\"%g,%g\"/>\n", dia_pt(A[n - 1]).x,
+ dia_pt(A[n - 1]).y);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:connections>\n");
+
+ if ((strcmp(shape_t, "ellipse") == 0)
+ || (strcmp(shape_t, "circle") == 0)
+ || (strcmp(shape_t, "doublecircle") == 0)) {
+ cp_h = dia_pt(ND_coord_i(head));
+ if (AG_IS_DIRECTED(Rootgraph))
+ conn_h = ellipse_connection(cp_h, dia_pt(A[n - 1]));
+ else
+ conn_h = ellipse_connection(cp_h, dia_pt(A[0]));
+ } else {
+ if (AG_IS_DIRECTED(Rootgraph))
+ conn_h = box_connection(head, dia_pt(A[n - 1]));
+ else
+ conn_h = box_connection(head, dia_pt(A[0]));
+ }
+
+ if ((strcmp(shape_t, "ellipse") == 0)
+ || (strcmp(shape_t, "circle") == 0)
+ || (strcmp(shape_t, "doublecircle") == 0)) {
+ cp_t = dia_pt(ND_coord_i(tail));
+ if (AG_IS_DIRECTED(Rootgraph))
+ conn_t = ellipse_connection(cp_t, dia_pt(A[0]));
+ else
+ conn_t = ellipse_connection(cp_t, dia_pt(A[n - 1]));
+ } else {
+ if (AG_IS_DIRECTED(Rootgraph))
+ conn_t = box_connection(tail, dia_pt(A[0]));
+ else
+ conn_t = box_connection(tail, dia_pt(A[n - 1]));
+ }
+
+ if (arrow_at_start) {
+ gvdevice_printf(job,
+ " <dia:connection handle=\"0\" to=\"%d\" connection=\"%d\"/>\n",
+ head->id, conn_h);
+ gvdevice_printf(job,
+ " <dia:connection handle=\"%d\" to=\"%d\" connection=\"%d\"/>\n",
+ (n - 1), tail->id, conn_t);
+ } else {
+ gvdevice_printf(job,
+ " <dia:connection handle=\"0\" to=\"%d\" connection=\"%d\"/>\n",
+ tail->id, conn_t);
+ gvdevice_printf(job,
+ " <dia:connection handle=\"%d\" to=\"%d\" connection=\"%d\"/>\n",
+ (n - 1), head->id, conn_h);
+ }
+
+ gvdevice_fputs(job, " </dia:connections>\n");
+ gvdevice_fputs(job, " </dia:object>\n");
+}
+
+
+
+static void dia_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+ int i;
+ pointf p, firstp = { 0, 0 }, llp = {
+ 0, 0}, urp = {
+ 0, 0};
+
+ if (cstk[SP].pen == P_NONE) {
+ /* its invisible, don't draw */
+ return;
+ }
+
+ switch (Obj) {
+ case NODE:
+ gvdevice_printf(job,
+ " <dia:object type=\"Standard - Polygon\" version=\"0\" id=\"%d\">\n",
+ Curnode->id);
+ break;
+ case EDGE:
+ return;
+ break;
+ case CLST:
+ gvdevice_printf(job,
+ " <dia:object type=\"Standard - Polygon\" version=\"0\" id=\"%s\">\n",
+ Curgraph->name);
+ break;
+ default:
+ gvdevice_printf(job,
+ " <dia:object type=\"Standard - Polygon\" version=\"0\" id=\"%s\">\n",
+ "polygon");
+ break;
+ }
+ gvdevice_fputs(job, " <dia:attribute name=\"poly_points\">\n");
+ for (i = 0; i < n; i++) {
+ p = dia_pt(A[i]);
+ if (!i)
+ llp = urp = firstp = p;
+ if (p.x < llp.x || p.y < llp.y)
+ llp = p;
+ if (p.x > urp.x || p.y > urp.y)
+ urp = p;
+ gvdevice_printf(job, " <dia:point val=\"%g,%g\"/>\n", p.x, p.y);
+ }
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"obj_pos\">\n");
+ gvdevice_printf(job, " <dia:point val=\"%g,%g\"/>\n", firstp.x, firstp.y);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"obj_bb\">\n");
+ gvdevice_printf(job, " <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
+ llp.x - .11, llp.y - .11, urp.x + .11, urp.y + .11);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ dia_style(job, &cstk[SP]);
+ dia_stylefill(job, &cstk[SP], filled);
+ gvdevice_fputs(job, " </dia:object>\n");
+}
+
+static void dia_polyline(GVJ_t * job, pointf * A, int n)
+{
+ int i;
+ pointf p, firstp = { 0, 0 }, llp = {
+ 0, 0}, urp = {
+ 0, 0};
+
+ if (cstk[SP].pen == P_NONE) {
+ /* its invisible, don't draw */
+ return;
+ }
+ gvdevice_printf(job,
+ " <dia:object type=\"Standard - PolyLine\" version=\"0\" id=\"%s\">\n",
+ "0");
+ gvdevice_fputs(job, " <dia:attribute name=\"poly_points\">\n");
+ for (i = 0; i < n; i++) {
+ p = dia_pt(A[i]);
+ if (!i)
+ llp = urp = firstp = p;
+ if (p.x < llp.x || p.y < llp.y)
+ llp = p;
+ if (p.x > urp.x || p.y > urp.y)
+ urp = p;
+ gvdevice_printf(job, "<dia:point val=\"%g,%g\"/>\n", p.x, p.y);
+ }
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ dia_style(job, &cstk[SP]);
+ gvdevice_fputs(job, " <dia:attribute name=\"obj_pos\">\n");
+ gvdevice_printf(job, " <dia:point val=\"%g,%g\"/>\n", firstp.x, firstp.y);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " <dia:attribute name=\"obj_bb\">\n");
+ gvdevice_printf(job, " <dia:rectangle val=\"%g,%g;%g,%g\"/>\n",
+ llp.x - .11, llp.y - .11, urp.x + .11, urp.y + .11);
+ gvdevice_fputs(job, " </dia:attribute>\n");
+ gvdevice_fputs(job, " </dia:object>\n");
+}
+
+gvrender_engine_t dia_engine = {
+ dia_begin_job, dia_end_job,
+ dia_begin_graph, dia_end_graph,
+ 0, /* dia_begin_layer */ 0, /* dia_end_layer */
+ dia_begin_page, dia_end_page,
+ dia_begin_cluster, dia_end_cluster,
+ 0, /* dia_begin_nodes */ 0, /* dia_end_nodes */
+ 0, /* dia_begin_edges */ 0, /* dia_end_edges */
+ dia_begin_node, dia_end_node,
+ dia_begin_edge, dia_end_edge,
+ 0, /* dia_begin_anchor */ 0, /* dia_end_anchor */
+ dia_textpara, dia_resolve_color,
+ dia_ellipse, dia_polygon,
+ dia_bezier, dia_polyline,
+ dia_comment,
+ 0, /* dia_library_shape */
+};
+
+/* NB. List must be LANG_C sorted */
+static char *dia_knowncolors[] = {
+ "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow",
+};
+
+
+gvrender_features_t dia_features = {
+ GVDEVICE_BINARY_FORMAT
+ GVDEVICE_COMPRESSED_FORMAT
+ | GVRENDER_Y_GOES_DOWN, /* flags */
+ DEFAULT_EMBED_MARGIN, /* default margin - points */
+ 4., /* default pad - graph units */
+ {0.,0.}, /* default page width, height - points */
+ {72.,72.}, /* default dpi */
+ dia_knowncolors, /* knowncolors */
+ sizeof(dia_knowncolors) / sizeof(char *), /* sizeof knowncolors */
+ RGBA_BYTE, /* color_type */
+};
+
+gvplugin_installed_t gvrender_core_dia_types[] = {
+ {FORMAT_DIA, "dia", -1, &dia_engine, &dia_features},
+ {0, NULL, 0, NULL, NULL}
+};
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <io.h>
+#include "compat.h"
+#endif
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+#include "graph.h"
+#include "agxbuf.h"
+#include "utils.h"
+#include "color.h"
+
+/* Number of points to split splines into */
+#define BEZIERSUBDIVISION 6
+
+typedef enum { FORMAT_HPGL, } format_type;
+
+static int Depth;
+
+static void hpglptarray(GVJ_t *job, pointf * A, int n, int close)
+{
+ int i;
+ point p;
+
+ for (i = 0; i < n; i++) {
+ PF2P(A[i],p);
+ gvdevice_printf(job, " %d %d", p.x, p.y);
+ }
+ if (close) {
+ PF2P(A[0],p);
+ gvdevice_printf(job, " %d %d", p.x, p.y);
+ }
+ gvdevice_fputs(job, "\n");
+}
+
+static char *hpgl_string(char *s)
+{
+ static char *buf = NULL;
+ static int bufsize = 0;
+ int pos = 0;
+ char *p;
+ unsigned char c;
+
+ if (!buf) {
+ bufsize = 64;
+ buf = malloc(bufsize * sizeof(char));
+ }
+
+ p = buf;
+ while ((c = *s++)) {
+ if (pos > (bufsize - 8)) {
+ bufsize *= 2;
+ buf = realloc(buf, bufsize * sizeof(char));
+ p = buf + pos;
+ }
+ if (isascii(c)) {
+ if (c == '\\') {
+ *p++ = '\\';
+ pos++;
+ }
+ *p++ = c;
+ pos++;
+ } else {
+ *p++ = '\\';
+ sprintf(p, "%03o", c);
+ p += 3;
+ pos += 4;
+ }
+ }
+ *p = '\0';
+ return buf;
+}
+
+static int hpglColorResolve(int *new, int r, int g, int b)
+{
+#define maxColors 256
+ static int top = 0;
+ static short red[maxColors], green[maxColors], blue[maxColors];
+ int c;
+ int ct = -1;
+ long rd, gd, bd, dist;
+ long mindist = 3 * 255 * 255; /* init to max poss dist */
+
+ *new = 0; /* in case it is not a new color */
+ for (c = 0; c < top; c++) {
+ rd = (long) (red[c] - r);
+ gd = (long) (green[c] - g);
+ bd = (long) (blue[c] - b);
+ dist = rd * rd + gd * gd + bd * bd;
+ if (dist < mindist) {
+ if (dist == 0)
+ return c; /* Return exact match color */
+ mindist = dist;
+ ct = c;
+ }
+ }
+ /* no exact match. We now know closest, but first try to allocate exact */
+ if (top++ == maxColors)
+ return ct; /* Return closest available color */
+ red[c] = r;
+ green[c] = g;
+ blue[c] = b;
+ *new = 1; /* flag new color */
+ return c; /* Return newly allocated color */
+}
+
+/* this table is in xfig color index order */
+static char *hpglcolor[] = {
+ "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL
+};
+
+static void hpgl_resolve_color(GVJ_t *job, gvcolor_t * color)
+{
+ int object_code = 0; /* always 0 for color */
+ int i, new;
+
+ switch (color->type) {
+ case COLOR_STRING:
+ for (i = 0; hpglcolor[i]; i++) {
+ if (streq(hpglcolor[i], color->u.string)) {
+ color->u.index = i;
+ break;
+ }
+ }
+ break;
+ case RGBA_BYTE:
+ i = 32 + hpglColorResolve(&new,
+ color->u.rgba[0],
+ color->u.rgba[1],
+ color->u.rgba[2]);
+ if (new)
+ gvdevice_printf(job, "%d %d #%02x%02x%02x\n",
+ object_code, i,
+ color->u.rgba[0],
+ color->u.rgba[1],
+ color->u.rgba[2]);
+ color->u.index = i;
+ break;
+ default:
+ assert(0); /* internal error */
+ }
+
+ color->type = COLOR_INDEX;
+}
+
+static void hpgl_line_style(obj_state_t *obj, int *line_style, double *style_val)
+{
+ switch (obj->pen) {
+ case PEN_DASHED:
+ *line_style = 1;
+ *style_val = 10.;
+ break;
+ case PEN_DOTTED:
+ *line_style = 2;
+ *style_val = 10.;
+ break;
+ case PEN_SOLID:
+ default:
+ *line_style = 0;
+ *style_val = 0.;
+ break;
+ }
+}
+
+static void hpgl_comment(GVJ_t *job, char *str)
+{
+ gvdevice_printf(job, "# %s\n", str);
+}
+
+static void hpgl_begin_graph(GVJ_t * job)
+{
+ obj_state_t *obj = job->obj;
+
+ gvdevice_fputs(job, "#FIG 3.2\n");
+ gvdevice_printf(job, "# Generated by %s version %s (%s)\n",
+ job->common->info[0], job->common->info[1], job->common->info[2]);
+ gvdevice_printf(job, "# For: %s\n", job->common->user);
+ gvdevice_printf(job, "# Title: %s\n", obj->u.g->name);
+ gvdevice_printf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
+ gvdevice_fputs(job, "Portrait\n"); /* orientation */
+ gvdevice_fputs(job, "Center\n"); /* justification */
+ gvdevice_fputs(job, "Inches\n"); /* units */
+ gvdevice_fputs(job, "Letter\n"); /* papersize */
+ gvdevice_fputs(job, "100.00\n"); /* magnification % */
+ gvdevice_fputs(job, "Single\n"); /* multiple-page */
+ gvdevice_fputs(job, "-2\n"); /* transparent color (none) */
+ gvdevice_fputs(job, "1200"); /* resolution */
+ gvdevice_fputs(job, " 2\n"); /* coordinate system (upper left) */
+}
+
+static void hpgl_end_graph(GVJ_t * job)
+{
+ gvdevice_fputs(job, "# end of FIG file\n");
+}
+
+static void hpgl_begin_page(GVJ_t * job)
+{
+ Depth = 2;
+}
+
+static void hpgl_begin_node(GVJ_t * job)
+{
+ Depth = 1;
+}
+
+static void hpgl_end_node(GVJ_t * job)
+{
+ Depth = 2;
+}
+
+static void hpgl_begin_edge(GVJ_t * job)
+{
+ Depth = 0;
+}
+
+static void hpgl_end_edge(GVJ_t * job)
+{
+ Depth = 2;
+}
+
+static void hpgl_textpara(GVJ_t * job, pointf p, textpara_t * para)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 4; /* always 4 for text */
+ int sub_type = 0; /* text justification */
+ int color = obj->pencolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int font = -1; /* init to xfig's default font */
+ double font_size = para->fontsize * job->zoom;
+ double angle = job->rotation ? (PI / 2.0) : 0.0;
+ int font_flags = 4; /* PostScript font */
+ double height = 0.0;
+ double length = 0.0;
+
+ if (para->postscript_alias) /* if it is a standard postscript font */
+ font = para->postscript_alias->xfig_code;
+
+ switch (para->just) {
+ case 'l':
+ sub_type = 0;
+ break;
+ case 'r':
+ sub_type = 2;
+ break;
+ default:
+ case 'n':
+ sub_type = 1;
+ break;
+ }
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n",
+ object_code, sub_type, color, depth, pen_style, font,
+ font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y),
+ hpgl_string(para->str));
+}
+
+static void hpgl_ellipse(GVJ_t * job, pointf * A, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 1; /* always 1 for ellipse */
+ int sub_type = 1; /* ellipse defined by radii */
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = obj->fillcolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill = filled ? 20 : -1;
+ double style_val;
+ int direction = 0;
+ double angle = 0.0;
+ int center_x, center_y, radius_x, radius_y;
+ int start_x, start_y, end_x, end_y;
+
+ hpgl_line_style(obj, &line_style, &style_val);
+
+ start_x = center_x = ROUND(A[0].x);
+ start_y = center_y = ROUND(A[0].y);
+ radius_x = ROUND(A[1].x - A[0].x);
+ radius_y = ROUND(A[1].y - A[0].y);
+ end_x = ROUND(A[1].x);
+ end_y = ROUND(A[1].y);
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n",
+ object_code, sub_type, line_style, thickness, pen_color,
+ fill_color, depth, pen_style, area_fill, style_val, direction,
+ angle, center_x, center_y, radius_x, radius_y, start_x,
+ start_y, end_x, end_y);
+}
+
+static void hpgl_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
+ int arrow_at_end, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 3; /* always 3 for spline */
+ int sub_type;
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = obj->fillcolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill;
+ double style_val;
+ int cap_style = 0;
+ int forward_arrow = 0;
+ int backward_arrow = 0;
+ int npoints = n;
+ int i;
+
+ pointf pf, V[4];
+ point p;
+ int j, step;
+ int count = 0;
+ int size;
+
+ char *buffer;
+ char *buf;
+ buffer =
+ malloc((npoints + 1) * (BEZIERSUBDIVISION +
+ 1) * 20 * sizeof(char));
+ buf = buffer;
+
+ hpgl_line_style(obj, &line_style, &style_val);
+
+ if (filled) {
+ sub_type = 5; /* closed X-spline */
+ area_fill = 20; /* fully saturated color */
+ fill_color = job->obj->fillcolor.u.index;
+ }
+ else {
+ sub_type = 4; /* opened X-spline */
+ area_fill = -1;
+ fill_color = 0;
+ }
+ V[3].x = A[0].x;
+ V[3].y = A[0].y;
+ /* Write first point in line */
+ count++;
+ PF2P(A[0], p);
+ size = sprintf(buf, " %d %d", p.x, p.y);
+ buf += size;
+ /* write subsequent points */
+ for (i = 0; i + 3 < n; i += 3) {
+ V[0] = V[3];
+ for (j = 1; j <= 3; j++) {
+ V[j].x = A[i + j].x;
+ V[j].y = A[i + j].y;
+ }
+ for (step = 1; step <= BEZIERSUBDIVISION; step++) {
+ count++;
+ pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
+ PF2P(pf, p);
+ size = sprintf(buf, " %d %d", p.x, p.y);
+ buf += size;
+ }
+ }
+
+ gvdevice_printf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
+ object_code,
+ sub_type,
+ line_style,
+ thickness,
+ pen_color,
+ fill_color,
+ depth,
+ pen_style,
+ area_fill,
+ style_val, cap_style, forward_arrow, backward_arrow, count);
+
+ gvdevice_printf(job, " %s\n", buffer); /* print points */
+ free(buffer);
+ for (i = 0; i < count; i++) {
+ gvdevice_printf(job, " %d", i % (count - 1) ? 1 : 0); /* -1 on all */
+ }
+ gvdevice_fputs(job, "\n");
+}
+
+static void hpgl_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 2; /* always 2 for polyline */
+ int sub_type = 3; /* always 3 for polygon */
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = obj->fillcolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill = filled ? 20 : -1;
+ double style_val;
+ int join_style = 0;
+ int cap_style = 0;
+ int radius = 0;
+ int forward_arrow = 0;
+ int backward_arrow = 0;
+ int npoints = n + 1;
+
+ hpgl_line_style(obj, &line_style, &style_val);
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+ object_code, sub_type, line_style, thickness, pen_color,
+ fill_color, depth, pen_style, area_fill, style_val, join_style,
+ cap_style, radius, forward_arrow, backward_arrow, npoints);
+ hpglptarray(job, A, n, 1); /* closed shape */
+}
+
+static void hpgl_polyline(GVJ_t * job, pointf * A, int n)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 2; /* always 2 for polyline */
+ int sub_type = 1; /* always 1 for polyline */
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = 0;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill = 0;
+ double style_val;
+ int join_style = 0;
+ int cap_style = 0;
+ int radius = 0;
+ int forward_arrow = 0;
+ int backward_arrow = 0;
+ int npoints = n;
+
+ hpgl_line_style(obj, &line_style, &style_val);
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+ object_code, sub_type, line_style, thickness, pen_color,
+ fill_color, depth, pen_style, area_fill, style_val, join_style,
+ cap_style, radius, forward_arrow, backward_arrow, npoints);
+ hpglptarray(job, A, n, 0); /* open shape */
+}
+
+gvrender_engine_t hpgl_engine = {
+ 0, /* hpgl_begin_job */
+ 0, /* hpgl_end_job */
+ hpgl_begin_graph,
+ hpgl_end_graph,
+ 0, /* hpgl_begin_layer */
+ 0, /* hpgl_end_layer */
+ hpgl_begin_page,
+ 0, /* hpgl_end_page */
+ 0, /* hpgl_begin_cluster */
+ 0, /* hpgl_end_cluster */
+ 0, /* hpgl_begin_nodes */
+ 0, /* hpgl_end_nodes */
+ 0, /* hpgl_begin_edges */
+ 0, /* hpgl_end_edges */
+ hpgl_begin_node,
+ hpgl_end_node,
+ hpgl_begin_edge,
+ hpgl_end_edge,
+ 0, /* hpgl_begin_anchor */
+ 0, /* hpgl_end_anchor */
+ hpgl_textpara,
+ hpgl_resolve_color,
+ hpgl_ellipse,
+ hpgl_polygon,
+ hpgl_bezier,
+ hpgl_polyline,
+ hpgl_comment,
+ 0, /* hpgl_library_shape */
+};
+
+
+/* NB. List must be LANG_C sorted */
+static char *hpgl_knowncolors[] = {
+ "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow",
+};
+
+
+gvrender_features_t hpgl_features = {
+ EMIT_COLORS
+ | GVRENDER_Y_GOES_DOWN, /* flags */
+ DEFAULT_EMBED_MARGIN, /* default margin - points */
+ 4., /* default pad - graph units */
+ {0.,0.}, /* default page width, height - points */
+ {1440.,1440.}, /* default dpi */
+ /* FIXME - this default dpi is a very strange number!!!
+ * It was picked to make .png usershapes the right size on my screen.
+ * It happens to be 1.2 * 1200, but I can't explain the 1.2.
+ * (I was expecting 1.3333 which is 96/72, but thats too big.)
+ * Also 1200 is hardcoded in hpgl_begin_graph() instead of using job->dpi
+ */
+
+ /* It may be TWIPS, i.e. 20 * POINT_PER_INCH
+ * but that doesn't explain what the 1200 is? */
+
+ hpgl_knowncolors, /* knowncolors */
+ sizeof(hpgl_knowncolors) / sizeof(char *), /* sizeof knowncolors */
+ RGBA_BYTE, /* color_type */
+ "hpgl", /* imageloader for usershapes */
+};
+
+gvplugin_installed_t gvrender_hpgl_types[] = {
+ {FORMAT_HPGL, "hpgl", -1, &hpgl_engine, &hpgl_features},
+ {0, NULL, 0, NULL, NULL}
+};
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+#include "gvcint.h"
+#include "graph.h"
+
+typedef enum { FORMAT_MIF, } format_type;
+
+/* MIF font modifiers */
+#define REGULAR 0
+#define BOLD 1
+#define ITALIC 2
+
+/* MIF patterns */
+#define P_SOLID 0
+#define P_NONE 15
+#define P_DOTTED 4 /* i wasn't sure about this */
+#define P_DASHED 11 /* or this */
+
+/* MIF bold line constant */
+#define WIDTH_NORMAL 1
+#define WIDTH_BOLD 3
+
+static char *FillStr = "<Fill 3>";
+static char *NoFillStr = "<Fill 15>";
+
+static void mif_ptarray(GVJ_t * job, pointf * A, int n)
+{
+ int i;
+
+ gvdevice_printf(job, " <NumPoints %d>\n", n);
+ for (i = 0; i < n; i++)
+ gvdevice_printf(job, " <Point %.2f %.2f>\n", A[i].x, A[i].y);
+}
+
+typedef struct {
+ char *name;
+ int CMYK[4];
+} mif_color_t;
+
+static mif_color_t mif_colors[] = {
+ {"Black", {0, 0, 0, 100}},
+ {"White", {0, 0, 0, 0}},
+ {"Red", {0, 100, 100, 0}},
+ {"Green", {100, 0, 100, 0}},
+ {"Blue", {100, 100, 0, 0}},
+ {"Cyan", {100, 0, 0, 0}},
+ {"Magenta", {0, 100, 0, 0}},
+ {"Yellow", {0, 0, 100, 0}},
+ {"aquamarine", {100, 0, 0, 18}},
+ {"plum", {0, 100, 0, 33}},
+ {"peru", {0, 24, 100, 32}},
+ {"pink", {0, 50, 0, 0}},
+ {"mediumpurple", {10, 100, 0, 0}},
+ {"grey", {0, 0, 0, 50}},
+ {"lightgrey", {0, 0, 0, 25}},
+ {"lightskyblue", {38, 33, 0, 0}},
+ {"lightcoral", {0, 50, 60, 0}},
+ {"yellowgreen", {31, 0, 100, 0}},
+};
+
+static void mif_color(GVJ_t * job, int i)
+{
+ if (isupper(mif_colors[i].name[0]))
+ gvdevice_printf(job, "<Separation %d>\n", i);
+ else
+ gvdevice_printf(job, "<ObColor `%s'>\n", mif_colors[i].name);
+}
+
+#if 0
+static void mif_style(GVJ_t * job, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ gvdevice_fputs(job, "style=\"fill:");
+ if (filled)
+ mif_color(job->obj->fillcolor);
+ else
+ gvdevice_fputs(job, "none");
+
+ gvdevice_fputs(job, ";stroke:");
+
+
+
+ while ((line = *s++)) {
+ if (streq(line, "solid"))
+ pen = P_SOLID;
+ else if (streq(line, "dashed"))
+ pen = P_DASHED;
+ else if (streq(line, "dotted"))
+ pen = P_DOTTED;
+ else if (streq(line, "invis"))
+ pen = P_NONE;
+ else if (streq(line, "bold"))
+ penwidth = WIDTH_BOLD;
+ else if (streq(line, "filled"))
+ fill = P_SOLID;
+ else if (streq(line, "unfilled"))
+ fill = P_NONE;
+ else {
+ agerr(AGERR,
+ "mif_style: unsupported style %s - ignoring\n",
+ line);
+ }
+ }
+
+ fw = fa = "Regular";
+ switch (cp->fontopt) {
+ case BOLD:
+ fw = "Bold";
+ break;
+ case ITALIC:
+ fa = "Italic";
+ break;
+ }
+ gvdevice_printf(job,
+ "<Font <FFamily `%s'> <FSize %.1f pt> <FWeight %s> <FAngle %s>>\n",
+ cp->fontfam, job->scale.x * cp->fontsz, fw, fa);
+
+ gvdevice_printf(job, "<Pen %d> <Fill %d> <PenWidth %d>\n",
+ job->pen, job->fill, job->penwidth);
+}
+#endif
+
+static void mif_comment(GVJ_t * job, char *str)
+{
+ gvdevice_printf(job, "# %s\n", str);
+}
+
+static void mif_color_declaration(GVJ_t * job, char *str, int CMYK[4])
+{
+ gvdevice_fputs(job, " <Color \n");
+ gvdevice_printf(job, " <ColorTag `%s'>\n", str);
+ gvdevice_printf(job, " <ColorCyan %d.000000>\n", CMYK[0]);
+ gvdevice_printf(job, " <ColorMagenta %d.000000>\n", CMYK[1]);
+ gvdevice_printf(job, " <ColorYellow %d.000000>\n", CMYK[2]);
+ gvdevice_printf(job, " <ColorBlack %d.000000>\n", CMYK[3]);
+ if (isupper(str[0])) {
+ gvdevice_printf(job, " <ColorAttribute ColorIs%s>\n", str);
+ gvdevice_fputs(job, " <ColorAttribute ColorIsReserved>\n");
+ }
+ gvdevice_fputs(job, " > # end of Color\n");
+}
+
+static void
+mif_begin_job(GVJ_t * job)
+{
+ gvdevice_init_compression(job, COMPRESSION_NONE);
+ gvdevice_printf(job,
+ "<MIFFile 3.00> # Generated by %s version %s (%s)\n",
+ job->common->info[0], job->common->info[1], job->common->info[2]);
+}
+
+static void mif_end_job(GVJ_t * job)
+{
+ gvdevice_fputs(job, "# end of MIFFile\n");
+ gvdevice_fini_compression(job);
+}
+
+static void mif_begin_graph(GVJ_t * job)
+{
+ int i;
+
+ gvdevice_printf(job, "# For: %s\n", job->common->user);
+ gvdevice_printf(job, "# Title: %s\n", job->obj->u.g->name);
+ gvdevice_printf(job, "# Pages: %d\n",
+ job->pagesArraySize.x * job->pagesArraySize.y);
+ gvdevice_fputs(job, "<Units Upt>\n");
+ gvdevice_fputs(job, "<ColorCatalog \n");
+ for (i = 0; i < (sizeof(mif_colors) / sizeof(mif_color_t)); i++)
+ mif_color_declaration(job, mif_colors[i].name, mif_colors[i].CMYK);
+ gvdevice_fputs(job, "> # end of ColorCatalog\n");
+ gvdevice_printf(job, "<BRect %g %g %g %g>\n",
+ job->canvasBox.LL.x,
+ job->canvasBox.UR.y,
+ job->canvasBox.UR.x - job->canvasBox.LL.x,
+ job->canvasBox.UR.y - job->canvasBox.LL.y);
+}
+
+static void
+mif_begin_page(GVJ_t *job)
+{
+ gvdevice_printf(job,
+ " <ArrowStyle <TipAngle 15> <BaseAngle 90> <Length %.1f> <HeadType Filled>>\n",
+ 14 * job->scale.x);
+}
+
+static void mif_set_color(GVJ_t * job, char *name)
+{
+ int i;
+
+ for (i = 0; i < (sizeof(mif_colors)/sizeof(mif_color_t)); i++) {
+ if (strcasecmp(mif_colors[i].name, name) == 0)
+ mif_color(job, i);
+ }
+ agerr(AGERR, "color %s not supported in MIF\n", name);
+}
+
+static char *mif_string(GVJ_t * job, char *s)
+{
+ static char *buf = NULL;
+ static int bufsize = 0;
+ int pos = 0;
+ char *p, esc;
+
+ if (!buf) {
+ bufsize = 64;
+ buf = malloc(bufsize);
+ }
+
+ p = buf;
+ while (*s) {
+ if (pos > (bufsize - 8)) {
+ bufsize *= 2;
+ buf = realloc(buf, bufsize);
+ p = buf + pos;
+ }
+ esc = 0;
+ switch (*s) {
+ case '\t':
+ esc = 't';
+ break;
+ case '>':
+ case '\'':
+ case '`':
+ case '\\':
+ esc = *s;
+ break;
+ }
+ if (esc) {
+ *p++ = '\\';
+ *p++ = esc;
+ pos += 2;
+ } else {
+ *p++ = *s;
+ pos++;
+ }
+ s++;
+ }
+ *p = '\0';
+ return buf;
+}
+
+static void mif_textpara(GVJ_t * job, pointf p, textpara_t * para)
+{
+ char *anchor;
+
+// p.y -= para->font.size / 2 + 2;
+ switch (para->just) {
+ case 'l':
+ anchor = "Left";
+ break;
+ case 'r':
+ anchor = "Right";
+ break;
+ default:
+ case 'n':
+ anchor = "Center";
+ break;
+ }
+ gvdevice_printf(job,
+ "<TextLine <Angle %d> <TLOrigin %.2f %.2f> <TLAlignment %s>",
+ job->rotation, p.x, p.y, anchor);
+ gvdevice_printf(job, " <String `%s'>>\n", mif_string(job, para->str));
+}
+
+static void mif_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
+ int arrow_at_end, int filled)
+{
+ gvdevice_printf(job,
+ "<PolyLine <Fill 15> <Smoothed Yes> <HeadCap Square>\n");
+ mif_ptarray(job, A, n);
+ gvdevice_fputs(job, ">\n");
+}
+
+static void mif_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+ gvdevice_printf(job, "<Polygon %s\n", (filled ? FillStr : NoFillStr));
+ mif_ptarray(job, A, n);
+ gvdevice_fputs(job, ">\n");
+}
+
+static void mif_ellipse(GVJ_t * job, pointf * A, int filled)
+{
+ pointf dia;
+
+ dia.x = (A[1].x - A[0].x) * 2;
+ dia.y = (A[1].y - A[0].y) * 2;
+
+ gvdevice_printf(job, "<Ellipse %s <BRect %.2f %.2f %.1f %.1f>>\n",
+ filled ? FillStr : NoFillStr,
+ A[1].x - dia.x, A[1].y, dia.x, -dia.y);
+}
+
+static void mif_polyline(GVJ_t * job, pointf * A, int n)
+{
+ gvdevice_fputs(job, "<PolyLine <HeadCap Square>\n");
+ mif_ptarray(job, A, n);
+ gvdevice_fputs(job, ">\n");
+}
+
+gvrender_engine_t mif_engine = {
+ mif_begin_job,
+ mif_end_job,
+ mif_begin_graph,
+ 0, /* mif_end_graph */
+ 0, /* mif_begin_layer */
+ 0, /* mif_end_layer */
+ mif_begin_page,
+ 0, /* mif_end_page */
+ 0, /* mif_begin_cluster */
+ 0, /* mif_end_cluster */
+ 0, /* mif_begin_nodes */
+ 0, /* mif_end_nodes */
+ 0, /* mif_begin_edges */
+ 0, /* mif_end_edges */
+ 0, /* mif_begin_node */
+ 0, /* mif_end_node */
+ 0, /* mif_begin_edge */
+ 0, /* mif_end_edge */
+ 0, /* mif_begin_anchor */
+ 0, /* mif_end_anchor */
+ mif_textpara,
+ 0, /* mif_resolve_color */
+ mif_ellipse,
+ mif_polygon,
+ mif_bezier,
+ mif_polyline,
+ mif_comment,
+ 0, /* mif_library_shape */
+};
+
+gvrender_features_t mif_features = {
+ GVRENDER_Y_GOES_DOWN, /* flags */
+ DEFAULT_PRINT_MARGIN, /* default margin - points */
+ 4., /* default pad - graph units */
+ {0.,0.}, /* default page width, height - points */
+ {72.,72.}, /* default dpi */
+ NULL, /* knowncolors */
+ 0, /* sizeof knowncolors */
+ CMYK_BYTE, /* color_type */
+};
+
+gvplugin_installed_t gvrender_mif_types[] = {
+ {FORMAT_MIF, "mif", -1, &mif_engine, &mif_features},
+ {0, NULL, 0, NULL, NULL}
+};
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <io.h>
+#include "compat.h"
+#endif
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+#include "graph.h"
+#include "agxbuf.h"
+#include "utils.h"
+#include "color.h"
+
+/* Number of points to split splines into */
+#define BEZIERSUBDIVISION 6
+
+typedef enum { FORMAT_MP, } format_type;
+
+static int Depth;
+
+static void mpptarray(GVJ_t *job, pointf * A, int n, int close)
+{
+ int i;
+ point p;
+
+ for (i = 0; i < n; i++) {
+ PF2P(A[i],p);
+ gvdevice_printf(job, " %d %d", p.x, p.y);
+ }
+ if (close) {
+ PF2P(A[0],p);
+ gvdevice_printf(job, " %d %d", p.x, p.y);
+ }
+ gvdevice_fputs(job, "\n");
+}
+
+static char *mp_string(char *s)
+{
+ static char *buf = NULL;
+ static int bufsize = 0;
+ int pos = 0;
+ char *p;
+ unsigned char c;
+
+ if (!buf) {
+ bufsize = 64;
+ buf = malloc(bufsize * sizeof(char));
+ }
+
+ p = buf;
+ while ((c = *s++)) {
+ if (pos > (bufsize - 8)) {
+ bufsize *= 2;
+ buf = realloc(buf, bufsize * sizeof(char));
+ p = buf + pos;
+ }
+ if (isascii(c)) {
+ if (c == '\\') {
+ *p++ = '\\';
+ pos++;
+ }
+ *p++ = c;
+ pos++;
+ } else {
+ *p++ = '\\';
+ sprintf(p, "%03o", c);
+ p += 3;
+ pos += 4;
+ }
+ }
+ *p = '\0';
+ return buf;
+}
+
+static int mpColorResolve(int *new, int r, int g, int b)
+{
+#define maxColors 256
+ static int top = 0;
+ static short red[maxColors], green[maxColors], blue[maxColors];
+ int c;
+ int ct = -1;
+ long rd, gd, bd, dist;
+ long mindist = 3 * 255 * 255; /* init to max poss dist */
+
+ *new = 0; /* in case it is not a new color */
+ for (c = 0; c < top; c++) {
+ rd = (long) (red[c] - r);
+ gd = (long) (green[c] - g);
+ bd = (long) (blue[c] - b);
+ dist = rd * rd + gd * gd + bd * bd;
+ if (dist < mindist) {
+ if (dist == 0)
+ return c; /* Return exact match color */
+ mindist = dist;
+ ct = c;
+ }
+ }
+ /* no exact match. We now know closest, but first try to allocate exact */
+ if (top++ == maxColors)
+ return ct; /* Return closest available color */
+ red[c] = r;
+ green[c] = g;
+ blue[c] = b;
+ *new = 1; /* flag new color */
+ return c; /* Return newly allocated color */
+}
+
+/* this table is in xfig color index order */
+static char *mpcolor[] = {
+ "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL
+};
+
+static void mp_resolve_color(GVJ_t *job, gvcolor_t * color)
+{
+ int object_code = 0; /* always 0 for color */
+ int i, new;
+
+ switch (color->type) {
+ case COLOR_STRING:
+ for (i = 0; mpcolor[i]; i++) {
+ if (streq(mpcolor[i], color->u.string)) {
+ color->u.index = i;
+ break;
+ }
+ }
+ break;
+ case RGBA_BYTE:
+ i = 32 + mpColorResolve(&new,
+ color->u.rgba[0],
+ color->u.rgba[1],
+ color->u.rgba[2]);
+ if (new)
+ gvdevice_printf(job, "%d %d #%02x%02x%02x\n",
+ object_code, i,
+ color->u.rgba[0],
+ color->u.rgba[1],
+ color->u.rgba[2]);
+ color->u.index = i;
+ break;
+ default:
+ assert(0); /* internal error */
+ }
+
+ color->type = COLOR_INDEX;
+}
+
+static void mp_line_style(obj_state_t *obj, int *line_style, double *style_val)
+{
+ switch (obj->pen) {
+ case PEN_DASHED:
+ *line_style = 1;
+ *style_val = 10.;
+ break;
+ case PEN_DOTTED:
+ *line_style = 2;
+ *style_val = 10.;
+ break;
+ case PEN_SOLID:
+ default:
+ *line_style = 0;
+ *style_val = 0.;
+ break;
+ }
+}
+
+static void mp_comment(GVJ_t *job, char *str)
+{
+ gvdevice_printf(job, "# %s\n", str);
+}
+
+static void mp_begin_graph(GVJ_t * job)
+{
+ obj_state_t *obj = job->obj;
+
+ gvdevice_fputs(job, "#FIG 3.2\n");
+ gvdevice_printf(job, "# Generated by %s version %s (%s)\n",
+ job->common->info[0], job->common->info[1], job->common->info[2]);
+ gvdevice_printf(job, "# For: %s\n", job->common->user);
+ gvdevice_printf(job, "# Title: %s\n", obj->u.g->name);
+ gvdevice_printf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
+ gvdevice_fputs(job, "Portrait\n"); /* orientation */
+ gvdevice_fputs(job, "Center\n"); /* justification */
+ gvdevice_fputs(job, "Inches\n"); /* units */
+ gvdevice_fputs(job, "Letter\n"); /* papersize */
+ gvdevice_fputs(job, "100.00\n"); /* magnification % */
+ gvdevice_fputs(job, "Single\n"); /* multiple-page */
+ gvdevice_fputs(job, "-2\n"); /* transparent color (none) */
+ gvdevice_fputs(job, "1200"); /* resolution */
+ gvdevice_fputs(job, " 2\n"); /* coordinate system (upper left) */
+}
+
+static void mp_end_graph(GVJ_t * job)
+{
+ gvdevice_fputs(job, "# end of FIG file\n");
+}
+
+static void mp_begin_page(GVJ_t * job)
+{
+ Depth = 2;
+}
+
+static void mp_begin_node(GVJ_t * job)
+{
+ Depth = 1;
+}
+
+static void mp_end_node(GVJ_t * job)
+{
+ Depth = 2;
+}
+
+static void mp_begin_edge(GVJ_t * job)
+{
+ Depth = 0;
+}
+
+static void mp_end_edge(GVJ_t * job)
+{
+ Depth = 2;
+}
+
+static void mp_textpara(GVJ_t * job, pointf p, textpara_t * para)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 4; /* always 4 for text */
+ int sub_type = 0; /* text justification */
+ int color = obj->pencolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int font = -1; /* init to xfig's default font */
+ double font_size = para->fontsize * job->zoom;
+ double angle = job->rotation ? (PI / 2.0) : 0.0;
+ int font_flags = 4; /* PostScript font */
+ double height = 0.0;
+ double length = 0.0;
+
+ if (para->postscript_alias) /* if it is a standard postscript font */
+ font = para->postscript_alias->xfig_code;
+
+ switch (para->just) {
+ case 'l':
+ sub_type = 0;
+ break;
+ case 'r':
+ sub_type = 2;
+ break;
+ default:
+ case 'n':
+ sub_type = 1;
+ break;
+ }
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n",
+ object_code, sub_type, color, depth, pen_style, font,
+ font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y),
+ mp_string(para->str));
+}
+
+static void mp_ellipse(GVJ_t * job, pointf * A, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 1; /* always 1 for ellipse */
+ int sub_type = 1; /* ellipse defined by radii */
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = obj->fillcolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill = filled ? 20 : -1;
+ double style_val;
+ int direction = 0;
+ double angle = 0.0;
+ int center_x, center_y, radius_x, radius_y;
+ int start_x, start_y, end_x, end_y;
+
+ mp_line_style(obj, &line_style, &style_val);
+
+ start_x = center_x = ROUND(A[0].x);
+ start_y = center_y = ROUND(A[0].y);
+ radius_x = ROUND(A[1].x - A[0].x);
+ radius_y = ROUND(A[1].y - A[0].y);
+ end_x = ROUND(A[1].x);
+ end_y = ROUND(A[1].y);
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n",
+ object_code, sub_type, line_style, thickness, pen_color,
+ fill_color, depth, pen_style, area_fill, style_val, direction,
+ angle, center_x, center_y, radius_x, radius_y, start_x,
+ start_y, end_x, end_y);
+}
+
+static void mp_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
+ int arrow_at_end, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 3; /* always 3 for spline */
+ int sub_type;
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = obj->fillcolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill;
+ double style_val;
+ int cap_style = 0;
+ int forward_arrow = 0;
+ int backward_arrow = 0;
+ int npoints = n;
+ int i;
+
+ pointf pf, V[4];
+ point p;
+ int j, step;
+ int count = 0;
+ int size;
+
+ char *buffer;
+ char *buf;
+ buffer =
+ malloc((npoints + 1) * (BEZIERSUBDIVISION +
+ 1) * 20 * sizeof(char));
+ buf = buffer;
+
+ mp_line_style(obj, &line_style, &style_val);
+
+ if (filled) {
+ sub_type = 5; /* closed X-spline */
+ area_fill = 20; /* fully saturated color */
+ fill_color = job->obj->fillcolor.u.index;
+ }
+ else {
+ sub_type = 4; /* opened X-spline */
+ area_fill = -1;
+ fill_color = 0;
+ }
+ V[3].x = A[0].x;
+ V[3].y = A[0].y;
+ /* Write first point in line */
+ count++;
+ PF2P(A[0], p);
+ size = sprintf(buf, " %d %d", p.x, p.y);
+ buf += size;
+ /* write subsequent points */
+ for (i = 0; i + 3 < n; i += 3) {
+ V[0] = V[3];
+ for (j = 1; j <= 3; j++) {
+ V[j].x = A[i + j].x;
+ V[j].y = A[i + j].y;
+ }
+ for (step = 1; step <= BEZIERSUBDIVISION; step++) {
+ count++;
+ pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
+ PF2P(pf, p);
+ size = sprintf(buf, " %d %d", p.x, p.y);
+ buf += size;
+ }
+ }
+
+ gvdevice_printf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
+ object_code,
+ sub_type,
+ line_style,
+ thickness,
+ pen_color,
+ fill_color,
+ depth,
+ pen_style,
+ area_fill,
+ style_val, cap_style, forward_arrow, backward_arrow, count);
+
+ gvdevice_printf(job, " %s\n", buffer); /* print points */
+ free(buffer);
+ for (i = 0; i < count; i++) {
+ gvdevice_printf(job, " %d", i % (count - 1) ? 1 : 0); /* -1 on all */
+ }
+ gvdevice_fputs(job, "\n");
+}
+
+static void mp_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 2; /* always 2 for polyline */
+ int sub_type = 3; /* always 3 for polygon */
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = obj->fillcolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill = filled ? 20 : -1;
+ double style_val;
+ int join_style = 0;
+ int cap_style = 0;
+ int radius = 0;
+ int forward_arrow = 0;
+ int backward_arrow = 0;
+ int npoints = n + 1;
+
+ mp_line_style(obj, &line_style, &style_val);
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+ object_code, sub_type, line_style, thickness, pen_color,
+ fill_color, depth, pen_style, area_fill, style_val, join_style,
+ cap_style, radius, forward_arrow, backward_arrow, npoints);
+ mpptarray(job, A, n, 1); /* closed shape */
+}
+
+static void mp_polyline(GVJ_t * job, pointf * A, int n)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 2; /* always 2 for polyline */
+ int sub_type = 1; /* always 1 for polyline */
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = 0;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill = 0;
+ double style_val;
+ int join_style = 0;
+ int cap_style = 0;
+ int radius = 0;
+ int forward_arrow = 0;
+ int backward_arrow = 0;
+ int npoints = n;
+
+ mp_line_style(obj, &line_style, &style_val);
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+ object_code, sub_type, line_style, thickness, pen_color,
+ fill_color, depth, pen_style, area_fill, style_val, join_style,
+ cap_style, radius, forward_arrow, backward_arrow, npoints);
+ mpptarray(job, A, n, 0); /* open shape */
+}
+
+gvrender_engine_t mp_engine = {
+ 0, /* mp_begin_job */
+ 0, /* mp_end_job */
+ mp_begin_graph,
+ mp_end_graph,
+ 0, /* mp_begin_layer */
+ 0, /* mp_end_layer */
+ mp_begin_page,
+ 0, /* mp_end_page */
+ 0, /* mp_begin_cluster */
+ 0, /* mp_end_cluster */
+ 0, /* mp_begin_nodes */
+ 0, /* mp_end_nodes */
+ 0, /* mp_begin_edges */
+ 0, /* mp_end_edges */
+ mp_begin_node,
+ mp_end_node,
+ mp_begin_edge,
+ mp_end_edge,
+ 0, /* mp_begin_anchor */
+ 0, /* mp_end_anchor */
+ mp_textpara,
+ mp_resolve_color,
+ mp_ellipse,
+ mp_polygon,
+ mp_bezier,
+ mp_polyline,
+ mp_comment,
+ 0, /* mp_library_shape */
+};
+
+
+/* NB. List must be LANG_C sorted */
+static char *mp_knowncolors[] = {
+ "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow",
+};
+
+
+gvrender_features_t mp_features = {
+ EMIT_COLORS
+ | GVRENDER_Y_GOES_DOWN, /* flags */
+ DEFAULT_EMBED_MARGIN, /* default margin - points */
+ 4., /* default pad - graph units */
+ {0.,0.}, /* default page width, height - points */
+ {1440.,1440.}, /* default dpi */
+ /* FIXME - this default dpi is a very strange number!!!
+ * It was picked to make .png usershapes the right size on my screen.
+ * It happens to be 1.2 * 1200, but I can't explain the 1.2.
+ * (I was expecting 1.3333 which is 96/72, but thats too big.)
+ * Also 1200 is hardcoded in mp_begin_graph() instead of using job->dpi
+ */
+
+ /* It may be TWIPS, i.e. 20 * POINT_PER_INCH
+ * but that doesn't explain what the 1200 is? */
+
+ mp_knowncolors, /* knowncolors */
+ sizeof(mp_knowncolors) / sizeof(char *), /* sizeof knowncolors */
+ RGBA_BYTE, /* color_type */
+};
+
+gvplugin_installed_t gvrender_mp_types[] = {
+ {FORMAT_MP, "mp", -1, &mp_engine, &mp_features},
+ {0, NULL, 0, NULL, NULL}
+};
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <io.h>
+#include "compat.h"
+#endif
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+#include "graph.h"
+#include "agxbuf.h"
+#include "utils.h"
+#include "color.h"
+
+/* Number of points to split splines into */
+#define BEZIERSUBDIVISION 6
+
+typedef enum { FORMAT_PIC, } format_type;
+
+static int Depth;
+
+static void picptarray(GVJ_t *job, pointf * A, int n, int close)
+{
+ int i;
+ point p;
+
+ for (i = 0; i < n; i++) {
+ PF2P(A[i],p);
+ gvdevice_printf(job, " %d %d", p.x, p.y);
+ }
+ if (close) {
+ PF2P(A[0],p);
+ gvdevice_printf(job, " %d %d", p.x, p.y);
+ }
+ gvdevice_fputs(job, "\n");
+}
+
+static char *pic_string(char *s)
+{
+ static char *buf = NULL;
+ static int bufsize = 0;
+ int pos = 0;
+ char *p;
+ unsigned char c;
+
+ if (!buf) {
+ bufsize = 64;
+ buf = malloc(bufsize * sizeof(char));
+ }
+
+ p = buf;
+ while ((c = *s++)) {
+ if (pos > (bufsize - 8)) {
+ bufsize *= 2;
+ buf = realloc(buf, bufsize * sizeof(char));
+ p = buf + pos;
+ }
+ if (isascii(c)) {
+ if (c == '\\') {
+ *p++ = '\\';
+ pos++;
+ }
+ *p++ = c;
+ pos++;
+ } else {
+ *p++ = '\\';
+ sprintf(p, "%03o", c);
+ p += 3;
+ pos += 4;
+ }
+ }
+ *p = '\0';
+ return buf;
+}
+
+static int picColorResolve(int *new, int r, int g, int b)
+{
+#define maxColors 256
+ static int top = 0;
+ static short red[maxColors], green[maxColors], blue[maxColors];
+ int c;
+ int ct = -1;
+ long rd, gd, bd, dist;
+ long mindist = 3 * 255 * 255; /* init to max poss dist */
+
+ *new = 0; /* in case it is not a new color */
+ for (c = 0; c < top; c++) {
+ rd = (long) (red[c] - r);
+ gd = (long) (green[c] - g);
+ bd = (long) (blue[c] - b);
+ dist = rd * rd + gd * gd + bd * bd;
+ if (dist < mindist) {
+ if (dist == 0)
+ return c; /* Return exact match color */
+ mindist = dist;
+ ct = c;
+ }
+ }
+ /* no exact match. We now know closest, but first try to allocate exact */
+ if (top++ == maxColors)
+ return ct; /* Return closest available color */
+ red[c] = r;
+ green[c] = g;
+ blue[c] = b;
+ *new = 1; /* flag new color */
+ return c; /* Return newly allocated color */
+}
+
+/* this table is in xfig color index order */
+static char *piccolor[] = {
+ "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL
+};
+
+static void pic_resolve_color(GVJ_t *job, gvcolor_t * color)
+{
+ int object_code = 0; /* always 0 for color */
+ int i, new;
+
+ switch (color->type) {
+ case COLOR_STRING:
+ for (i = 0; piccolor[i]; i++) {
+ if (streq(piccolor[i], color->u.string)) {
+ color->u.index = i;
+ break;
+ }
+ }
+ break;
+ case RGBA_BYTE:
+ i = 32 + picColorResolve(&new,
+ color->u.rgba[0],
+ color->u.rgba[1],
+ color->u.rgba[2]);
+ if (new)
+ gvdevice_printf(job, "%d %d #%02x%02x%02x\n",
+ object_code, i,
+ color->u.rgba[0],
+ color->u.rgba[1],
+ color->u.rgba[2]);
+ color->u.index = i;
+ break;
+ default:
+ assert(0); /* internal error */
+ }
+
+ color->type = COLOR_INDEX;
+}
+
+static void pic_line_style(obj_state_t *obj, int *line_style, double *style_val)
+{
+ switch (obj->pen) {
+ case PEN_DASHED:
+ *line_style = 1;
+ *style_val = 10.;
+ break;
+ case PEN_DOTTED:
+ *line_style = 2;
+ *style_val = 10.;
+ break;
+ case PEN_SOLID:
+ default:
+ *line_style = 0;
+ *style_val = 0.;
+ break;
+ }
+}
+
+static void pic_comment(GVJ_t *job, char *str)
+{
+ gvdevice_printf(job, "# %s\n", str);
+}
+
+static void pic_begin_graph(GVJ_t * job)
+{
+ obj_state_t *obj = job->obj;
+
+ gvdevice_fputs(job, "#FIG 3.2\n");
+ gvdevice_printf(job, "# Generated by %s version %s (%s)\n",
+ job->common->info[0], job->common->info[1], job->common->info[2]);
+ gvdevice_printf(job, "# For: %s\n", job->common->user);
+ gvdevice_printf(job, "# Title: %s\n", obj->u.g->name);
+ gvdevice_printf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
+ gvdevice_fputs(job, "Portrait\n"); /* orientation */
+ gvdevice_fputs(job, "Center\n"); /* justification */
+ gvdevice_fputs(job, "Inches\n"); /* units */
+ gvdevice_fputs(job, "Letter\n"); /* papersize */
+ gvdevice_fputs(job, "100.00\n"); /* magnification % */
+ gvdevice_fputs(job, "Single\n"); /* multiple-page */
+ gvdevice_fputs(job, "-2\n"); /* transparent color (none) */
+ gvdevice_fputs(job, "1200"); /* resolution */
+ gvdevice_fputs(job, " 2\n"); /* coordinate system (upper left) */
+}
+
+static void pic_end_graph(GVJ_t * job)
+{
+ gvdevice_fputs(job, "# end of FIG file\n");
+}
+
+static void pic_begin_page(GVJ_t * job)
+{
+ Depth = 2;
+}
+
+static void pic_begin_node(GVJ_t * job)
+{
+ Depth = 1;
+}
+
+static void pic_end_node(GVJ_t * job)
+{
+ Depth = 2;
+}
+
+static void pic_begin_edge(GVJ_t * job)
+{
+ Depth = 0;
+}
+
+static void pic_end_edge(GVJ_t * job)
+{
+ Depth = 2;
+}
+
+static void pic_textpara(GVJ_t * job, pointf p, textpara_t * para)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 4; /* always 4 for text */
+ int sub_type = 0; /* text justification */
+ int color = obj->pencolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int font = -1; /* init to xfig's default font */
+ double font_size = para->fontsize * job->zoom;
+ double angle = job->rotation ? (PI / 2.0) : 0.0;
+ int font_flags = 4; /* PostScript font */
+ double height = 0.0;
+ double length = 0.0;
+
+ if (para->postscript_alias) /* if it is a standard postscript font */
+ font = para->postscript_alias->xfig_code;
+
+ switch (para->just) {
+ case 'l':
+ sub_type = 0;
+ break;
+ case 'r':
+ sub_type = 2;
+ break;
+ default:
+ case 'n':
+ sub_type = 1;
+ break;
+ }
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n",
+ object_code, sub_type, color, depth, pen_style, font,
+ font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y),
+ pic_string(para->str));
+}
+
+static void pic_ellipse(GVJ_t * job, pointf * A, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 1; /* always 1 for ellipse */
+ int sub_type = 1; /* ellipse defined by radii */
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = obj->fillcolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill = filled ? 20 : -1;
+ double style_val;
+ int direction = 0;
+ double angle = 0.0;
+ int center_x, center_y, radius_x, radius_y;
+ int start_x, start_y, end_x, end_y;
+
+ pic_line_style(obj, &line_style, &style_val);
+
+ start_x = center_x = ROUND(A[0].x);
+ start_y = center_y = ROUND(A[0].y);
+ radius_x = ROUND(A[1].x - A[0].x);
+ radius_y = ROUND(A[1].y - A[0].y);
+ end_x = ROUND(A[1].x);
+ end_y = ROUND(A[1].y);
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n",
+ object_code, sub_type, line_style, thickness, pen_color,
+ fill_color, depth, pen_style, area_fill, style_val, direction,
+ angle, center_x, center_y, radius_x, radius_y, start_x,
+ start_y, end_x, end_y);
+}
+
+static void pic_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
+ int arrow_at_end, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 3; /* always 3 for spline */
+ int sub_type;
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = obj->fillcolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill;
+ double style_val;
+ int cap_style = 0;
+ int forward_arrow = 0;
+ int backward_arrow = 0;
+ int npoints = n;
+ int i;
+
+ pointf pf, V[4];
+ point p;
+ int j, step;
+ int count = 0;
+ int size;
+
+ char *buffer;
+ char *buf;
+ buffer =
+ malloc((npoints + 1) * (BEZIERSUBDIVISION +
+ 1) * 20 * sizeof(char));
+ buf = buffer;
+
+ pic_line_style(obj, &line_style, &style_val);
+
+ if (filled) {
+ sub_type = 5; /* closed X-spline */
+ area_fill = 20; /* fully saturated color */
+ fill_color = job->obj->fillcolor.u.index;
+ }
+ else {
+ sub_type = 4; /* opened X-spline */
+ area_fill = -1;
+ fill_color = 0;
+ }
+ V[3].x = A[0].x;
+ V[3].y = A[0].y;
+ /* Write first point in line */
+ count++;
+ PF2P(A[0], p);
+ size = sprintf(buf, " %d %d", p.x, p.y);
+ buf += size;
+ /* write subsequent points */
+ for (i = 0; i + 3 < n; i += 3) {
+ V[0] = V[3];
+ for (j = 1; j <= 3; j++) {
+ V[j].x = A[i + j].x;
+ V[j].y = A[i + j].y;
+ }
+ for (step = 1; step <= BEZIERSUBDIVISION; step++) {
+ count++;
+ pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
+ PF2P(pf, p);
+ size = sprintf(buf, " %d %d", p.x, p.y);
+ buf += size;
+ }
+ }
+
+ gvdevice_printf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
+ object_code,
+ sub_type,
+ line_style,
+ thickness,
+ pen_color,
+ fill_color,
+ depth,
+ pen_style,
+ area_fill,
+ style_val, cap_style, forward_arrow, backward_arrow, count);
+
+ gvdevice_printf(job, " %s\n", buffer); /* print points */
+ free(buffer);
+ for (i = 0; i < count; i++) {
+ gvdevice_printf(job, " %d", i % (count - 1) ? 1 : 0); /* -1 on all */
+ }
+ gvdevice_fputs(job, "\n");
+}
+
+static void pic_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 2; /* always 2 for polyline */
+ int sub_type = 3; /* always 3 for polygon */
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = obj->fillcolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill = filled ? 20 : -1;
+ double style_val;
+ int join_style = 0;
+ int cap_style = 0;
+ int radius = 0;
+ int forward_arrow = 0;
+ int backward_arrow = 0;
+ int npoints = n + 1;
+
+ pic_line_style(obj, &line_style, &style_val);
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+ object_code, sub_type, line_style, thickness, pen_color,
+ fill_color, depth, pen_style, area_fill, style_val, join_style,
+ cap_style, radius, forward_arrow, backward_arrow, npoints);
+ picptarray(job, A, n, 1); /* closed shape */
+}
+
+static void pic_polyline(GVJ_t * job, pointf * A, int n)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 2; /* always 2 for polyline */
+ int sub_type = 1; /* always 1 for polyline */
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = 0;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill = 0;
+ double style_val;
+ int join_style = 0;
+ int cap_style = 0;
+ int radius = 0;
+ int forward_arrow = 0;
+ int backward_arrow = 0;
+ int npoints = n;
+
+ pic_line_style(obj, &line_style, &style_val);
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+ object_code, sub_type, line_style, thickness, pen_color,
+ fill_color, depth, pen_style, area_fill, style_val, join_style,
+ cap_style, radius, forward_arrow, backward_arrow, npoints);
+ picptarray(job, A, n, 0); /* open shape */
+}
+
+gvrender_engine_t pic_engine = {
+ 0, /* pic_begin_job */
+ 0, /* pic_end_job */
+ pic_begin_graph,
+ pic_end_graph,
+ 0, /* pic_begin_layer */
+ 0, /* pic_end_layer */
+ pic_begin_page,
+ 0, /* pic_end_page */
+ 0, /* pic_begin_cluster */
+ 0, /* pic_end_cluster */
+ 0, /* pic_begin_nodes */
+ 0, /* pic_end_nodes */
+ 0, /* pic_begin_edges */
+ 0, /* pic_end_edges */
+ pic_begin_node,
+ pic_end_node,
+ pic_begin_edge,
+ pic_end_edge,
+ 0, /* pic_begin_anchor */
+ 0, /* pic_end_anchor */
+ pic_textpara,
+ pic_resolve_color,
+ pic_ellipse,
+ pic_polygon,
+ pic_bezier,
+ pic_polyline,
+ pic_comment,
+ 0, /* pic_library_shape */
+};
+
+
+/* NB. List must be LANG_C sorted */
+static char *pic_knowncolors[] = {
+ "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow",
+};
+
+
+gvrender_features_t pic_features = {
+ EMIT_COLORS
+ | GVRENDER_Y_GOES_DOWN, /* flags */
+ DEFAULT_EMBED_MARGIN, /* default margin - points */
+ 4., /* default pad - graph units */
+ {0.,0.}, /* default page width, height - points */
+ {1440.,1440.}, /* default dpi */
+ /* FIXME - this default dpi is a very strange number!!!
+ * It was picked to make .png usershapes the right size on my screen.
+ * It happens to be 1.2 * 1200, but I can't explain the 1.2.
+ * (I was expecting 1.3333 which is 96/72, but thats too big.)
+ * Also 1200 is hardcoded in pic_begin_graph() instead of using job->dpi
+ */
+
+ /* It may be TWIPS, i.e. 20 * POINT_PER_INCH
+ * but that doesn't explain what the 1200 is? */
+
+ pic_knowncolors, /* knowncolors */
+ sizeof(pic_knowncolors) / sizeof(char *), /* sizeof knowncolors */
+ RGBA_BYTE, /* color_type */
+};
+
+gvplugin_installed_t gvrender_pic_types[] = {
+ {FORMAT_PIC, "pic", -1, &pic_engine, &pic_features},
+ {0, NULL, 0, NULL, NULL}
+};
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+#include "gvcint.h"
+#include "graph.h"
+#include "types.h" /* need the SVG font name schemes */
+
+/* highlight flag */
+#define HIGHLIGHT 1
+#define NOHIGHLIGHT 0
+
+typedef enum { FORMAT_TK, } format_type;
+
+static char *tkgen_string(char *s)
+{
+ return s;
+}
+
+static void tkgen_print_color(GVJ_t * job, gvcolor_t color)
+{
+ switch (color.type) {
+ case COLOR_STRING:
+ gvdevice_fputs(job, color.u.string);
+ break;
+ case RGBA_BYTE:
+ if (color.u.rgba[3] == 0) /* transparent */
+ gvdevice_fputs(job, "none");
+ else
+ gvdevice_printf(job, "#%02x%02x%02x",
+ color.u.rgba[0], color.u.rgba[1], color.u.rgba[2]);
+ break;
+ default:
+ assert(0); /* internal error */
+ }
+}
+
+static void tkgen_print_tags(GVJ_t *job, int tag)
+{
+ char *ObjType;
+ unsigned int ObjHandle;
+ obj_state_t *obj = job->obj;
+
+ switch (obj->emit_state) {
+ case EMIT_NDRAW:
+ case EMIT_NLABEL:
+ ObjType = "node";
+ ObjHandle = obj->u.n->handle;
+ break;
+ case EMIT_EDRAW:
+ case EMIT_TDRAW:
+ case EMIT_HDRAW:
+ case EMIT_ELABEL:
+ case EMIT_TLABEL:
+ case EMIT_HLABEL:
+ ObjType = "edge";
+ ObjHandle = obj->u.e->handle;
+ break;
+ case EMIT_GDRAW:
+ case EMIT_CDRAW:
+ case EMIT_GLABEL:
+ case EMIT_CLABEL:
+ ObjType = "graph";
+ ObjHandle = obj->u.g->handle;
+ break;
+ default:
+ assert (0);
+ break;
+ }
+ gvdevice_printf(job, " -tags %d%s%ld", tag, ObjType, ObjHandle);
+}
+
+
+static void tkgen_grstyle(GVJ_t * job, int filled)
+{
+#if 0
+ obj_state_t *obj = job->obj;
+
+ gvdevice_fputs(job, " style=\"fill:");
+ if (filled)
+ tkgen_print_color(job, obj->fillcolor);
+ else
+ gvdevice_fputs(job, "none");
+ gvdevice_fputs(job, ";stroke:");
+ tkgen_print_color(job, obj->pencolor);
+ if (obj->penwidth != PENWIDTH_NORMAL)
+ gvdevice_printf(job, ";stroke-width:%g", obj->penwidth);
+ if (obj->pen == PEN_DASHED) {
+ gvdevice_printf(job, ";stroke-dasharray:%s", sdarray);
+ } else if (obj->pen == PEN_DOTTED) {
+ gvdevice_printf(job, ";stroke-dasharray:%s", sdotarray);
+ }
+ gvdevice_fputs(job, ";\"");
+#endif
+}
+
+static void tkgen_comment(GVJ_t * job, char *str)
+{
+ gvdevice_fputs(job, "# ");
+ gvdevice_fputs(job, tkgen_string(str));
+ gvdevice_fputs(job, "\n");
+}
+
+static void tkgen_begin_job(GVJ_t * job)
+{
+ gvdevice_fputs(job, "# Generated by ");
+ gvdevice_fputs(job, tkgen_string(job->common->info[0]));
+ gvdevice_fputs(job, " version ");
+ gvdevice_fputs(job, tkgen_string(job->common->info[1]));
+ gvdevice_fputs(job, " (");
+ gvdevice_fputs(job, tkgen_string(job->common->info[2]));
+ gvdevice_fputs(job, ")\n# For user: ");
+ gvdevice_fputs(job, tkgen_string(job->common->user));
+ gvdevice_fputs(job, "\n");
+}
+
+static void tkgen_begin_graph(GVJ_t * job)
+{
+ obj_state_t *obj = job->obj;
+
+ gvdevice_fputs(job, "#");
+ if (obj->u.g->name[0]) {
+ gvdevice_fputs(job, " Title: ");
+ gvdevice_fputs(job, tkgen_string(obj->u.g->name));
+ }
+ gvdevice_printf(job, " Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
+}
+
+static void tkgen_textpara(GVJ_t * job, pointf p, textpara_t * para)
+{
+ obj_state_t *obj = job->obj;
+
+ gvdevice_fputs(job, "$c create text");
+ gvdevice_printf(job, " %d %d", ROUND(p.x), ROUND(p.y));
+ gvdevice_fputs(job, " -text {");
+ gvdevice_fputs(job, para->str);
+ gvdevice_fputs(job, "}");
+ gvdevice_fputs(job, " -fill ");
+ tkgen_print_color(job, obj->pencolor);
+ gvdevice_fputs(job, " -font {");
+ gvdevice_fputs(job, para->fontname);
+ gvdevice_printf(job, " %g}", para->fontsize);
+ switch (para->just) {
+ case 'l':
+ gvdevice_fputs(job, " -anchor w");
+ break;
+ case 'r':
+ gvdevice_fputs(job, " -anchor e");
+ break;
+ default:
+ case 'n':
+ break;
+ }
+ gvdevice_fputs(job, " -state disabled");
+ tkgen_print_tags(job, NOHIGHLIGHT);
+ gvdevice_fputs(job, "\n");
+}
+
+static void tkgen_ellipse(GVJ_t * job, pointf * A, int filled)
+{
+#if 0
+ /* A[] contains 2 points: the center and corner. */
+ gvdevice_fputs(job, "<ellipse");
+ tkgen_grstyle(job, filled);
+ gvdevice_printf(job, " cx=\"%g\" cy=\"%g\"", A[0].x, -A[0].y);
+ gvdevice_printf(job, " rx=\"%g\" ry=\"%g\"",
+ A[1].x - A[0].x, A[1].y - A[0].y);
+ gvdevice_fputs(job, "/>\n");
+#endif
+}
+
+static void
+tkgen_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
+ int arrow_at_end, int filled)
+{
+#if 0
+ gvdevice_fputs(job, "<path");
+ tkgen_grstyle(job, filled);
+ gvdevice_fputs(job, " d=\"");
+ tkgen_bzptarray(job, A, n);
+ gvdevice_fputs(job, "\"/>\n");
+#endif
+}
+
+static void tkgen_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+ int i;
+
+ gvdevice_fputs(job, "$c create polygon");
+ for (i = 0; i < n; i++)
+ gvdevice_printf(job, " %d %d", ROUND(A[i].x), ROUND(-A[i].y));
+ gvdevice_fputs(job, " -state disabled");
+ tkgen_print_tags(job, NOHIGHLIGHT);
+ gvdevice_fputs(job, "\n");
+}
+
+static void tkgen_polyline(GVJ_t * job, pointf * A, int n)
+{
+#if 0
+ int i;
+
+ gvdevice_fputs(job, "<polyline");
+ tkgen_grstyle(job, 0);
+ gvdevice_fputs(job, " points=\"");
+ for (i = 0; i < n; i++)
+ gvdevice_printf(job, "%g,%g ", A[i].x, -A[i].y);
+ gvdevice_fputs(job, "\"/>\n");
+#endif
+}
+
+/* color names from http://www.w3.org/TR/SVG/types.html */
+/* NB. List must be LANG_C sorted */
+static char *tkgen_knowncolors[] = {
+ "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
+ "beige", "bisque", "black", "blanchedalmond", "blue",
+ "blueviolet", "brown", "burlywood",
+ "cadetblue", "chartreuse", "chocolate", "coral",
+ "cornflowerblue", "cornsilk", "crimson", "cyan",
+ "darkblue", "darkcyan", "darkgoldenrod", "darkgray",
+ "darkgreen", "darkgrey", "darkkhaki", "darkmagenta",
+ "darkolivegreen", "darkorange", "darkorchid", "darkred",
+ "darksalmon", "darkseagreen", "darkslateblue", "darkslategray",
+ "darkslategrey", "darkturquoise", "darkviolet", "deeppink",
+ "deepskyblue", "dimgray", "dimgrey", "dodgerblue",
+ "firebrick", "floralwhite", "forestgreen", "fuchsia",
+ "gainsboro", "ghostwhite", "gold", "goldenrod", "gray",
+ "green", "greenyellow", "grey",
+ "honeydew", "hotpink", "indianred",
+ "indigo", "ivory", "khaki",
+ "lavender", "lavenderblush", "lawngreen", "lemonchiffon",
+ "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow",
+ "lightgray", "lightgreen", "lightgrey", "lightpink",
+ "lightsalmon", "lightseagreen", "lightskyblue",
+ "lightslategray", "lightslategrey", "lightsteelblue",
+ "lightyellow", "lime", "limegreen", "linen",
+ "magenta", "maroon", "mediumaquamarine", "mediumblue",
+ "mediumorchid", "mediumpurple", "mediumseagreen",
+ "mediumslateblue", "mediumspringgreen", "mediumturquoise",
+ "mediumvioletred", "midnightblue", "mintcream",
+ "mistyrose", "moccasin",
+ "navajowhite", "navy", "oldlace",
+ "olive", "olivedrab", "orange", "orangered", "orchid",
+ "palegoldenrod", "palegreen", "paleturquoise",
+ "palevioletred", "papayawhip", "peachpuff", "peru", "pink",
+ "plum", "powderblue", "purple",
+ "red", "rosybrown", "royalblue",
+ "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell",
+ "sienna", "silver", "skyblue", "slateblue", "slategray",
+ "slategrey", "snow", "springgreen", "steelblue",
+ "tan", "teal", "thistle", "tomato", "turquoise",
+ "violet",
+ "wheat", "white", "whitesmoke",
+ "yellow", "yellowgreen"
+};
+
+gvrender_engine_t tkgen_engine = {
+ tkgen_begin_job,
+ 0, /* tkgen_end_job */
+ tkgen_begin_graph,
+ 0, /* tkgen_end_graph */
+ 0, /* tkgen_begin_layer */
+ 0, /* tkgen_end_layer */
+ 0, /* tkgen_begin_page */
+ 0, /* tkgen_end_page */
+ 0, /* tkgen_begin_cluster */
+ 0, /* tkgen_end_cluster */
+ 0, /* tkgen_begin_nodes */
+ 0, /* tkgen_end_nodes */
+ 0, /* tkgen_begin_edges */
+ 0, /* tkgen_end_edges */
+ 0, /* tkgen_begin_node */
+ 0, /* tkgen_end_node */
+ 0, /* tkgen_begin_edge */
+ 0, /* tkgen_end_edge */
+ 0, /* tkgen_begin_anchor */
+ 0, /* tkgen_end_anchor */
+ tkgen_textpara,
+ 0, /* tkgen_resolve_color */
+ tkgen_ellipse,
+ tkgen_polygon,
+ tkgen_bezier,
+ tkgen_polyline,
+ tkgen_comment,
+ 0, /* tkgen_library_shape */
+};
+
+gvrender_features_t render_features_tk = {
+ GVRENDER_Y_GOES_DOWN, /* flags */
+ 4., /* default pad - graph units */
+ tkgen_knowncolors, /* knowncolors */
+ sizeof(tkgen_knowncolors) / sizeof(char *), /* sizeof knowncolors */
+ RGBA_BYTE, /* color_type */
+};
+
+gvdevice_features_t device_features_tk = {
+ 0, /* flags */
+ {0.,0.}, /* default margin - points */
+ {0.,0.}, /* default page width, height - points */
+ {72.,72.}, /* default dpi */
+};
+
+gvplugin_installed_t gvrender_tk_types[] = {
+ {FORMAT_TK, "tk", 1, &tkgen_engine, &render_features_tk},
+ {0, NULL, 0, NULL, NULL}
+};
+
+gvplugin_installed_t gvdevice_tk_types[] = {
+ {FORMAT_TK, "tk:tk", 1, NULL, &device_features_tk},
+ {0, NULL, 0, NULL, NULL}
+};
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+/* FIXME - incomplete replacement for codegen */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <io.h>
+#include "compat.h"
+#endif
+
+#include "macros.h"
+#include "const.h"
+
+#include "gvplugin_render.h"
+#include "graph.h"
+#include "agxbuf.h"
+#include "utils.h"
+#include "color.h"
+
+/* Number of points to split splines into */
+#define BEZIERSUBDIVISION 6
+
+typedef enum { FORMAT_VTX, } format_type;
+
+static int Depth;
+
+static void vtxptarray(GVJ_t *job, pointf * A, int n, int close)
+{
+ int i;
+ point p;
+
+ for (i = 0; i < n; i++) {
+ PF2P(A[i],p);
+ gvdevice_printf(job, " %d %d", p.x, p.y);
+ }
+ if (close) {
+ PF2P(A[0],p);
+ gvdevice_printf(job, " %d %d", p.x, p.y);
+ }
+ gvdevice_fputs(job, "\n");
+}
+
+static char *vtx_string(char *s)
+{
+ static char *buf = NULL;
+ static int bufsize = 0;
+ int pos = 0;
+ char *p;
+ unsigned char c;
+
+ if (!buf) {
+ bufsize = 64;
+ buf = malloc(bufsize * sizeof(char));
+ }
+
+ p = buf;
+ while ((c = *s++)) {
+ if (pos > (bufsize - 8)) {
+ bufsize *= 2;
+ buf = realloc(buf, bufsize * sizeof(char));
+ p = buf + pos;
+ }
+ if (isascii(c)) {
+ if (c == '\\') {
+ *p++ = '\\';
+ pos++;
+ }
+ *p++ = c;
+ pos++;
+ } else {
+ *p++ = '\\';
+ sprintf(p, "%03o", c);
+ p += 3;
+ pos += 4;
+ }
+ }
+ *p = '\0';
+ return buf;
+}
+
+static int vtxColorResolve(int *new, int r, int g, int b)
+{
+#define maxColors 256
+ static int top = 0;
+ static short red[maxColors], green[maxColors], blue[maxColors];
+ int c;
+ int ct = -1;
+ long rd, gd, bd, dist;
+ long mindist = 3 * 255 * 255; /* init to max poss dist */
+
+ *new = 0; /* in case it is not a new color */
+ for (c = 0; c < top; c++) {
+ rd = (long) (red[c] - r);
+ gd = (long) (green[c] - g);
+ bd = (long) (blue[c] - b);
+ dist = rd * rd + gd * gd + bd * bd;
+ if (dist < mindist) {
+ if (dist == 0)
+ return c; /* Return exact match color */
+ mindist = dist;
+ ct = c;
+ }
+ }
+ /* no exact match. We now know closest, but first try to allocate exact */
+ if (top++ == maxColors)
+ return ct; /* Return closest available color */
+ red[c] = r;
+ green[c] = g;
+ blue[c] = b;
+ *new = 1; /* flag new color */
+ return c; /* Return newly allocated color */
+}
+
+/* this table is in xfig color index order */
+static char *vtxcolor[] = {
+ "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL
+};
+
+static void vtx_resolve_color(GVJ_t *job, gvcolor_t * color)
+{
+ int object_code = 0; /* always 0 for color */
+ int i, new;
+
+ switch (color->type) {
+ case COLOR_STRING:
+ for (i = 0; vtxcolor[i]; i++) {
+ if (streq(vtxcolor[i], color->u.string)) {
+ color->u.index = i;
+ break;
+ }
+ }
+ break;
+ case RGBA_BYTE:
+ i = 32 + vtxColorResolve(&new,
+ color->u.rgba[0],
+ color->u.rgba[1],
+ color->u.rgba[2]);
+ if (new)
+ gvdevice_printf(job, "%d %d #%02x%02x%02x\n",
+ object_code, i,
+ color->u.rgba[0],
+ color->u.rgba[1],
+ color->u.rgba[2]);
+ color->u.index = i;
+ break;
+ default:
+ assert(0); /* internal error */
+ }
+
+ color->type = COLOR_INDEX;
+}
+
+static void vtx_line_style(obj_state_t *obj, int *line_style, double *style_val)
+{
+ switch (obj->pen) {
+ case PEN_DASHED:
+ *line_style = 1;
+ *style_val = 10.;
+ break;
+ case PEN_DOTTED:
+ *line_style = 2;
+ *style_val = 10.;
+ break;
+ case PEN_SOLID:
+ default:
+ *line_style = 0;
+ *style_val = 0.;
+ break;
+ }
+}
+
+static void vtx_comment(GVJ_t *job, char *str)
+{
+ gvdevice_printf(job, "# %s\n", str);
+}
+
+static void vtx_begin_graph(GVJ_t * job)
+{
+ obj_state_t *obj = job->obj;
+
+ gvdevice_fputs(job, "#FIG 3.2\n");
+ gvdevice_printf(job, "# Generated by %s version %s (%s)\n",
+ job->common->info[0], job->common->info[1], job->common->info[2]);
+ gvdevice_printf(job, "# For: %s\n", job->common->user);
+ gvdevice_printf(job, "# Title: %s\n", obj->u.g->name);
+ gvdevice_printf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
+ gvdevice_fputs(job, "Portrait\n"); /* orientation */
+ gvdevice_fputs(job, "Center\n"); /* justification */
+ gvdevice_fputs(job, "Inches\n"); /* units */
+ gvdevice_fputs(job, "Letter\n"); /* papersize */
+ gvdevice_fputs(job, "100.00\n"); /* magnification % */
+ gvdevice_fputs(job, "Single\n"); /* multiple-page */
+ gvdevice_fputs(job, "-2\n"); /* transparent color (none) */
+ gvdevice_fputs(job, "1200"); /* resolution */
+ gvdevice_fputs(job, " 2\n"); /* coordinate system (upper left) */
+}
+
+static void vtx_end_graph(GVJ_t * job)
+{
+ gvdevice_fputs(job, "# end of FIG file\n");
+}
+
+static void vtx_begin_page(GVJ_t * job)
+{
+ Depth = 2;
+}
+
+static void vtx_begin_node(GVJ_t * job)
+{
+ Depth = 1;
+}
+
+static void vtx_end_node(GVJ_t * job)
+{
+ Depth = 2;
+}
+
+static void vtx_begin_edge(GVJ_t * job)
+{
+ Depth = 0;
+}
+
+static void vtx_end_edge(GVJ_t * job)
+{
+ Depth = 2;
+}
+
+static void vtx_textpara(GVJ_t * job, pointf p, textpara_t * para)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 4; /* always 4 for text */
+ int sub_type = 0; /* text justification */
+ int color = obj->pencolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int font = -1; /* init to xfig's default font */
+ double font_size = para->fontsize * job->zoom;
+ double angle = job->rotation ? (PI / 2.0) : 0.0;
+ int font_flags = 4; /* PostScript font */
+ double height = 0.0;
+ double length = 0.0;
+
+ if (para->postscript_alias) /* if it is a standard postscript font */
+ font = para->postscript_alias->xfig_code;
+
+ switch (para->just) {
+ case 'l':
+ sub_type = 0;
+ break;
+ case 'r':
+ sub_type = 2;
+ break;
+ default:
+ case 'n':
+ sub_type = 1;
+ break;
+ }
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n",
+ object_code, sub_type, color, depth, pen_style, font,
+ font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y),
+ vtx_string(para->str));
+}
+
+static void vtx_ellipse(GVJ_t * job, pointf * A, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 1; /* always 1 for ellipse */
+ int sub_type = 1; /* ellipse defined by radii */
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = obj->fillcolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill = filled ? 20 : -1;
+ double style_val;
+ int direction = 0;
+ double angle = 0.0;
+ int center_x, center_y, radius_x, radius_y;
+ int start_x, start_y, end_x, end_y;
+
+ vtx_line_style(obj, &line_style, &style_val);
+
+ start_x = center_x = ROUND(A[0].x);
+ start_y = center_y = ROUND(A[0].y);
+ radius_x = ROUND(A[1].x - A[0].x);
+ radius_y = ROUND(A[1].y - A[0].y);
+ end_x = ROUND(A[1].x);
+ end_y = ROUND(A[1].y);
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n",
+ object_code, sub_type, line_style, thickness, pen_color,
+ fill_color, depth, pen_style, area_fill, style_val, direction,
+ angle, center_x, center_y, radius_x, radius_y, start_x,
+ start_y, end_x, end_y);
+}
+
+static void vtx_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
+ int arrow_at_end, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 3; /* always 3 for spline */
+ int sub_type;
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = obj->fillcolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill;
+ double style_val;
+ int cap_style = 0;
+ int forward_arrow = 0;
+ int backward_arrow = 0;
+ int npoints = n;
+ int i;
+
+ pointf pf, V[4];
+ point p;
+ int j, step;
+ int count = 0;
+ int size;
+
+ char *buffer;
+ char *buf;
+ buffer =
+ malloc((npoints + 1) * (BEZIERSUBDIVISION +
+ 1) * 20 * sizeof(char));
+ buf = buffer;
+
+ vtx_line_style(obj, &line_style, &style_val);
+
+ if (filled) {
+ sub_type = 5; /* closed X-spline */
+ area_fill = 20; /* fully saturated color */
+ fill_color = job->obj->fillcolor.u.index;
+ }
+ else {
+ sub_type = 4; /* opened X-spline */
+ area_fill = -1;
+ fill_color = 0;
+ }
+ V[3].x = A[0].x;
+ V[3].y = A[0].y;
+ /* Write first point in line */
+ count++;
+ PF2P(A[0], p);
+ size = sprintf(buf, " %d %d", p.x, p.y);
+ buf += size;
+ /* write subsequent points */
+ for (i = 0; i + 3 < n; i += 3) {
+ V[0] = V[3];
+ for (j = 1; j <= 3; j++) {
+ V[j].x = A[i + j].x;
+ V[j].y = A[i + j].y;
+ }
+ for (step = 1; step <= BEZIERSUBDIVISION; step++) {
+ count++;
+ pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
+ PF2P(pf, p);
+ size = sprintf(buf, " %d %d", p.x, p.y);
+ buf += size;
+ }
+ }
+
+ gvdevice_printf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
+ object_code,
+ sub_type,
+ line_style,
+ thickness,
+ pen_color,
+ fill_color,
+ depth,
+ pen_style,
+ area_fill,
+ style_val, cap_style, forward_arrow, backward_arrow, count);
+
+ gvdevice_printf(job, " %s\n", buffer); /* print points */
+ free(buffer);
+ for (i = 0; i < count; i++) {
+ gvdevice_printf(job, " %d", i % (count - 1) ? 1 : 0); /* -1 on all */
+ }
+ gvdevice_fputs(job, "\n");
+}
+
+static void vtx_polygon(GVJ_t * job, pointf * A, int n, int filled)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 2; /* always 2 for polyline */
+ int sub_type = 3; /* always 3 for polygon */
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = obj->fillcolor.u.index;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill = filled ? 20 : -1;
+ double style_val;
+ int join_style = 0;
+ int cap_style = 0;
+ int radius = 0;
+ int forward_arrow = 0;
+ int backward_arrow = 0;
+ int npoints = n + 1;
+
+ vtx_line_style(obj, &line_style, &style_val);
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+ object_code, sub_type, line_style, thickness, pen_color,
+ fill_color, depth, pen_style, area_fill, style_val, join_style,
+ cap_style, radius, forward_arrow, backward_arrow, npoints);
+ vtxptarray(job, A, n, 1); /* closed shape */
+}
+
+static void vtx_polyline(GVJ_t * job, pointf * A, int n)
+{
+ obj_state_t *obj = job->obj;
+
+ int object_code = 2; /* always 2 for polyline */
+ int sub_type = 1; /* always 1 for polyline */
+ int line_style; /* solid, dotted, dashed */
+ int thickness = obj->penwidth;
+ int pen_color = obj->pencolor.u.index;
+ int fill_color = 0;
+ int depth = Depth;
+ int pen_style = 0; /* not used */
+ int area_fill = 0;
+ double style_val;
+ int join_style = 0;
+ int cap_style = 0;
+ int radius = 0;
+ int forward_arrow = 0;
+ int backward_arrow = 0;
+ int npoints = n;
+
+ vtx_line_style(obj, &line_style, &style_val);
+
+ gvdevice_printf(job,
+ "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
+ object_code, sub_type, line_style, thickness, pen_color,
+ fill_color, depth, pen_style, area_fill, style_val, join_style,
+ cap_style, radius, forward_arrow, backward_arrow, npoints);
+ vtxptarray(job, A, n, 0); /* open shape */
+}
+
+gvrender_engine_t vtx_engine = {
+ 0, /* vtx_begin_job */
+ 0, /* vtx_end_job */
+ vtx_begin_graph,
+ vtx_end_graph,
+ 0, /* vtx_begin_layer */
+ 0, /* vtx_end_layer */
+ vtx_begin_page,
+ 0, /* vtx_end_page */
+ 0, /* vtx_begin_cluster */
+ 0, /* vtx_end_cluster */
+ 0, /* vtx_begin_nodes */
+ 0, /* vtx_end_nodes */
+ 0, /* vtx_begin_edges */
+ 0, /* vtx_end_edges */
+ vtx_begin_node,
+ vtx_end_node,
+ vtx_begin_edge,
+ vtx_end_edge,
+ 0, /* vtx_begin_anchor */
+ 0, /* vtx_end_anchor */
+ vtx_textpara,
+ vtx_resolve_color,
+ vtx_ellipse,
+ vtx_polygon,
+ vtx_bezier,
+ vtx_polyline,
+ vtx_comment,
+ 0, /* vtx_library_shape */
+};
+
+
+/* NB. List must be LANG_C sorted */
+static char *vtx_knowncolors[] = {
+ "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow",
+};
+
+
+gvrender_features_t vtx_features = {
+ EMIT_COLORS
+ | GVRENDER_Y_GOES_DOWN, /* flags */
+ DEFAULT_EMBED_MARGIN, /* default margin - points */
+ 4., /* default pad - graph units */
+ {0.,0.}, /* default page width, height - points */
+ {1440.,1440.}, /* default dpi */
+ /* FIXME - this default dpi is a very strange number!!!
+ * It was picked to make .png usershapes the right size on my screen.
+ * It happens to be 1.2 * 1200, but I can't explain the 1.2.
+ * (I was expecting 1.3333 which is 96/72, but thats too big.)
+ * Also 1200 is hardcoded in vtx_begin_graph() instead of using job->dpi
+ */
+
+ /* It may be TWIPS, i.e. 20 * POINT_PER_INCH
+ * but that doesn't explain what the 1200 is? */
+
+ vtx_knowncolors, /* knowncolors */
+ sizeof(vtx_knowncolors) / sizeof(char *), /* sizeof knowncolors */
+ RGBA_BYTE, /* color_type */
+};
+
+gvplugin_installed_t gvrender_vtx_types[] = {
+ {FORMAT_VTX, "vtx", -1, &vtx_engine, &vtx_features},
+ {0, NULL, 0, NULL, NULL}
+};