From 5efcc96e20a81c09664aae74138233932beba066 Mon Sep 17 00:00:00 2001 From: ellson Date: Tue, 27 Jun 2006 17:04:19 +0000 Subject: [PATCH] clean up --- lib/common/Makefile.am | 2 +- lib/common/gdgen.c | 969 --------------------------------- lib/common/mapgen.c | 1157 ---------------------------------------- lib/common/psgen.c | 707 ------------------------ lib/common/svggen.c | 944 -------------------------------- lib/common/vrmlgen.c | 1052 ------------------------------------ 6 files changed, 1 insertion(+), 4830 deletions(-) delete mode 100644 lib/common/gdgen.c delete mode 100644 lib/common/mapgen.c delete mode 100644 lib/common/psgen.c delete mode 100644 lib/common/svggen.c delete mode 100644 lib/common/vrmlgen.c diff --git a/lib/common/Makefile.am b/lib/common/Makefile.am index e2928810e..e27043d30 100644 --- a/lib/common/Makefile.am +++ b/lib/common/Makefile.am @@ -17,7 +17,7 @@ noinst_HEADERS = render.h utils.h memory.h \ noinst_LTLIBRARIES = libcommon_C.la if WITH_CODEGENS -CODEGENS = $(GD_CODEGENS) diagen.c figgen.c hpglgen.c mapgen.c mifgen.c mpgen.c \ +CODEGENS = $(GD_CODEGENS) diagen.c figgen.c hpglgen.c mifgen.c mpgen.c \ picgen.c vtxgen.c xdgen.c endif diff --git a/lib/common/gdgen.c b/lib/common/gdgen.c deleted file mode 100644 index e67cf3ed8..000000000 --- a/lib/common/gdgen.c +++ /dev/null @@ -1,969 +0,0 @@ -/* $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 * -**********************************************************/ - -#include "render.h" -#include "gd.h" - -#include -#ifdef MSWIN32 -#include -#endif - -static gdImagePtr im; -static int external_surface; - -#ifdef _UWIN -#ifndef DEFAULT_FONTPATH -#define DEFAULT_FONTPATH "/win/fonts" -#endif /* DEFAULT_FONTPATH */ -#else -#ifndef MSWIN32 -#ifndef DEFAULT_FONTPATH -#define DEFAULT_FONTPATH "/usr/share/ttf:/usr/local/share/ttf:/usr/share/fonts/ttf:/usr/local/share/fonts/ttf:/usr/lib/fonts:/usr/local/lib/fonts:/usr/lib/fonts/ttf:/usr/local/lib/fonts/ttf:/usr/common/graphviz/lib/fonts/ttf:/windows/fonts:/dos/windows/fonts:/usr/add-on/share/ttf:." -#endif /* DEFAULT_FONTPATH */ -#else -#ifndef DEFAULT_FONTPATH -#define DEFAULT_FONTPATH "%WINDIR%/FONTS;C:/WINDOWS/FONTS;C:/WINNT/Fonts;C:/winnt/fonts" -#endif /* DEFAULT_FONTPATH */ -#endif /* MSWIN32 */ -#endif /* _UWIN */ - -#define BEZIERSUBDIVISION 10 - -/* font modifiers */ -#define REGULAR 0 -#define BOLD 1 -#define ITALIC 2 - -/* patterns */ -#define P_SOLID 0 -#define P_DOTTED 4 -#define P_DASHED 11 -#define P_NONE 15 - -/* bold line constant */ -#define WIDTH_NORMAL 1 -#define WIDTH_BOLD 2 - -/* static int N_pages; */ -/* static point Pages; */ -static pointf Dpi; -static point Margin; -static pointf CompScale; -static int Rot; - -static point Viewport; -static pointf GraphFocus; -static double Zoom; - -typedef struct context_t { - int pencolor, fillcolor; - char *fontfam, fontopt, font_was_set, pen, fill, penwidth; - double fontsz; -} context_t; - -#define MAXNEST 4 -static context_t cstk[MAXNEST]; -static int SP; -static node_t *Curnode; - -static int white, black, transparent; - -static int gd_resolve_color(char *name) -{ - gvcolor_t color; - - if (!(strcmp(name, "transparent"))) { - /* special case for "transparent" color */ - return transparent; - } else { - colorxlate(name, &color, RGBA_BYTE); - /* seems gd alpha is "transparency" rather than the usual "opacity" */ - return gdImageColorResolveAlpha(im, - color.u.rgba[0], - color.u.rgba[1], - color.u.rgba[2], - (255 - - color.u.rgba[3]) * gdAlphaMax / - 255); - } -} - -static pointf gdpt(pointf p) -{ - pointf rv; - - if (Rot == 0) { - rv.x = (p.x - GraphFocus.x) * CompScale.x + Viewport.x / 2. + Margin.x; - rv.y = -(p.y - GraphFocus.y) * CompScale.y + Viewport.y / 2. + Margin.y; - } else { - rv.x = -(p.y - GraphFocus.y) * CompScale.x + Viewport.x / 2. + Margin.x; - rv.y = -(p.x - GraphFocus.x) * CompScale.y + Viewport.y / 2. + Margin.y; - } - return rv; -} - -static void gd_begin_job(FILE * ofp, graph_t * g, char **lib, char *user, - char *info[], point pages) -{ -/* Pages = pages; */ -/* N_pages = pages.x * pages.y; */ -#ifdef MYTRACE - fprintf(stderr, "gd_begin_job\n"); -#endif -} - -static void gd_end_job(void) -{ -#ifdef MYTRACE - fprintf(stderr, "gd_end_job\n"); -#endif -} - -static void init1_gd(GVC_t * gvc, graph_t * g, box bb, point pb) -{ - Dpi = gvc->job->dpi; - Margin.x = ROUND(gvc->job->margin.x * Dpi.x / POINTS_PER_INCH); - Margin.y = ROUND(gvc->job->margin.y * Dpi.y / POINTS_PER_INCH); - Viewport.x = gvc->job->width; - Viewport.y = gvc->job->height; - Zoom = gvc->job->zoom; - GraphFocus = gvc->job->focus; - CompScale.x = Zoom * Dpi.x / POINTS_PER_INCH; - CompScale.y = Zoom * Dpi.y / POINTS_PER_INCH; -} - -static void init2_gd(gdImagePtr im) -{ - SP = 0; - - white = gdImageColorResolveAlpha(im, - gdRedMax, gdGreenMax, gdBlueMax, - gdAlphaOpaque); - black = gdImageColorResolveAlpha(im, 0, 0, 0, gdAlphaOpaque); - transparent = gdImageColorResolveAlpha(im, - gdRedMax - 1, gdGreenMax, - gdBlueMax, gdAlphaTransparent); - gdImageColorTransparent(im, transparent); - - cstk[0].pencolor = black; /* set pen black */ - cstk[0].fontfam = "times"; /* font family name */ - 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 bool is_format_truecolor_capable(int Output_lang) -{ - bool rv = FALSE; - - if (Output_lang == GD) { - rv = TRUE; -#ifdef HAVE_LIBZ - } else if (Output_lang == GD2) { - rv = TRUE; -#endif -#ifdef HAVE_GD_GIF - } else if (Output_lang == GIF) { - rv = FALSE; -#endif -#ifdef HAVE_GD_JPEG - } else if (Output_lang == JPEG) { - rv = TRUE; -#endif -#ifdef HAVE_GD_PNG - } else if (Output_lang == PNG) { - rv = TRUE; -#endif - } else if (Output_lang == WBMP) { - rv = FALSE; -#ifdef HAVE_GD_XPM - } else if (Output_lang == XBM) { - rv = FALSE; -#endif - } - return rv; -} - -static void gd_begin_graph(GVC_t * gvc, graph_t * g, box bb, point pb) -{ - char *bgcolor_str = NULL; - char *truecolor_str; - bool truecolor_p = FALSE; /* try to use cheaper paletted mode */ - bool bg_transparent_p = FALSE; - int bgcolor; - - external_surface = gvc->job->external_surface; - - init1_gd(gvc, g, bb, pb); - - if (external_surface) { - im = (gdImagePtr)gvc->job->surface; - } else { - int width, height; - - truecolor_str = agget(g, "truecolor"); /* allow user to force truecolor */ - bgcolor_str = agget(g, "bgcolor"); - - if (truecolor_str && truecolor_str[0]) - truecolor_p = mapbool(truecolor_str); - - if (bgcolor_str && strcmp(bgcolor_str, "transparent") == 0) { - bg_transparent_p = TRUE; - if (is_format_truecolor_capable(Output_lang)) - truecolor_p = TRUE; /* force truecolor */ - } - - if (GD_has_images(g)) - truecolor_p = TRUE; /* force truecolor */ - - /* device size with margins all around */ - width = Viewport.x + 2 * Margin.x; - height = Viewport.y + 2 * Margin.y; - - if (truecolor_p) { - if (Verbose) - fprintf(stderr, "%s: allocating a %dK TrueColor GD image\n", - gvc->common.cmdname, ROUND(width * height * 4 / 1024.)); - im = gdImageCreateTrueColor(width, height); - } else { - if (Verbose) - fprintf(stderr, "%s: allocating a %dK PaletteColor GD image\n", - gvc->common.cmdname, ROUND(width * height / 1024.)); - im = gdImageCreate(width, height); - } - if (!im) { - agerr(AGERR, "gdImageCreate returned NULL. Malloc problem?\n"); - return; - } - } - - init2_gd(im); - - if (! external_surface) { - if (bgcolor_str && bgcolor_str[0]) - if (bg_transparent_p) - bgcolor = transparent; - else - bgcolor = gd_resolve_color(bgcolor_str); - else - bgcolor = white; - - cstk[0].fillcolor = bgcolor; - - /* Blending must be off to lay a transparent bgcolor. - Nothing to blend with anyway. */ - gdImageAlphaBlending(im, FALSE); - - gdImageFill(im, im->sx / 2, im->sy / 2, bgcolor); - - /* Blend everything else together, - especially fonts over non-transparent backgrounds */ - gdImageAlphaBlending(im, TRUE); - } - -#ifdef MYTRACE - fprintf(stderr, "gd_begin_graph\n"); -#endif -} - -static void gd_end_graph(void) -{ - if (!im || external_surface) - return; - -/* - * Windows will do \n -> \r\n translations on stdout unless told otherwise. - */ -#ifdef HAVE_SETMODE -#ifdef O_BINARY - setmode(fileno(Output_file), O_BINARY); -#endif -#endif - - /* Only save the alpha channel in outputs that support it if - the base color was transparent. Otherwise everything - was blended so there is no useful alpha info */ - if (im->trueColor) { - if (is_format_truecolor_capable(Output_lang)) - gdImageSaveAlpha(im, TRUE); - else - gdImageTrueColorToPalette(im, 0, 256); - } - if (Output_lang == GD) { - gdImageGd(im, Output_file); -#ifdef HAVE_LIBZ - } else if (Output_lang == GD2) { -#define GD2_CHUNKSIZE 128 -#define GD2_RAW 1 -#define GD2_COMPRESSED 2 - gdImageGd2(im, Output_file, GD2_CHUNKSIZE, GD2_COMPRESSED); -#endif -#ifdef HAVE_GD_GIF - } else if (Output_lang == GIF) { - gdImageGif(im, Output_file); -#endif -#ifdef HAVE_GD_JPEG - } else if (Output_lang == JPEG) { - /* - * Write IM to OUTFILE as a JFIF-formatted JPEG image, using - * quality JPEG_QUALITY. If JPEG_QUALITY is in the range - * 0-100, increasing values represent higher quality but - * also larger image size. If JPEG_QUALITY is negative, the - * IJG JPEG library's default quality is used (which should - * be near optimal for many applications). See the IJG JPEG - * library documentation for more details. - */ -#define JPEG_QUALITY -1 - gdImageJpeg(im, Output_file, JPEG_QUALITY); -#endif -#ifdef HAVE_GD_PNG - } else if (Output_lang == PNG) { - gdImagePng(im, Output_file); -#endif - } else if (Output_lang == WBMP) { - /* Use black for the foreground color for the B&W wbmp image. */ - gdImageWBMP(im, black, Output_file); -#ifdef HAVE_GD_XPM - } else if (Output_lang == XBM) { - gdImageXbm(im, Output_file); -#endif - } - gdImageDestroy(im); -#ifdef MYTRACE - fprintf(stderr, "gd_end_graph_to_file\n"); -#endif -} - -static void -gd_begin_page(graph_t * g, point page, double scale, int rot, point offset) -{ - if (!im) - return; - -/* int page_number; */ -/* point sz; */ - - Rot = rot; - -/* page_number = page.x + page.y * Pages.x + 1; */ -#ifdef MYTRACE - fprintf(stderr, "gd_begin_page\n"); - fprintf(stderr, " page=%d,%d offset=%d,%d\n", page.x, page.y, offset.x, - offset.y); - fprintf(stderr, " page_number=%d\n", page_number); -#endif -} - -void gd_end_page(void) -{ -#ifdef MYTRACE - fprintf(stderr, "gd_end_page\n"); -#endif -} - -static void gd_begin_node(node_t * n) -{ - Curnode = n; -} - -static void gd_end_node(void) -{ - Curnode = NULL; -} - -static void gd_begin_context(void) -{ - assert(SP + 1 < MAXNEST); - cstk[SP + 1] = cstk[SP]; - SP++; -} - -static void gd_end_context(void) -{ - int psp = SP - 1; - assert(SP > 0); - SP = psp; -} - -static void gd_set_font(char *fontname, double fontsize) -{ - context_t *cp; -#if 0 - char *p; - char *q; -#endif - - cp = &(cstk[SP]); - cp->fontsz = fontsize; -#if 0 - p = strdup(fontname); - if ((q = strchr(p, '-'))) { - *q++ = 0; - if (strcasecmp(q, "italic") == 0) - cp->fontopt = ITALIC; - else if (strcasecmp(q, "bold") == 0) - cp->fontopt = BOLD; - } -#endif - cp->fontfam = fontname; -} - -static void gd_set_pencolor(char *name) -{ - if (!im) - return; - - cstk[SP].pencolor = gd_resolve_color(name); -} - -static void gd_set_fillcolor(char *name) -{ - if (!im) - return; - - cstk[SP].fillcolor = gd_resolve_color(name); -} - -static void gd_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 - agerr(AGWARN, - "gd_set_style: unsupported style %s - ignoring\n", line); - } -} - -void gd_missingfont(char *err, char *fontreq) -{ - static char *lastmissing = 0; - static int n_errors = 0; - - if (n_errors >= 20) - return; - if ((lastmissing == 0) || (strcmp(lastmissing, fontreq))) { -#if HAVE_GD_FONTCONFIG - agerr(AGERR, "%s : %s\n", err, fontreq); -#else - char *p = getenv("GDFONTPATH"); - if (!p) - p = DEFAULT_FONTPATH; - agerr(AGERR, "%s : %s in %s\n", err, fontreq, p); -#endif - if (lastmissing) - free(lastmissing); - lastmissing = strdup(fontreq); - n_errors++; - if (n_errors >= 20) - agerr(AGWARN, "(font errors suppressed)\n"); - } -} - -extern gdFontPtr gdFontTiny, gdFontSmall, gdFontMediumBold, gdFontLarge, gdFontGiant; - -static void gd_textpara(point p, textpara_t * para) -{ - pointf mp, ep; - double fontsz; - gdFTStringExtra strex; - int pencolor; -#ifdef HAVE_GD_FREETYPE - char *err; - int brect[8]; -#endif - - if (!im) - return; - - strex.flags = gdFTEX_RESOLUTION; - strex.hdpi = strex.vdpi = Dpi.x * Zoom; - - if (cstk[SP].pen == P_NONE) - return; - - pencolor = cstk[SP].pencolor; - if (!im->trueColor && cstk[SP].fillcolor == transparent) - pencolor = -pencolor; /* disable antialiasing */ - - if (strstr(cstk[SP].fontfam, "/")) - strex.flags |= gdFTEX_FONTPATHNAME; - else - strex.flags |= gdFTEX_FONTCONFIG; - - fontsz = cstk[SP].fontsz; - - switch (para->just) { - case 'l': - mp.x = p.x; - break; - case 'r': - mp.x = p.x - para->width; - break; - default: - case 'n': - mp.x = p.x - para->width / 2; - break; - } - ep.y = mp.y = p.y; - ep.x = mp.x + para->width; - - mp = gdpt(mp); - if (fontsz <= FONTSIZE_MUCH_TOO_SMALL) { - /* ignore entirely */ - } else if (fontsz <= FONTSIZE_TOO_SMALL) { - /* draw line in place of text */ - ep = gdpt(ep); - gdImageLine(im, ROUND(mp.x), ROUND(mp.y), - ROUND(ep.x), ROUND(ep.y), cstk[SP].pencolor); - } else { -#ifdef HAVE_GD_FREETYPE - gdFTUseFontConfig(1); /* use fontconfig if possible */ - err = gdImageStringFTEx(im, brect, pencolor, - para->fontname, fontsz, Rot ? (PI / 2) : 0, - ROUND(mp.x), ROUND(mp.y), para->str, &strex); -#if 0 - gdImagePolygon(im, (gdPointPtr) brect, 4, cstk[SP].pencolor); -#endif -#if 0 - fprintf(stderr, - "textpara: font=%s size=%g pos=%g,%g width=%g dpi=%d width/dpi=%g\n", - para->fontname, fontsz, mp.x, mp.y, (double) (brect[4] - brect[0]), - strex.hdpi, - (((double) (brect[4] - brect[0])) / strex.hdpi)); -#endif - if (err) { - /* revert to builtin fonts */ - gd_missingfont(err, cstk[SP].fontfam); -#endif - mp.y += 2; - if (fontsz <= 8.5) { - gdImageString(im, gdFontTiny, - ROUND(mp.x), ROUND(mp.y - 9.), - (unsigned char *) para->str, cstk[SP].pencolor); - } else if (fontsz <= 9.5) { - gdImageString(im, gdFontSmall, - ROUND(mp.x), ROUND(mp.y - 12.), - (unsigned char *) para->str, cstk[SP].pencolor); - } else if (fontsz <= 10.5) { - gdImageString(im, gdFontMediumBold, - ROUND(mp.x), ROUND(mp.y - 13.), - (unsigned char *) para->str, cstk[SP].pencolor); - } else if (fontsz <= 11.5) { - gdImageString(im, gdFontLarge, - ROUND(mp.x), ROUND(mp.y - 14.), - (unsigned char *) para->str, cstk[SP].pencolor); - } else { - gdImageString(im, gdFontGiant, - ROUND(mp.x), ROUND(mp.y - 15.), - (unsigned char *) para->str, cstk[SP].pencolor); - } -#ifdef HAVE_GD_FREETYPE - } -#endif - } -} - -static void -gd_bezier(point * A, int n, int arrow_at_start, int arrow_at_end, int filled) -{ - pointf p, p0, p1, V[4]; - int i, j, step; - int style[20]; - int pen, width; - gdImagePtr brush = NULL; - gdPoint F[4]; - - if (!im) - return; - - if (cstk[SP].pen != P_NONE) { - if (cstk[SP].pen == P_DASHED) { - for (i = 0; i < 10; i++) - style[i] = cstk[SP].pencolor; - for (; i < 20; i++) - style[i] = transparent; - gdImageSetStyle(im, style, 20); - pen = gdStyled; - } else if (cstk[SP].pen == P_DOTTED) { - for (i = 0; i < 2; i++) - style[i] = cstk[SP].pencolor; - for (; i < 12; i++) - style[i] = transparent; - gdImageSetStyle(im, style, 12); - pen = gdStyled; - } else { - pen = cstk[SP].pencolor; - } - width = cstk[SP].penwidth * CompScale.x; - if (width < WIDTH_NORMAL) - width = WIDTH_NORMAL; /* gd can't do thin lines */ - gdImageSetThickness(im, width); - if (width > WIDTH_NORMAL) { - brush = gdImageCreate(width, width); - gdImagePaletteCopy(brush, im); - gdImageFilledRectangle(brush, - 0, 0, width - 1, width - 1, - cstk[SP].pencolor); - gdImageSetBrush(im, brush); - if (pen == gdStyled) - pen = gdStyledBrushed; - else - pen = gdBrushed; - } - p.x = A[0].x; - p.y = A[0].y; - p = gdpt(p); - F[0].x = ROUND(p.x); - F[0].y = ROUND(p.y); - p.x = A[n-1].x; - p.y = A[n-1].y; - p = gdpt(p); - F[3].x = ROUND(p.x); - F[3].y = ROUND(p.y); - V[3].x = A[0].x; - V[3].y = A[0].y; - 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; - } - p0 = gdpt(V[0]); - for (step = 1; step <= BEZIERSUBDIVISION; step++) { - p1 = gdpt(Bezier - (V, 3, (double) step / BEZIERSUBDIVISION, NULL, - NULL)); - gdImageLine(im, ROUND(p0.x), ROUND(p0.y), ROUND(p1.x), - ROUND(p1.y), pen); - if (filled) { - F[1].x = ROUND(p0.x); - F[1].y = ROUND(p0.y); - F[2].x = ROUND(p1.x); - F[2].y = ROUND(p1.y); - gdImageFilledPolygon(im, F, 4, cstk[SP].fillcolor); - } - p0 = p1; - } - } - if (brush) - gdImageDestroy(brush); - } -} - -static void gd_polygon(point * A, int n, int filled) -{ - pointf p; - int i; - gdPoint *points; - int style[20]; - int pen, width; - gdImagePtr brush = NULL; - - if (!im) - return; - - if (cstk[SP].pen != P_NONE) { - if (cstk[SP].pen == P_DASHED) { - for (i = 0; i < 10; i++) - style[i] = cstk[SP].pencolor; - for (; i < 20; i++) - style[i] = transparent; - gdImageSetStyle(im, style, 20); - pen = gdStyled; - } else if (cstk[SP].pen == P_DOTTED) { - for (i = 0; i < 2; i++) - style[i] = cstk[SP].pencolor; - for (; i < 12; i++) - style[i] = transparent; - gdImageSetStyle(im, style, 12); - pen = gdStyled; - } else { - pen = cstk[SP].pencolor; - } - width = cstk[SP].penwidth * CompScale.x; - if (width < WIDTH_NORMAL) - width = WIDTH_NORMAL; /* gd can't do thin lines */ - gdImageSetThickness(im, width); - /* use brush instead of Thickness to improve end butts */ - if (width > WIDTH_NORMAL) { - brush = gdImageCreate(width, width); - gdImagePaletteCopy(brush, im); - gdImageFilledRectangle(brush, - 0, 0, width - 1, width - 1, - cstk[SP].pencolor); - gdImageSetBrush(im, brush); - if (pen == gdStyled) - pen = gdStyledBrushed; - else - pen = gdBrushed; - } - points = N_GNEW(n, gdPoint); - for (i = 0; i < n; i++) { - p.x = A[i].x; - p.y = A[i].y; - p = gdpt(p); - points[i].x = ROUND(p.x); - points[i].y = ROUND(p.y); - } - if (filled) { - gdImageFilledPolygon(im, points, n, cstk[SP].fillcolor); - } - - gdImagePolygon(im, points, n, pen); - free(points); - if (brush) - gdImageDestroy(brush); - } -} - -static void gd_ellipse(point p, int rx, int ry, int filled) -{ - pointf mp; - int i; - int style[40]; /* need 2* size for arcs, I don't know why */ - int pen, width; - gdImagePtr brush = NULL; - - if (!im) - return; - - if (cstk[SP].pen != P_NONE) { - if (cstk[SP].pen == P_DASHED) { - for (i = 0; i < 20; i++) - style[i] = cstk[SP].pencolor; - for (; i < 40; i++) - style[i] = transparent; - gdImageSetStyle(im, style, 40); - pen = gdStyled; - } else if (cstk[SP].pen == P_DOTTED) { - for (i = 0; i < 2; i++) - style[i] = cstk[SP].pencolor; - for (; i < 24; i++) - style[i] = transparent; - gdImageSetStyle(im, style, 24); - pen = gdStyled; - } else { - pen = cstk[SP].pencolor; - } - width = cstk[SP].penwidth * CompScale.x; - if (width < WIDTH_NORMAL) - width = WIDTH_NORMAL; /* gd can't do thin lines */ - gdImageSetThickness(im, width); - /* use brush instead of Thickness to improve outline appearance */ - if (width > WIDTH_NORMAL) { - brush = gdImageCreate(width, width); - gdImagePaletteCopy(brush, im); - gdImageFilledRectangle(brush, - 0, 0, width - 1, width - 1, - cstk[SP].pencolor); - gdImageSetBrush(im, brush); - if (pen == gdStyled) - pen = gdStyledBrushed; - else - pen = gdBrushed; - } - if (Rot) { - int t; - t = rx; - rx = ry; - ry = t; - } - mp.x = p.x; - mp.y = p.y; - mp = gdpt(mp); - if (filled) { - gdImageFilledEllipse(im, ROUND(mp.x), ROUND(mp.y), - ROUND(CompScale.x * (rx + rx)), - ROUND(CompScale.y * (ry + ry)), - cstk[SP].fillcolor); - } - gdImageArc(im, ROUND(mp.x), ROUND(mp.y), - ROUND(CompScale.x * (rx + rx)), - ROUND(CompScale.y * (ry + ry)), 0, 360, pen); - if (brush) - gdImageDestroy(brush); - } -} - -static void gd_polyline(point * A, int n) -{ - pointf p, p1; - int i; - int style[20]; - int pen, width; - gdImagePtr brush = NULL; - - if (!im) - return; - - if (cstk[SP].pen != P_NONE) { - if (cstk[SP].pen == P_DASHED) { - for (i = 0; i < 10; i++) - style[i] = cstk[SP].pencolor; - for (; i < 20; i++) - style[i] = transparent; - gdImageSetStyle(im, style, 20); - pen = gdStyled; - } else if (cstk[SP].pen == P_DOTTED) { - for (i = 0; i < 2; i++) - style[i] = cstk[SP].pencolor; - for (; i < 12; i++) - style[i] = transparent; - gdImageSetStyle(im, style, 12); - pen = gdStyled; - } else { - pen = cstk[SP].pencolor; - } - width = cstk[SP].penwidth * CompScale.x; - if (width < WIDTH_NORMAL) - width = WIDTH_NORMAL; /* gd can't do thin lines */ - gdImageSetThickness(im, width); - if (width != WIDTH_NORMAL) { - brush = gdImageCreate(width, width); - gdImagePaletteCopy(brush, im); - gdImageFilledRectangle(brush, - 0, 0, width - 1, width - 1, - cstk[SP].pencolor); - gdImageSetBrush(im, brush); - if (pen == gdStyled) - pen = gdStyledBrushed; - else - pen = gdBrushed; - } - p.x = A[0].x; - p.y = A[0].y; - p = gdpt(p); - for (i = 1; i < n; i++) { - p1.x = A[i].x; - p1.y = A[i].y; - p1 = gdpt(p1); - gdImageLine(im, ROUND(p.x), ROUND(p.y), - ROUND(p1.x), ROUND(p1.y), pen); - p.x = p1.x; - p.y = p1.y; - } - if (brush) - gdImageDestroy(brush); - } -} - -static void gd_freeimage(usershape_t *us) -{ - gdImageDestroy((gdImagePtr)us->data); -} - -static void gd_usershape(usershape_t *us, boxf b, point *A, int n, bool filled) -{ - gdImagePtr im2 = NULL, im3; - - if (!us->f) - return; - - if (us->data) { - if (us->datafree == gd_freeimage) - im2 = (gdImagePtr)(us->data); /* use cached data */ - else { - us->datafree(us); /* free incompatible cache data */ - us->data = NULL; - } - } - if (!im2) { /* read file into cache */ - fseek(us->f, 0, SEEK_SET); - switch (us->type) { -#ifdef HAVE_GD_PNG - case FT_PNG: - im2 = gdImageCreateFromPng(us->f); - break; -#endif -#ifdef HAVE_GD_GIF - case FT_GIF: - im2 = gdImageCreateFromGif(us->f); - break; -#endif -#ifdef HAVE_GD_JPEG - case FT_JPEG: - im2 = gdImageCreateFromJpeg(us->f); - break; -#endif - default: - im2 = NULL; - } - if (im2) { - us->data = (void*)im2; - us->datafree = gd_freeimage; - } - } - if (im2) { - if (Rot) { - im3 = gdImageCreate(im2->sy, im2->sx); /* scratch image for rotation */ - gdImageCopyRotated(im3, im2, im3->sx / 2., im3->sy / 2., - 0, 0, im2->sx, im2->sy, Rot); - gdImageCopyResized(im, im3, ROUND(b.LL.x), ROUND(b.LL.y), 0, 0, - ROUND(b.UR.y - b.LL.y), ROUND(b.UR.x - b.LL.x), im3->sx, im3->sy); - gdImageDestroy(im3); - } - else { - gdImageCopyResized(im, im2, ROUND(b.LL.x), ROUND(b.LL.y), 0, 0, - ROUND(b.UR.x - b.LL.x), ROUND(b.UR.y - b.LL.y), im2->sx, im2->sy); - } - } -} - -codegen_t GD_CodeGen = { - 0, /* gd_reset */ - gd_begin_job, gd_end_job, - gd_begin_graph, gd_end_graph, - gd_begin_page, gd_end_page, - 0, /* gd_begin_layer */ 0, /* gd_end_layer */ - 0, /* gd_begin_cluster */ 0, /* gd_end_cluster */ - 0, /* gd_begin_nodes */ 0, /* gd_end_nodes */ - 0, /* gd_begin_edges */ 0, /* gd_end_edges */ - gd_begin_node, gd_end_node, - 0, /* gd_begin_edge */ 0, /* gd_end_edge */ - gd_begin_context, gd_end_context, - 0, /* gd_begin_anchor */ 0, /* gd_end_anchor */ - gd_set_font, gd_textpara, - gd_set_pencolor, gd_set_fillcolor, gd_set_style, - gd_ellipse, gd_polygon, - gd_bezier, gd_polyline, - 0, /* bezier_has_arrows */ - 0, /* gd_comment */ - gd_usershape -}; diff --git a/lib/common/mapgen.c b/lib/common/mapgen.c deleted file mode 100644 index 4147a58e0..000000000 --- a/lib/common/mapgen.c +++ /dev/null @@ -1,1157 +0,0 @@ -/* $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 * -**********************************************************/ - -#define NEWANCHORS 0 - -#include "render.h" -#include "htmltable.h" - -/* IMAP font modifiers */ -#define REGULAR 0 -#define BOLD 1 -#define ITALIC 2 - -/* IMAP 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 */ - -/* IMAP bold line constant */ -#define WIDTH_NORMAL 1 -#define WIDTH_BOLD 3 - -/* static int N_pages; */ -/* static point Pages; */ -static int onetime = TRUE; -static int isLatin1; - -typedef struct context_t { - char color_ix, *fontfam, fontopt, font_was_set; - char pen, fill, penwidth, style_was_set; - double fontsz; -} context_t; - -#ifdef OLD -#define MAXNEST 4 -static context_t cstk[MAXNEST]; -static int SP; -#endif - -static double Dpi; -static double DevScale; -static double CompScale; -static int Rot; - -static point Viewport; -static pointf GraphFocus; -static double Zoom; - -/* isRect: - * isRect function returns true when polygon has - * regular rectangular shape. Rectangle is regular when - * it is not skewed and distorted and orientation is almost zero - */ -bool isRect(polygon_t * p) -{ - return (p->sides == 4 && (ROUND(p->orientation) % 90) == 0 - && p->distortion == 0.0 && p->skew == 0.0); -} - -/* pEllipse: - * pEllipse function returns 'np' points from the circumference - * of ellipse described by radii 'a' and 'b'. - * Assumes 'np' is greater than zero. - * 'np' should be at least 4 to sample polygon from ellipse - */ -static pointf *pEllipse(double a, double b, int np) -{ - double theta = 0.0; - double deltheta = 2 * M_PI / np; - int i; - pointf *ps; - - ps = N_NEW(np, pointf); - for (i = 0; i < np; i++) { - ps[i].x = a * cos(theta); - ps[i].y = b * sin(theta); - theta += deltheta; - } - return ps; -} - -static pointf mapptf(pointf p) -{ - pointf rv; - - if (Rot == 0) { - rv.x = (p.x - GraphFocus.x) * CompScale + Viewport.x / 2.; - rv.y = -(p.y - GraphFocus.y) * CompScale + Viewport.y / 2.; - } else { - rv.x = -(p.y - GraphFocus.y) * CompScale + Viewport.x / 2.; - rv.y = -(p.x - GraphFocus.x) * CompScale + Viewport.y / 2.; - } - /* apply clipping */ - if (rv.x < 0) - rv.x = 0; - if (rv.x > (double) Viewport.x) - rv.x = (double) (Viewport.x - 1); - if (rv.y < 0) - rv.y = 0; - if (rv.y > (double) Viewport.y) - rv.y = (double) (Viewport.y - 1); - return rv; -} - -/* - * isFilled function returns 1 if filled style has been set for node 'n' - * otherwise returns 0. it accepts pointer to node_t as an argument - */ -static int ifFilled(node_t * n) -{ - char *style, *p, **pp; - int r = 0; - style = late_nnstring(n, N_style, ""); - if (style[0]) { - pp = parse_style(style); - while ((p = *pp)) { - if (strcmp(p, "filled") == 0) - r = 1; - pp++; - } - } - return r; -} - -#if ! NEWANCHORS -static void mapOutput (map_shape_t map_shape, point* pp, int nump, - char* url, char *target, char *label, char *tooltip) -{ - int i; - - if (Output_lang == IMAP && url && url[0]) { - switch (map_shape) { - case MAP_RECTANGLE: - fprintf(Output_file, "rectangle %s %d %d %d %d\n", url, - pp[0].x, pp[0].y, pp[1].x, pp[1].y); - break; - case MAP_CIRCLE: - fprintf(Output_file, "circle %s %d %d %d %d\n", url, - pp[0].x, pp[0].y, (pp[1].x+pp[0].x), pp[0].y); - break; - case MAP_POLYGON: - fprintf(Output_file, "poly %s", url); - for (i = 0; i < nump; i++) - fprintf(Output_file, " %d,%d", pp[i].x, pp[i].y); - fprintf(Output_file, "\n"); - break; - default: - assert(0); - break; - } - - } else if (Output_lang == ISMAP && url && url[0]) { - switch (map_shape) { - case MAP_RECTANGLE: - fprintf(Output_file, "rectangle (%d,%d) (%d,%d) %s %s\n", - pp[0].x, pp[0].y, pp[1].x, pp[1].y, url, label); - break; - default: - assert(0); - break; - } - - } else if (Output_lang == CMAP || Output_lang == CMAPX) { - switch (map_shape) { - case MAP_RECTANGLE: - fprintf(Output_file, "\n"); - - } else if (Output_lang == POSTSCRIPT || Output_lang == PDF) { - if (url && url[0]) { - fprintf(Output_file, "[ /Rect [ %d %d %d %d ]\n" - " /Border [ 0 0 0 ]\n" - " /Action << /Subtype /URI /URI %s >>\n" - " /Subtype /Link\n" - "/ANN pdfmark\n", - pp[0].x, pp[0].y, pp[1].x, pp[1].y, ps_string(url, isLatin1)); - } - } -} -#endif - -/* - * map_output_poly function generates the map file of requested format - * currently imap, cmapx, ismap, cmap, postscipt and pdf formats are supported - * This function maps the node. - */ -static void -map_output_poly(node_t * n, char *url, - char *target, char *label, char *tooltip, int sample) -{ - int sides, peri, nump, i, j, filled = 0, rect = 0, nshape; - pointf *ppf, *vertices, ldimen; - point *pp, coord; - map_shape_t map_shape; - polygon_t *poly = NULL; - - /* checking shape of node */ - nshape = shapeOf(n); - /* node coordinate */ - coord = ND_coord_i(n); - /* checking if filled style has been set for node */ - filled = ifFilled(n); - - if (nshape == SH_POLY || nshape == SH_POINT) { - poly = (polygon_t *) ND_shape_info(n); - - /* checking if polygon is regular rectangle */ - if (isRect(poly) && (poly->peripheries || filled)) - rect = 1; - } - - /* When node has polygon shape and requested output format is imap or cmapx, - * we have used shape of polygon to map clickable region that is circle, - * ellipse, polygon with n side, or point. For regular rectangular shape - * we have use node's bounding box to map clickable region - */ - if (poly && !rect && (Output_lang == IMAP || Output_lang == CMAPX)) { - - if (poly->sides < 3) - sides = 1; - else - sides = poly->sides; - - if (poly->peripheries < 2) - peri = 1; - else - peri = poly->peripheries; - - vertices = poly->vertices; - - /* use bounding box of text label for mapping - * when polygon has no peripheries and node is not filled - */ - if (poly->peripheries == 0 && !filled) { - map_shape = MAP_RECTANGLE; - nump = 2; - ppf = N_NEW(nump, pointf); - pp = N_NEW(nump, point); - ldimen = ND_label(n)->dimen; - ppf[0].x = coord.x - (ldimen.x) / 2.0; - ppf[0].y = coord.y + (ldimen.y) / 2.0; - ppf[1].x = coord.x + (ldimen.x) / 2.0; - ppf[1].y = coord.y - (ldimen.y) / 2.0; - - } - /* circle or ellipse */ - else if (poly->sides < 3 && poly->skew == 0.0 - && poly->distortion == 0.0) { - if (poly->regular) { - map_shape = MAP_CIRCLE; - nump = 2; /* center of circle and radius */ - ppf = N_NEW(nump, pointf); - pp = N_NEW(nump, point); - ppf[0].x = coord.x; - ppf[0].y = coord.y; - ppf[1].x = vertices[peri - 1].x; - ppf[1].y = vertices[peri - 1].y; - } - else { /* ellipse is treated as polygon */ - double a, b; - map_shape = MAP_POLYGON; - a = vertices[peri - 1].x; - b = vertices[peri - 1].y; - nump = sample; - ppf = pEllipse(a, b, nump); - pp = N_NEW(nump, point); - for (i = 0; i < nump; i++) { - ppf[i].x += coord.x; - ppf[i].y += coord.y; - } - } - /* all other polygonal shape */ - } else { - int offset = (peri - 1)*(poly->sides); - map_shape = MAP_POLYGON; - /* distorted or skewed ellipses and circles are polygons with 120 - * sides. For mapping we convert them into polygon with sample sides - */ - if (poly->sides == 120) { - int delta = 120/sample; - nump = sample; - ppf = N_NEW(nump, pointf); - pp = N_NEW(nump, point); - for (i = 0, j = 0; j < nump; i += delta, j++) { - ppf[j].x = coord.x + vertices[i + offset].x; - ppf[j].y = coord.y + vertices[i + offset].y; - } - } else { - nump = sides; - ppf = N_NEW(nump, pointf); - pp = N_NEW(nump, point); - for (i = 0; i < nump; i++) { - ppf[i].x = coord.x + vertices[i + offset].x; - ppf[i].y = coord.y + vertices[i + offset].y; - } - } - } - } else { - /* we have used node's bounding box to map clickable region - * when requested output format is neither imap nor cmapx and for all - * node shapes other than polygon ( except regular rectangle polygon ) - */ - map_shape = MAP_RECTANGLE; - nump = 2; - ppf = N_NEW(nump, pointf); - pp = N_NEW(nump, point); - ppf[0].x = ND_coord_i(n).x - ND_lw_i(n); - ppf[0].y = ND_coord_i(n).y + (ND_ht_i(n) / 2); - ppf[1].x = ND_coord_i(n).x + ND_rw_i(n); - ppf[1].y = ND_coord_i(n).y - (ND_ht_i(n) / 2); - } - - /* apply scaling and translation if necessary */ - if (Output_lang == ISMAP - || Output_lang == IMAP - || Output_lang == CMAP || Output_lang == CMAPX) { - for (i = 0; i < nump; i++) { - ppf[i] = mapptf(ppf[i]); - } - } - - for (i = 0; i < nump; i++) { - pp[i].x = ROUND(ppf[i].x); - pp[i].y = ROUND(ppf[i].y); - } - -#if ! NEWANCHORS - mapOutput (map_shape, pp, nump, url, target, label, tooltip); -#endif - free(ppf); - free(pp); -} - -static void -map_output_rect(pointf p1, pointf p2, char *url, char *target, char *label, - char *tooltip) -{ - pointf ppf1, ppf2; - point pp[2]; - double t; - - if (!(url && url[0]) && !(tooltip && tooltip[0])) - return; - - /* apply scaling and translation if necessary */ - if (Output_lang == ISMAP - || Output_lang == IMAP - || Output_lang == CMAP || Output_lang == CMAPX) { - ppf1 = mapptf(p1); - ppf2 = mapptf(p2); - } else { - ppf1 = p1; - ppf2 = p2; - } - pp[0].x = ROUND(ppf1.x); - pp[0].y = ROUND(ppf1.y); - pp[1].x = ROUND(ppf2.x); - pp[1].y = ROUND(ppf2.y); - - /* suppress maps that are totally clipped in either x or y */ - if (pp[0].x == pp[1].x || pp[0].y == pp[1].y) - return; - - /* fix up coordinate order */ - if (pp[1].x < pp[0].x) { - t = pp[1].x; - pp[1].x = pp[0].x; - pp[0].x = t; - } - if (pp[1].y < pp[0].y) { - t = pp[1].y; - pp[1].y = pp[0].y; - pp[0].y = t; - } -#if ! NEWANCHORS - mapOutput (MAP_RECTANGLE, pp, 2, url, target, label, tooltip); -#endif -} - -/* radius of mouse-sensitive region around a point */ -#define FUZZ 3 -static void -map_output_fuzzy_point(pointf p, char *url, char *target, char *label, - char *tooltip) -{ - pointf p1, p2; - - p1.x = p.x - FUZZ; - p1.y = p.y - FUZZ; - p2.x = p.x + FUZZ; - p2.y = p.y + FUZZ; - - map_output_rect(p1, p2, url, target, label, tooltip); -} - -static void map_reset(void) -{ - onetime = TRUE; -} - -static void init_imap(void) -{ -#ifdef OLD - SP = 0; - cstk[0].color_ix = 0; /* IMAP color index 0-7 */ - cstk[0].fontfam = "Times"; /* font family name */ - cstk[0].fontopt = REGULAR; /* modifier: REGULAR, BOLD or ITALIC */ - cstk[0].pen = P_SOLID; /* pen pattern style, default is sold */ - cstk[0].fill = P_NONE; - cstk[0].penwidth = WIDTH_NORMAL; -#endif -} - -static void doHTMLdata(htmldata_t * dp, point p, void *obj) -{ - char *url = NULL, *target = NULL, *title = NULL; - pointf p1, p2; - int havetitle = 0; - - if ((url = dp->href) && url[0]) { - switch (agobjkind(obj)) { - case AGGRAPH: - url = strdup_and_subst_graph(url, (graph_t *) obj); - break; - case AGNODE: - url = strdup_and_subst_node(url, (node_t *) obj); - break; - case AGEDGE: - url = strdup_and_subst_edge(url, (edge_t *) obj); - break; - } - } - target = dp->target; - if ((title = dp->title) && title[0]) { - havetitle++; - switch (agobjkind(obj)) { - case AGGRAPH: - title = strdup_and_subst_graph(title, (graph_t *) obj); - break; - case AGNODE: - title = strdup_and_subst_node(title, (node_t *) obj); - break; - case AGEDGE: - title = strdup_and_subst_edge(title, (edge_t *) obj); - break; - } - } - if (url || title) { - p1.x = p.x + dp->box.LL.x; - p1.y = p.y + dp->box.LL.y; - p2.x = p.x + dp->box.UR.x; - p2.y = p.y + dp->box.UR.y; - map_output_rect(p1, p2, url, target, "", title); - } - free(url); - free(title); -} - -/* forward declaration */ -static void doHTMLcell(htmlcell_t * cp, point p, void *obj); - -static void doHTMLtbl(htmltbl_t * tbl, point p, void *obj) -{ - htmlcell_t **cells = tbl->u.n.cells; - htmlcell_t *cp; - - while ((cp = *cells++)) - doHTMLcell(cp, p, obj); - if (tbl->data.href) - doHTMLdata(&tbl->data, p, obj); -} - -static void doHTMLcell(htmlcell_t * cp, point p, void *obj) -{ - if (cp->child.kind == HTML_TBL) - doHTMLtbl(cp->child.u.tbl, p, obj); - if (cp->data.href) - doHTMLdata(&cp->data, p, obj); -} - -static void doHTMLlabel(htmllabel_t * lbl, point p, void *obj) -{ - if (lbl->kind == HTML_TBL) { - doHTMLtbl(lbl->u.tbl, p, obj); - } -} - -static void -map_begin_job(FILE * ofp, graph_t * g, char **lib, char *user, - char *info[], point pages) -{ - /* Pages = pages; */ - /* N_pages = pages.x * pages.y; */ - if (Output_lang == IMAP) { - fprintf(Output_file, "base referer\n"); - } else if (Output_lang == ISMAP) { -/* fprintf(Output_file,"base referer\n"); */ - } else if (Output_lang == CMAP || Output_lang == CMAPX) { -/* fprintf(Output_file,"base referer\n"); */ - } else if (Output_lang == POSTSCRIPT || Output_lang == PDF) { -/* fprintf(Output_file,"base referer\n"); */ - } - isLatin1 = (GD_charset(g) == CHAR_LATIN1); -} - -static void map_begin_graph(GVC_t * gvc, graph_t * g, box bb, point pb) -{ - Dpi = GD_drawing(g)->dpi; - if (Dpi < 1.0) - Dpi = DEFAULT_DPI; - DevScale = Dpi / POINTS_PER_INCH; - - Viewport.x = gvc->job->width; - Viewport.y = gvc->job->height; - if (Viewport.x) { - Zoom = gvc->job->zoom; - GraphFocus = gvc->job->focus; - } else { - Viewport.x = - (bb.UR.x - bb.LL.x + 2 * GD_drawing(g)->margin.x) * DevScale + - 2; - Viewport.y = - (bb.UR.y - bb.LL.y + 2 * GD_drawing(g)->margin.y) * DevScale + - 2; - GraphFocus.x = (GD_bb(g).UR.x - GD_bb(g).LL.x) / 2.; - GraphFocus.y = (GD_bb(g).UR.y - GD_bb(g).LL.y) / 2.; - Zoom = 1.0; - } - CompScale = Zoom * DevScale; - - if (onetime) { - init_imap(); - onetime = FALSE; - } -} - -static graph_t *Root_Graph; -static char *Default_URL; - -static void -map_begin_page(graph_t * g, point page, double scale, int rot, - point offset) -{ - char *url, *name; - - Rot = rot; - name = xml_string(g->name); - - if (Output_lang == CMAPX) { - fprintf(Output_file, "\n", name, name); - } - Root_Graph = g; - Default_URL = NULL; - if (((url = agget(g, "href")) && url[0]) - || ((url = agget(g, "URL")) && url[0])) { - if (Output_lang == IMAP) { - fprintf(Output_file, "default %s\n", url); - } else if (Output_lang == ISMAP) { - fprintf(Output_file, "default %s %s\n", url, g->name); - } else if (Output_lang == CMAP || Output_lang == CMAPX) { - Default_URL = url; - } - } - -} - -static void map_end_page(void) -{ - pointf Default_p1, Default_p2; - char *Default_label; - graph_t *g = Root_Graph; - - if (GD_label(g) && GD_label(g)->html) - doHTMLlabel(GD_label(g)->u.html, GD_label(g)->p, (void *) g); - if (Default_URL) { - Default_URL = strdup_and_subst_graph(Default_URL, g); - Default_label = g->name; - Default_p1.x = GD_bb(g).LL.x; - Default_p1.y = GD_bb(g).LL.y; - Default_p2.x = GD_bb(g).UR.x; - Default_p2.y = GD_bb(g).UR.y; - map_output_rect(Default_p1, Default_p2, Default_URL, "", - Default_label, ""); - free(Default_URL); - } - if (Output_lang == CMAPX) { - fprintf(Output_file, "\n"); - } -} - -void map_begin_cluster(graph_t * g) -{ - char *s, *url = NULL, *target = NULL, *title = NULL, *tooltip = NULL, - *m_url = NULL, *m_target = NULL, *m_tooltip = NULL; - pointf p1, p2; - - if (GD_label(g)) { - if (GD_label(g)->html) - doHTMLlabel(GD_label(g)->u.html, GD_label(g)->p, (void *) g); - title = GD_label(g)->text; - } - if (((s = agget(g, "href")) && s[0]) - || ((s = agget(g, "URL")) && s[0])) - m_url = url = strdup_and_subst_graph(s, g); - if ((s = agget(g, "target")) && s[0]) - m_target = target = strdup_and_subst_graph(s, g); - if ((s = agget(g, "tooltip")) && s[0]) - m_tooltip = tooltip = strdup_and_subst_graph(s, g); - else - tooltip = title; - if (url || m_tooltip) { - p1.x = GD_bb(g).LL.x; - p1.y = GD_bb(g).LL.y; - p2.x = GD_bb(g).UR.x; - p2.y = GD_bb(g).UR.y; - map_output_rect(p1, p2, url, target, title, tooltip); - } - free(m_target); - free(m_tooltip); - free(m_url); -} - -void map_begin_node(node_t * n) -{ - char *s, *url = NULL, *target = NULL, *tooltip = NULL, - *m_url = NULL, *m_target = NULL, *m_tooltip = NULL; - - if (ND_label(n)->html) - doHTMLlabel(ND_label(n)->u.html, ND_coord_i(n), (void *) n); - if (((s = agget(n, "href")) && s[0]) || ((s = agget(n, "URL")) && s[0])) - m_url = url = strdup_and_subst_node(s, n); - if ((s = agget(n, "target")) && s[0]) - m_target = target = strdup_and_subst_node(s, n); - if ((s = agget(n, "tooltip")) && s[0]) - m_tooltip = tooltip = strdup_and_subst_node(s, n); - else - tooltip = ND_label(n)->text; - - if (url || m_tooltip) { - int sample = 0; - char *p = agget(n, "samplepoints"); - if (p) - sample = atoi(p); - /* We want at least 4 points. For server-side maps, at most 100 - * points are allowed. To simplify things to fit with the 120 points - * used for skewed ellipses, we set the bound at 60. - */ - if ((sample < 4) || (sample > 60)) - sample = DFLT_SAMPLE; - map_output_poly(n, url, target, ND_label(n)->text, tooltip, sample); - } - - free(m_url); - free(m_target); - free(m_tooltip); -} - -#define HW 2.0 /* maximum distance away from line, in points */ - -/* check_control_points: - * check_control_points function checks the size of quadrilateral - * formed by four control points - * returns 1 if four points are in line (or close to line) - * else return 0 - */ -static int check_control_points(pointf *cp) -{ - double dis1 = ptToLine2 (cp[0], cp[3], cp[1]); - double dis2 = ptToLine2 (cp[0], cp[3], cp[2]); - if (dis1 < HW*HW && dis2 < HW*HW) - return 1; - else - return 0; -} - -#ifdef DEBUG -void psmapOutput (point* ps, int n) -{ - int i; - fprintf (stdout, "newpath %d %d moveto\n", ps[0].x, ps[0].y); - for (i=1; i < n; i++) - fprintf (stdout, "%d %d lineto\n", ps[i].x, ps[i].y); - fprintf (stdout, "closepath stroke\n"); -} -#endif - -typedef struct segitem_s { - pointf p; - struct segitem_s* next; -} segitem_t; - -#define MARK_FIRST_SEG(L) ((L)->next = (segitem_t*)1) -#define FIRST_SEG(L) ((L)->next == (segitem_t*)1) -#define INIT_SEG(P,L) {(L)->next = 0; (L)->p = P;} - -static segitem_t* -appendSeg (pointf p, segitem_t* lp) -{ - segitem_t* s = GNEW(segitem_t); - INIT_SEG (p, s); - lp->next = s; - return s; -} - -/* map_bspline_poly: - * Output the polygon determined by the n points in p1, followed - * by the n points in p2 in reverse order. Assumes n <= 50. - * - * Note: when using psmapOutput for debugging, remove the calls to - * mapptf, since for postscript the necessary parameters aren't defined and - * mapptf always returns (0,0). - */ -static void -map_bspline_poly(int n, pointf* p1, pointf* p2, - char *url, char* target, char* tooltip) -{ - int i; - pointf ppf; - point rp[100]; - int last = 2*n-1; - - for (i = 0; i < n; i++) { - ppf = mapptf(p1[i]); - rp[i].x = ROUND(ppf.x); - rp[i].y = ROUND(ppf.y); - } - for (i = 0; i < n; i++) { - ppf = mapptf(p2[i]); - rp[last-i].x = ROUND(ppf.x); - rp[last-i].y = ROUND(ppf.y); - } - mapOutput (MAP_POLYGON, rp, last+1, url, target, NULL, tooltip); -#ifdef DEBUG - psmapOutput (rp, last+1); -#endif -} -/* approx_bezier: - * Approximate Bezier by line segments. If the four points are - * almost colinear, as determined by check_control_points, we store - * the segment cp[0]-cp[3]. Otherwise we split the Bezier into 2 - * and recurse. - * Since 2 contiguous segments share an endpoint, we actually store - * the segments as a list of points. - * New points are appended to the list given by lp. The tail of the - * list is returned. - */ -static segitem_t* -approx_bezier (pointf *cp, segitem_t* lp) -{ - pointf sub_curves[8]; - - if (check_control_points(cp)) { - if (FIRST_SEG (lp)) INIT_SEG (cp[0], lp); - lp = appendSeg (cp[3], lp); - } - else { - Bezier (cp, 3, 0.5, sub_curves, sub_curves+4); - lp = approx_bezier (sub_curves, lp); - lp = approx_bezier (sub_curves+4, lp); - } - return lp; -} - -/* bisect: - * Return the angle of the bisector between the two rays - * pp-cp and cp-np. The bisector returned is always to the - * left of pp-cp-np. - */ -static double -bisect (pointf pp, pointf cp, pointf np) -{ - double ang, theta, phi; - theta = atan2(np.y - cp.y,np.x - cp.x); - phi = atan2(pp.y - cp.y,pp.x - cp.x); - ang = theta - phi; - if (ang > 0) ang -= 2*M_PI; - - return (phi + ang/2.0); -} - -/* mkSegPts: - * Determine polygon points related to 2 segments prv-cur and cur-nxt. - * The points lie on the bisector of the 2 segments, passing through cur, - * and distance HW from cur. The points are stored in p1 and p2. - * If p1 is NULL, we use the normal to cur-nxt. - * If p2 is NULL, we use the normal to prv-cur. - * Assume at least one of prv or nxt is non-NULL. - */ -static void -mkSegPts (segitem_t* prv, segitem_t* cur, segitem_t* nxt, - pointf* p1, pointf* p2) -{ - pointf cp, pp, np; - double theta, delx, dely; - pointf p; - - cp = cur->p; - /* if prv or nxt are NULL, use the one given to create a collinear - * prv or nxt. This could be more efficiently done with special case code, - * but this way is more uniform. - */ - if (prv) { - pp = prv->p; - if (nxt) - np = nxt->p; - else { - np.x = 2*cp.x - pp.x; - np.y = 2*cp.y - pp.y; - } - } - else { - np = nxt->p; - pp.x = 2*cp.x - np.x; - pp.y = 2*cp.y - np.y; - } - theta = bisect(pp,cp,np); - delx = HW*cos(theta); - dely = HW*sin(theta); - p.x = cp.x + delx; - p.y = cp.y + dely; - *p1 = p; - p.x = cp.x - delx; - p.y = cp.y - dely; - *p2 = p; -} - -/* map_output_bspline: - * Construct and output a closed polygon approximating the input - * B-spline bp. We do this by first approximating bp by a sequence - * of line segments. We then use the sequence of segments to determine - * the polygon. - * In cmapx, polygons are limited to 100 points, so we output polygons - * in chunks of 100. - */ -static void -map_output_bspline (bezier* bp, char *url, char *target, char *tooltip) -{ - segitem_t* segl = GNEW(segitem_t); - segitem_t* segp = segl; - segitem_t* segprev; - segitem_t* segnext; - int nc, j, k, cnt; - pointf pts[4]; - pointf pt1[50], pt2[50]; - - MARK_FIRST_SEG(segl); - nc = (bp->size - 1)/3; /* nc is number of bezier curves */ - for (j = 0; j < nc; j++) { - for (k = 0; k < 4; k++) { - pts[k].x = (double)bp->list[3*j + k].x; - pts[k].y = (double)bp->list[3*j + k].y; - } - segp = approx_bezier (pts, segp); - } - - segp = segl; - segprev = 0; - cnt = 0; - while (segp) { - segnext = segp->next; - mkSegPts (segprev, segp, segnext, pt1+cnt, pt2+cnt); - cnt++; - if ((segnext == NULL) || (cnt == 50)) { - map_bspline_poly (cnt, pt1, pt2, url, target, tooltip); - pt1[0] = pt1[cnt-1]; - pt2[0] = pt2[cnt-1]; - cnt = 1; - } - segprev = segp; - segp = segnext; - } - - /* free segl */ - while (segl) { - segp = segl->next; - free (segl); - segl = segp; - } -} - -void map_begin_edge(edge_t* e) -{ - /* strings */ - char *s, *label, *taillabel, *headlabel, *url, *tailurl, *headurl, - *target, *tailtarget, *headtarget, *tooltip, *tailtooltip, *headtooltip, - *m_url = NULL, *m_tailurl = NULL, *m_headurl = NULL, - *m_target = NULL, *m_tailtarget = NULL, *m_headtarget = NULL, - *m_tooltip = NULL, *m_tailtooltip = NULL, *m_headtooltip = NULL; - - textlabel_t *lab = NULL, *tlab = NULL, *hlab = NULL; - pointf p, p1, p2; - bezier bz; - - /* establish correct text for main edge label, URL, tooltip */ - label = NULL; - if ((lab = ED_label(e))) { - if (lab->html) - doHTMLlabel(lab->u.html, lab->p, (void *) e); - label = lab->text; - } - url = NULL; - if (((s = agget(e, "href")) && s[0]) || ((s = agget(e, "URL")) && s[0])) - m_url = url = strdup_and_subst_edge(s, e); - tooltip = label; - if ((s = agget(e, "tooltip")) && s[0]) - m_tooltip = tooltip = strdup_and_subst_edge(s, e); - target = NULL; - if ((s = agget(e, "target")) && s[0]) - m_target = target = strdup_and_subst_edge(s, e); - - /* establish correct text for tail label, URL, tooltip */ - taillabel = label; - if ((tlab = ED_tail_label(e))) { - if (tlab->html) - doHTMLlabel(tlab->u.html, tlab->p, (void *) e); - taillabel = tlab->text; - } - tailurl = url; - if (((s = agget(e, "tailhref")) && s[0]) || ((s = agget(e, "tailURL")) && s[0])) - m_tailurl = tailurl = strdup_and_subst_edge(s, e); - tailtooltip = taillabel; - if ((s = agget(e, "tailtooltip")) && s[0]) - m_tailtooltip = tailtooltip = strdup_and_subst_edge(s, e); - tailtarget = target; - if ((s = agget(e, "tailtarget")) && s[0]) - m_tailtarget = tailtarget = strdup_and_subst_edge(s, e); - - /* establish correct text for head label, URL, tooltip */ - headlabel = label; - if ((hlab = ED_head_label(e))) { - if (hlab->html) - doHTMLlabel(hlab->u.html, hlab->p, (void *) e); - headlabel = hlab->text; - } - headurl = url; - if (((s = agget(e, "headhref")) && s[0]) || ((s = agget(e, "headURL")) && s[0])) - m_headurl = headurl = strdup_and_subst_edge(s, e); - headtooltip = headlabel; - if ((s = agget(e, "headtooltip")) && s[0]) - m_headtooltip = headtooltip = strdup_and_subst_edge(s, e); - headtarget = target; - if ((s = agget(e, "headtarget")) && s[0]) - m_headtarget = headtarget = strdup_and_subst_edge(s, e); - - /* strings are now set - next we map the three labels */ - - if (lab && (url || m_tooltip)) { - /* map a rectangle around the edge label */ - p1.x = lab->p.x - lab->dimen.x / 2; - p1.y = lab->p.y - lab->dimen.y / 2; - p2.x = lab->p.x + lab->dimen.x / 2; - p2.y = lab->p.y + lab->dimen.y / 2; - map_output_rect(p1, p2, url, target, label, tooltip); - } - - if (tlab && (tailurl || m_tailtooltip)) { - /* map a rectangle around the edge taillabel */ - p1.x = tlab->p.x - tlab->dimen.x / 2; - p1.y = tlab->p.y - tlab->dimen.y / 2; - p2.x = tlab->p.x + tlab->dimen.x / 2; - p2.y = tlab->p.y + tlab->dimen.y / 2; - map_output_rect(p1, p2, tailurl, tailtarget, taillabel, tailtooltip); - } - - if (hlab && (headurl || m_headtooltip)) { - /* map a rectangle around the edge headlabel */ - p1.x = hlab->p.x - hlab->dimen.x / 2; - p1.y = hlab->p.y - hlab->dimen.y / 2; - p2.x = hlab->p.x + hlab->dimen.x / 2; - p2.y = hlab->p.y + hlab->dimen.y / 2; - map_output_rect(p1, p2, headurl, headtarget, headlabel, headtooltip); - } - - /* finally we map the two ends of the edge where they touch nodes */ - - /* process intersecion with tail node */ - if (ED_spl(e) && (tailurl || m_tailtooltip)) { - bz = ED_spl(e)->list[0]; - if (bz.sflag) { - /* Arrow at start of splines */ - p.x = bz.sp.x; - p.y = bz.sp.y; - } else { - /* No arrow at start of splines */ - p.x = bz.list[0].x; - p.y = bz.list[0].y; - } - map_output_fuzzy_point(p, tailurl, tailtarget, taillabel, tailtooltip); - } - - /* process intersection with head node */ - if (ED_spl(e) && (headurl || m_headtooltip)) { - bz = ED_spl(e)->list[ED_spl(e)->size - 1]; - if (bz.eflag) { - /* Arrow at end of splines */ - p.x = bz.ep.x; - p.y = bz.ep.y; - } else { - /* No arrow at end of splines */ - p.x = bz.list[bz.size - 1].x; - p.y = bz.list[bz.size - 1].y; - } - map_output_fuzzy_point(p, headurl, headtarget, headlabel, headtooltip); - } - - /* map the edge (spline) for format IMAP or CMAPX */ - - if (ED_spl(e) && (url || m_tooltip) && (Output_lang == IMAP || Output_lang == CMAPX)) - { - int i, ns; - splines *spl; - - spl = ED_spl(e); - ns = spl->size; /* number of splines */ - for (i = 0; i < ns; i++) { - map_output_bspline (spl->list+i, url, target, tooltip); - } - } - - free(m_url); - free(m_target); - free(m_tailtarget); - free(m_headtarget); - free(m_tailurl); - free(m_headurl); - free(m_tooltip); - free(m_tailtooltip); - free(m_headtooltip); -} - -static void map_begin_anchor(char *href, char *tooltip, char *target) -{ -#if NEWANCHORS - fprintf(Output_file, "\n"); -#endif -} - -static void map_polygon(point * A, int n, int filled) -{ -#if NEWANCHORS - int i; - point p; - - fprintf(Output_file, " shape=\"polygon\" coords=\""); - for (i = 0; i < n; i++) { - p = mappt(A[i]); - fprintf(Output_file, "%d,%d,", p.x, p.y); - } - p = mappt(A[0]); - fprintf(Output_file, "%d,%d\"", p.x, p.y); -#endif -} - -static void map_ellipse(point p, int rx, int ry, int filled) -{ -#if NEWANCHORS - fprintf(Output_file, " shape=\"ellipse\""); -#endif -} - - -codegen_t MAP_CodeGen = { - map_reset, - map_begin_job, 0, /* map_end_job */ - map_begin_graph, 0, /* map_end_graph */ - map_begin_page, map_end_page, - 0, /* map_begin_layer */ 0, /* map_end_layer */ - map_begin_cluster, 0, /* map_end_cluster */ - 0, /* map_begin_nodes */ 0, /* map_end_nodes */ - 0, /* map_begin_edges */ 0, /* map_end_edges */ - map_begin_node, 0, /* map_end_node */ - map_begin_edge, 0, /* map_end_edge */ - 0, /* map_begin_context */ 0, /* map_end_context */ - map_begin_anchor, map_end_anchor, - 0, /* map_set_font */ 0, /* map_textpara */ - 0, /* map_set_color */ 0, /* map_set_color */ 0, /* map_set_style */ - map_ellipse, map_polygon, - 0, /* map_bezier */ 0, /* map_polyline */ - 0, /* bezier_has_arrows */ - 0, /* map_comment */ - 0 /* map_usershape */ -}; diff --git a/lib/common/psgen.c b/lib/common/psgen.c deleted file mode 100644 index 2c082ba32..000000000 --- a/lib/common/psgen.c +++ /dev/null @@ -1,707 +0,0 @@ -/* $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 * -**********************************************************/ - -/* - J$: added `pdfmark' URL embedding. PostScript rendered from - dot files with URL attributes will get active PDF links - from Adobe's Distiller. - */ -#define PDFMAX 14400 /* Maximum size of PDF page */ - -#include "render.h" -#include "agxbuf.h" -#include -#include -#if HAVE_SYS_MMAN_H -#include -#endif - -#ifdef HAVE_LIBGD -#include "gd.h" -#endif - -#ifndef MSWIN32 -#include -#endif - -extern void epsf_define(FILE * of); -extern void epsf_emit_body(usershape_t *us, FILE *of); -extern char *ps_string(char *ins, int latin); - -static int N_pages, Cur_page; -/* static point Pages; */ -static box PB; -static box DBB; -static int onetime = TRUE; -static int isLatin1; -static char setupLatin1; -static node_t *Curnode; /* for user shapes */ - -static char *Fill = "fill\n"; -static char *Stroke = "stroke\n"; -static char *Newpath_Moveto = "newpath %d %d moveto\n"; -static char **U_lib; - -typedef struct grcontext_t { - char *pencolor, *fillcolor, *font; - char invis; - double size; -} grcontext_t; - -#define STACKSIZE 8 -static grcontext_t S[STACKSIZE]; -static int SP = 0; - -static void ps_reset(void) -{ - onetime = TRUE; -} - -static void -ps_begin_job(FILE * ofp, graph_t * g, char **lib, char *user, char *info[], - point pages) -{ - /* Pages = pages; */ - U_lib = lib; - /* wrong when drawing more than one than one graph - use (atend) */ - N_pages = pages.x * pages.y; - if (onetime) { - Cur_page = 0; - fprintf(Output_file, "%%!PS-Adobe-2.0\n"); - fprintf(Output_file, "%%%%Creator: %s version %s (%s)\n", - info[0], info[1], info[2]); - fprintf(Output_file, "%%%%For: %s\n", user); - fprintf(Output_file, "%%%%Title: %s\n", g->name); - fprintf(Output_file, "%%%%Pages: (atend)\n"); - if (Show_boxes == NULL) - fprintf(Output_file, "%%%%BoundingBox: (atend)\n"); - fprintf(Output_file, "%%%%EndComments\nsave\n"); - } - - /* remainder is emitted by first begin_graph */ -} - -static void ps_end_job(void) -{ - fprintf(Output_file, "%%%%Trailer\n"); - fprintf(Output_file, "%%%%Pages: %d\n", Cur_page); - if (Show_boxes == NULL) - fprintf(Output_file, "%%%%BoundingBox: %d %d %d %d\n", - DBB.LL.x, DBB.LL.y, DBB.UR.x, DBB.UR.y); - fprintf(Output_file, "end\nrestore\n"); - fprintf(Output_file, "%%%%EOF\n"); - setupLatin1 = FALSE; -} - -static void ps_comment(char *str) -{ - fprintf(Output_file, "%% %s\n", str); -} - -static void ps_begin_graph(GVC_t * gvc, graph_t * g, box bb, point pb) -{ - char *s; - - PB = bb; - if (onetime) { - cat_preamble(gvc->job, U_lib); - epsf_define(Output_file); - if (Show_boxes) { - char* args[2]; - args[0] = Show_boxes[0]; - args[1] = NULL; - cat_libfile(Output_file, NULL, args); - } - - /* Set base URL for relative links (for Distiller >= 3.0) */ - if (((s = agget(g, "href")) && s[0]) - || ((s = agget(g, "URL")) && s[0])) { - fprintf(Output_file, - "[ {Catalog} << /URI << /Base (%s) >> >>\n" - "/PUT pdfmark\n", s); - } - } - - isLatin1 = (GD_charset(g) == CHAR_LATIN1); - if (isLatin1 && !setupLatin1) { - fprintf(Output_file, "setupLatin1\n"); /* as defined in ps header */ - setupLatin1 = TRUE; - } -} - -static void ps_end_graph(void) -{ - onetime = FALSE; -} - -static void -ps_begin_page(graph_t * g, point page, double scale, int rot, point offset) -{ - point sz; - box pbr; - - sz = sub_points(PB.UR,PB.LL); - Cur_page++; - fprintf(Output_file, "%%%%Page: %d %d\n", Cur_page, Cur_page); - - if (rot) { - pbr.LL.x = PB.LL.y; - pbr.LL.y = PB.LL.x; - pbr.UR.x = PB.UR.y; - pbr.UR.y = PB.UR.x; - } - else { - pbr = PB; - } - if (onetime) { - DBB = pbr; - } - else { - EXPANDBB(DBB, pbr); - } - if (Show_boxes == NULL) { - fprintf(Output_file, "%%%%PageBoundingBox: %d %d %d %d\n", - pbr.LL.x, pbr.LL.y, pbr.UR.x, pbr.UR.y); - } - - fprintf(Output_file, "%%%%PageOrientation: %s\n", - (rot ? "Landscape" : "Portrait")); - if (Output_lang == PDF) - fprintf(Output_file, "<< /PageSize [%d %d] >> setpagedevice\n", - pbr.UR.x, pbr.UR.y); - if (Show_boxes == NULL) { - fprintf(Output_file, "gsave\n%d %d %d %d boxprim clip newpath\n", - pbr.LL.x, pbr.LL.y, pbr.UR.x, pbr.UR.y); - } - fprintf(Output_file, "%d %d translate\n", PB.LL.x, PB.LL.y); - if (rot) - fprintf(Output_file, "gsave %d %d translate %d rotate\n", - PB.UR.x - PB.LL.x, 0, rot); - fprintf(Output_file, "%d %d %d beginpage\n", page.x, page.y, N_pages); - if (rot) - fprintf(Output_file, "grestore\n"); - fprintf(Output_file, "%g %g set_scale\n", scale, scale); - fprintf(Output_file, "%d %d translate %d rotate\n", - offset.x, offset.y, rot); - assert(SP == 0); - S[SP].font = S[SP].pencolor = S[SP].fillcolor = ""; - S[SP].size = 0.0; - - /* Define the size of the PS canvas */ - if (Output_lang == PDF) { - if (sz.x > PDFMAX || sz.y > PDFMAX) - agerr(AGWARN, - "canvas size (%d,%d) exceeds PDF limit (%d)\n" - "\t(suggest setting a bounding box size, see dot(1))\n", - sz.x, sz.y, PDFMAX); - fprintf(Output_file, "[ /CropBox [%d %d %d %d] /PAGE pdfmark\n", - pbr.LL.x, pbr.LL.y, pbr.UR.x, pbr.UR.y); - } -} - -static void ps_end_page(void) -{ - if (Show_boxes) - cat_libfile(Output_file, NULL, Show_boxes+1); - - /* the showpage is really a no-op, but at least one PS processor - * out there needs to see this literal token. endpage does the real work. - */ - fprintf(Output_file, "endpage\nshowpage\ngrestore\n"); - fprintf(Output_file, "%%%%PageTrailer\n"); - fprintf(Output_file, "%%%%EndPage: %d\n", Cur_page); - assert(SP == 0); -} - -static void ps_begin_layer(char *s, int n, int Nlayers) -{ - fprintf(Output_file, "%d %d setlayer\n", n, Nlayers); -} - -static void ps_begin_cluster(graph_t * g) -{ - fprintf(Output_file, "%% %s\n", g->name); - - /* Embed information for Distiller to generate hyperlinked PDF */ - map_begin_cluster(g); -} - -static void ps_begin_node(node_t * n) -{ - Curnode = n; - - /* Embed information for Distiller to generate hyperlinked PDF */ - map_begin_node(n); -} - -static void ps_begin_edge(edge_t * e) -{ - /* Embed information for Distiller, so it can generate hyperactive PDF */ - map_begin_edge(e); -} - - -static void ps_begin_context(void) -{ - fprintf(Output_file, "gsave 10 dict begin\n"); - if (SP == STACKSIZE - 1) - agerr(AGWARN, "psgen stk ovfl\n"); - else { - SP++; - S[SP] = S[SP - 1]; - } -} - -static void ps_end_context(void) -{ - if (SP == 0) - agerr(AGWARN, "psgen stk undfl\n"); - else - SP--; - fprintf(Output_file, "end grestore\n"); -} - -static void ps_set_font(char *name, double size) -{ - if (strcmp(S[SP].font, name) || (size != S[SP].size)) { - fprintf(Output_file, "%.2f /%s set_font\n", size, name); - S[SP].font = name; - S[SP].size = size; - } -} - -static void ps_set_color(char *name) -{ - static char *op[] = { "graph", "node", "edge", "sethsb" }; - gvcolor_t color; - - colorxlate(name, &color, HSV_DOUBLE); - fprintf(Output_file, "%.3f %.3f %.3f %scolor\n", - color.u.HSV[0], color.u.HSV[1], color.u.HSV[2], op[Obj]); -} - -static void ps_set_pencolor(char *name) -{ - if (streq(name, "transparent")) - S[SP].pencolor = ""; - else if (strcmp(name, S[SP].pencolor)) { - ps_set_color(name); /* change pen color immediately */ - S[SP].pencolor = name; - } -} - -static void ps_set_fillcolor(char *name) -{ - /* defer changes to fill color to shape */ - if (streq(name, "transparent")) - S[SP].fillcolor = ""; - else - S[SP].fillcolor = name; -} - -static void ps_set_style(char **s) -{ - char *line, *p; - - while ((p = line = *s++)) { - while (*p) - p++; - p++; - while (*p) { - fprintf(Output_file, "%s ", p); - while (*p) - p++; - p++; - } - if (streq(line, "invis")) - S[SP].invis = TRUE; - fprintf(Output_file, "%s\n", line); - } -} - -static void ps_textpara(point p, textpara_t * para) -{ - double adj; - - if (S[SP].invis) - return; - if (*S[SP].pencolor == '\0') - return; - if (para->xshow) { - switch (para->just) { - case 'l': - break; - case 'r': - p.x -= para->width; - break; - default: - case 'n': - p.x -= para->width / 2; - break; - } - fprintf(Output_file, "%d %d moveto\n%s\n[%s]\nxshow\n", - p.x, p.y, ps_string(para->str,isLatin1), para->xshow); - } else { - switch (para->just) { - case 'l': - adj = 0.0; - break; - case 'r': - adj = -1.0; - break; - default: - case 'n': - adj = -0.5; - break; - } - fprintf(Output_file, "%d %d moveto %.1f %.1f %s alignedtext\n", - p.x, p.y, para->width, adj, ps_string(para->str,isLatin1)); - } -} - -static void -ps_bezier(point * A, int n, int arrow_at_start, int arrow_at_end, int filled) -{ - int j; - if (S[SP].invis) - return; - if (filled && *S[SP].fillcolor) { - ps_set_color(S[SP].fillcolor); - fprintf(Output_file, Newpath_Moveto, A[0].x, A[0].y); - for (j = 1; j < n; j += 3) - fprintf(Output_file, "%d %d %d %d %d %d curveto\n", - A[j].x, A[j].y, A[j + 1].x, A[j + 1].y, A[j + 2].x, - A[j + 2].y); - fprintf(Output_file, "closepath\n"); - fprintf(Output_file, Fill); - if (*S[SP].pencolor) - ps_set_color(S[SP].pencolor); - } - if (*S[SP].pencolor == '\0') - return; - if (arrow_at_start || arrow_at_end) - agerr(AGERR, "ps_bezier illegal arrow args\n"); - fprintf(Output_file, Newpath_Moveto, A[0].x, A[0].y); - for (j = 1; j < n; j += 3) - fprintf(Output_file, "%d %d %d %d %d %d curveto\n", - A[j].x, A[j].y, A[j + 1].x, A[j + 1].y, A[j + 2].x, - A[j + 2].y); - fprintf(Output_file, Stroke); -} - -static void ps_polygon(point * A, int n, int filled) -{ - int j; - - if (S[SP].invis) - return; - if (filled && *S[SP].fillcolor) { - ps_set_color(S[SP].fillcolor); - fprintf(Output_file, Newpath_Moveto, A[0].x, A[0].y); - for (j = 1; j < n; j++) - fprintf(Output_file, "%d %d lineto\n", A[j].x, A[j].y); - fprintf(Output_file, "closepath\n"); - fprintf(Output_file, Fill); - if (*S[SP].pencolor) - ps_set_color(S[SP].pencolor); - } - if (*S[SP].pencolor == '\0') - return; - fprintf(Output_file, Newpath_Moveto, A[0].x, A[0].y); - for (j = 1; j < n; j++) - fprintf(Output_file, "%d %d lineto\n", A[j].x, A[j].y); - fprintf(Output_file, "closepath\n"); - fprintf(Output_file, Stroke); -} - -static void ps_ellipse(point p, int rx, int ry, int filled) -{ - if (S[SP].invis) - return; - if (filled && *S[SP].fillcolor) { - ps_set_color(S[SP].fillcolor); - fprintf(Output_file, "%d %d %d %d ellipse_path\n", p.x, p.y, rx, - ry); - fprintf(Output_file, Fill); - if (*S[SP].pencolor) - ps_set_color(S[SP].pencolor); - } - if (*S[SP].pencolor == '\0') - return; - if (!filled || (filled && strcmp(S[SP].fillcolor, S[SP].pencolor))) { - fprintf(Output_file, "%d %d %d %d ellipse_path\n", p.x, p.y, rx, - ry); - fprintf(Output_file, Stroke); - } -} - -static void ps_polyline(point * A, int n) -{ - int j; - - if (S[SP].invis) - return; - if (*S[SP].pencolor == '\0') - return; - fprintf(Output_file, Newpath_Moveto, A[0].x, A[0].y); - for (j = 1; j < n; j++) - fprintf(Output_file, "%d %d lineto\n", A[j].x, A[j].y); - fprintf(Output_file, Stroke); -} - -#ifdef HAVE_LIBGD -static void writePSBitmap (gdImagePtr im, boxf bb) -{ - int X = im->sx, Y = im->sy, x, y, px; - - fprintf(Output_file, "gsave\n"); - - /* this sets the position of the image */ - fprintf(Output_file, "%g %g translate %% lower-left coordinate\n", bb.LL.x, bb.LL.y); - - /* this sets the rendered size to fit the box */ - fprintf(Output_file,"%g %g scale\n", bb.UR.x - bb.LL.x, bb.UR.y - bb.LL.y); - - /* xsize ysize bits-per-sample [matrix] */ - fprintf(Output_file, "%d %d 8 [%d 0 0 %d 0 %d]\n", X, Y, X, -Y, Y); - - fprintf(Output_file, "{<\n"); - if (im->trueColor) { - for (y = 0; y < Y; y++) { - for (x = 0; x < X; x++) { - px = gdImageTrueColorPixel(im, x, y); - fprintf(Output_file, "%02x%02x%02x", - gdTrueColorGetRed(px), - gdTrueColorGetGreen(px), - gdTrueColorGetBlue(px)); - } - fprintf(Output_file, "\n"); - } - } - else { - for (y = 0; y < Y; y++) { - for (x = 0; x < X; x++) { - px = gdImagePalettePixel(im, x, y); - fprintf(Output_file, "%02x%02x%02x", - im->red[px], - im->green[px], - im->blue[px]); - } - fprintf(Output_file, "\n"); - } - } - - fprintf(Output_file, ">}\n"); - fprintf(Output_file, "false 3 colorimage\n"); - - fprintf(Output_file, "grestore\n"); -} -#endif - -static void ps_freeimage_gd (usershape_t *us) -{ -#ifdef HAVE_LIBGD - gdImageDestroy((gdImagePtr)us->data); -#endif -} - -static void ps_freeimage_ps (usershape_t *us) -{ -#if HAVE_SYS_MMAN_H - munmap(us->data, us->datasize); -#else - free(us->data); -#endif -} - -/* ps_usershape: - * Images for postscript are complicated by the old epsf shape, as - * well as user-defined shapes using postscript code. - * If the name is custom, we look for the image stored in the - * current node's shapefile attribute. - * Else we see if name is a user-defined postscript function - * Else we assume name is the name of the image. This occurs when - * the image is part of an html label. - */ -static void ps_usershape(usershape_t *us, boxf b, point *A, int n, bool filled) -{ - int j; - shape_desc *shape; - - assert(us); - assert(us->name); - - if (S[SP].invis) - return; - - if (!us->f) { - if ((shape = (shape_desc*)us->data)) { /* if we found the shape in a library then us->data was set */ - if (filled) { - ps_begin_context(); - ps_set_color(S[SP].fillcolor); - fprintf(Output_file, "[ "); - for (j = 0; j < n; j++) - fprintf(Output_file, "%d %d ", A[j].x, A[j].y); - fprintf(Output_file, "%d %d ", A[0].x, A[0].y); - fprintf(Output_file, "] %d true %s\n", n, us->name); - ps_end_context(); - } - fprintf(Output_file, "[ "); - for (j = 0; j < n; j++) - fprintf(Output_file, "%d %d ", A[j].x, A[j].y); - fprintf(Output_file, "%d %d ", A[0].x, A[0].y); - fprintf(Output_file, "] %d false %s\n", n, us->name); - } - return; - } - - if (us->data) { - if ((us->datafree != ps_freeimage_gd) - && (us->datafree != ps_freeimage_ps)) { - us->datafree(us); /* free incompatible cache data */ - us->data = NULL; - us->datafree = NULL; - us->datasize = 0; - } - } - - if (! us->data) { /* read file into cache */ - int fd = fileno(us->f); - struct stat statbuf; - - fseek(us->f, 0, SEEK_SET); - switch (us->type) { -#ifdef HAVE_LIBGD -#ifdef HAVE_GD_PNG - case FT_PNG: - us->data = (void*)gdImageCreateFromPng(us->f); - us->datafree = ps_freeimage_gd; - break; -#endif -#ifdef HAVE_GD_GIF - case FT_GIF: - us->data = (void*)gdImageCreateFromGif(us->f); - us->datafree = ps_freeimage_gd; - break; -#endif -#ifdef HAVE_GD_JPEG - case FT_JPEG: - us->data = (void*)gdImageCreateFromJpeg(us->f); - us->datafree = ps_freeimage_gd; - break; -#endif -#endif - case FT_PS: - case FT_EPS: - fstat(fd, &statbuf); - us->datasize = statbuf.st_size; -#if HAVE_SYS_MMAN_H - us->data = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); -#else - us->data = malloc(statbuf.st_size); - read(fd, us->data, statbuf.st_size); -#endif - us->datafree = ps_freeimage_ps; - us->must_inline = true; - break; - default: - break; - } - } - - if (us->data) { - boxf bb; - pointf p; - double pw, ph, tw, th; - double scalex, scaley; - int i; - - /* compute bb of polygon */ - P2PF(A[0],p); - bb.LL = bb.UR = p; - for (i = 1; i < n; i++) { - P2PF(A[i],p); - EXPANDBP(bb, p); - } - pw = b.UR.x - b.LL.x; - ph = b.UR.y - b.LL.y; - scalex = pw / (double) (us->w); - scaley = ph / (double) (us->h); - - /* keep aspect ratio fixed by just using the smaller scale */ - if (scalex < scaley) { - tw = us->w * scalex; - th = us->h * scalex; - } else { - tw = us->w * scaley; - th = us->h * scaley; - } - /* if image is smaller than target area then center it */ - if (tw < pw) { - b.LL.x += (pw - tw) / 2.0; - b.UR.x -= (pw - tw) / 2.0; - } - if (th < ph) { - b.LL.y += (ph - th) / 2.0; - b.UR.y -= (ph - th) / 2.0; - } - switch (us->type) { -#ifdef HAVE_LIBGD - case FT_PNG: - case FT_GIF: - case FT_JPEG: - writePSBitmap ((gdImagePtr)us->data, bb); - break; -#endif - case FT_PS: - case FT_EPS: - ps_begin_context(); - fprintf(Output_file, "%d %d translate newpath\n", - ROUND(bb.LL.x - us->x), ROUND(bb.LL.y - us->y)); - if (us->must_inline) - epsf_emit_body(us, Output_file); - else - fprintf(Output_file, "user_shape_%d\n", us->macro_id); - ps_end_context(); - break; - default: - agerr(AGERR, "usershape %s is not supported in PostScript output\n", us->name); - break; - } - } -} - -codegen_t PS_CodeGen = { - ps_reset, - ps_begin_job, ps_end_job, - ps_begin_graph, ps_end_graph, - ps_begin_page, ps_end_page, - ps_begin_layer, 0, /* ps_end_layer */ - ps_begin_cluster, 0, /* ps_end_cluster */ - 0, /* ps_begin_nodes */ 0, /* ps_end_nodes */ - 0, /* ps_begin_edges */ 0, /* ps_end_edges */ - ps_begin_node, 0, /* ps_end_node */ - ps_begin_edge, 0, /* ps_end_edge */ - ps_begin_context, ps_end_context, - 0, /* ps_begin_anchor */ 0, /* ps_end_anchor */ - ps_set_font, ps_textpara, - ps_set_pencolor, ps_set_fillcolor, ps_set_style, - ps_ellipse, ps_polygon, - ps_bezier, ps_polyline, - 0, /* bezier_has_arrows */ - ps_comment, - ps_usershape -}; diff --git a/lib/common/svggen.c b/lib/common/svggen.c deleted file mode 100644 index 671a220ac..000000000 --- a/lib/common/svggen.c +++ /dev/null @@ -1,944 +0,0 @@ -/* $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 * -**********************************************************/ - - -/* this is a rough start at a working SVG driver. -you can get image nodes by setting a node's - [shape=webimage,shapefile="http://www.your.site.com/path/image.png"] -(of course can also be a file: reference if you run locally. -which causes a warning (FIX that) but the back end turns this into -a custom shape. you can also set -[ href = "http://some.place.com/whatever" ] -to get clickable nodes (and edges for that matter). - -some major areas needing work: -0. fonts including embedded font support. is SVG finished in this area? -1. styles, including dotted/dashed lines, also "style function" -passthrough in SVG similar to what we have in postscript. -2. look at what happens in landscape mode, pagination? etc. -3. allow arbitrary user transforms via graph "style" attribute. -4. javascript hooks. particularly, look at this in the context -of SVG animation for dynadag output (n.b. dynadag only in alpha release) -5. image node improvement, e.g. set clip path to node boundary, and -support scaling with fixed aspect ratio (this feature seems to be -broken in the current Adobe SVG plugin for Windows). -6. can we support arbitrary HTML for node contents? -7. encode abstract graph as interleaved XML in some sort of graph XML dialect? -8. accessibility features -9. embed directions about getting plugin, if not present in browser - -Stephen North -north@research.att.com -*/ - -#include -#include "render.h" -#ifdef HAVE_LIBZ -#include "zlib.h" -#endif -#ifdef MSWIN32 -#include -#include -#endif - -/* SVG font modifiers */ -#define REGULAR 0 -#define BOLD 1 -#define ITALIC 2 - -/* SVG 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 */ - -/* SVG bold line constant */ -#define WIDTH_NORMAL 1 -#define WIDTH_BOLD 3 - -#ifdef TESTFAILED -/* sodipodi doesn't understand style sheets */ -#define DEFAULT_STYLE\ -"" - -#define DEFAULT_FILTER \ -"\n" \ -"\n" \ -"\n" \ -"\n" \ -"\n" \ -"\n" \ -"\n" \ -"\n" \ -"\n" \ -"\n" \ -"\n" \ -"\n" \ -"" -#endif - -#define SCALE 1 - -/* SVG dash array */ -static char *sdarray = "5,2"; -/* SVG dot array */ -static char *sdotarray = "1,5"; - -static int N_pages; -/* static point Pages; */ -static int onetime = TRUE; -static int isLatin1; - -static pointf CompScale; -static double FontScale; -static int Rot; - -static point Margin; -static point Viewport; -static pointf GraphFocus; -static double Zoom; - -static node_t *Curnode; - -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; - -static char *op[] = { "graph", "node", "edge", "graph" }; - -#ifdef HAVE_LIBZ -static gzFile Zfile; -#endif - -static void svg_fputs(char *s) -{ - int len; - - len = strlen(s); - switch (Output_lang) { - case SVGZ: -#ifdef HAVE_LIBZ - gzwrite(Zfile, s, (unsigned) len); - break; -#else - agerr(AGERR, "No libz support.\n"); - exit(1); -#endif - case SVG: - fwrite(s, sizeof(char), (unsigned) len, Output_file); - break; - } -} - -/* svg_printf: - * Note that this function is unsafe due to the fixed buffer size. - * It should only be used when the caller is sure the input will not - * overflow the buffer. In particular, it should be avoided for - * input coming from users. Also, if vsnprintf is available, the - * code should check for return values to use it safely. - */ -static void svg_printf(const char *format, ...) -{ - char buf[BUFSIZ]; - va_list argp; - - va_start(argp, format); -#ifdef HAVE_VSNPRINTF - (void) vsnprintf(buf, sizeof(buf), format, argp); -#else - (void) vsprintf(buf, format, argp); -#endif - va_end(argp); - - svg_fputs(buf); -} - -static void svg_reset(void) -{ - onetime = TRUE; -} - -static void init_svg(void) -{ - SP = 0; - cstk[0].pencolor = DEFAULT_COLOR; /* SVG pencolor */ - cstk[0].fillcolor = ""; /* SVG 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 point svgpt(point p) -{ - point rv; - - if (Rot == 0) { - rv.x = (p.x - GraphFocus.x) * CompScale.x + Viewport.x / 2. + Margin.x; - rv.y = -(p.y - GraphFocus.y) * CompScale.y + Viewport.y / 2. + Margin.y; - } else { - rv.x = -(p.y - GraphFocus.y) * CompScale.x + Viewport.x / 2. + Margin.x; - rv.y = -(p.x - GraphFocus.x) * CompScale.y + Viewport.y / 2. + Margin.y; - } - return rv; -} - -static void svgbzptarray(point * A, int n) -{ - int i; - point p; - char *c; - - c = "M"; /* first point */ - for (i = 0; i < n; i++) { - p = svgpt(A[i]); - svg_printf("%s%d,%d", c, p.x, p.y); - if (i == 0) - c = "C"; /* second point */ - else - c = " "; /* remaining points */ - } -} - -static int svg_comparestr(const void *s1, const void *s2) -{ - return strcmp(*(char **) s1, *(char **) s2); -} - -char *svg_resolve_color(char *name, int useKnown) -{ -/* 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); - if (!useKnown || (bsearch(&tok, svg_known_colors, - sizeof(svg_known_colors) / sizeof(char *), - sizeof(char *), svg_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 svg_font(context_t * cp) -{ - char *color, buf[BUFSIZ]; - int needstyle = 0; - - strcpy(buf, " style=\""); - if (strcasecmp(cp->fontfam, DEFAULT_FONTNAME)) { - sprintf(buf + strlen(buf), "font-family:%s;", cp->fontfam); - needstyle++; - } - if (cp->fontsz != DEFAULT_FONTSIZE) { - sprintf(buf + strlen(buf), "font-size:%.2fpt;", cp->fontsz * FontScale); - needstyle++; - } - color = svg_resolve_color(cp->pencolor, 1); - if ((strcasecmp(color, "black"))) { - sprintf(buf + strlen(buf), "fill:%s;", color); - needstyle++; - } - if (needstyle) { - strcat(buf, "\""); - svg_fputs(buf); - } -} - - -static void svg_grstyle(context_t * cp, int filled) -{ - svg_fputs(" style=\""); - if (filled) - svg_printf("fill:%s;", svg_resolve_color(cp->fillcolor, 1)); - else - svg_fputs("fill:none;"); - svg_printf("stroke:%s;", svg_resolve_color(cp->pencolor, 1)); - if (cp->penwidth != WIDTH_NORMAL) - svg_printf("stroke-width:%d;", cp->penwidth); - if (cp->pen == P_DASHED) { - svg_printf("stroke-dasharray:%s;", sdarray); - } else if (cp->pen == P_DOTTED) { - svg_printf("stroke-dasharray:%s;", sdotarray); - } - svg_fputs("\""); -} - -/* xml_namestring: - * Return xml_string applied to input. - * If input is Latin1, first translate to UTF8 - */ -static char* -xml_namestring (char* str) -{ - if (isLatin1) { - char* s = latin1ToUTF8 (str); - str = xml_string(s); - free (s); - } - else - str = xml_string(str); - return str; -} - -/* svg_name_fputs: - * Do fputs on input. - * If input is Latin1, first translate to UTF8. - */ -static void -svg_name_fputs (char* str) -{ - if (isLatin1) { - char* s = latin1ToUTF8 (str); - svg_fputs(s); - free (s); - } - else - svg_fputs(str); -} - -static void svg_comment(char *str) -{ - - svg_fputs("\n"); -} - -/* isAscii: - * Return true if all bytes in string are ascii. - */ -static int isAscii (char* s) -{ - int c; - - while ((c = *s++) && isascii(c)) ; - return (c == '\0'); -} - -static void -svg_begin_job(FILE * ofp, graph_t * g, char **lib, char *user, - char *info[], point pages) -{ - char *s; -#if HAVE_LIBZ - int fd; -#endif - - switch (Output_lang) { - case SVGZ: -#if HAVE_LIBZ - fd = dup(fileno(Output_file)); /* open dup so can gzclose - independent of FILE close */ -#ifdef HAVE_SETMODE -#ifdef O_BINARY - /* - * Windows will do \n -> \r\n translations on - * stdout unless told otherwise. - */ - setmode(fd, O_BINARY); -#endif -#endif - - Zfile = gzdopen(fd, "wb"); - if (!Zfile) { - agerr(AGERR, "Error opening compressed output file\n"); - exit(1); - } - break; -#else - agerr(AGERR, "No libz support.\n"); - exit(1); -#endif - case SVG: - break; - } - -/* Pages = pages; */ - N_pages = pages.x * pages.y; - svg_fputs - ("\n"); - if ((s = agget(g, "stylesheet")) && s[0]) { - svg_fputs("\n"); - } - svg_fputs("\n]"); - svg_fputs(">\n\n"); - } - else - svg_fputs(") -->\n"); -} - -static void svg_begin_graph(GVC_t * gvc, graph_t * g, box bb, point pb) -{ - Viewport.x = gvc->job->width; - Viewport.y = gvc->job->height; - Margin.x = ROUND(gvc->job->margin.x * gvc->job->dpi.x / POINTS_PER_INCH); - Margin.y = ROUND(gvc->job->margin.y * gvc->job->dpi.y / POINTS_PER_INCH); - - Zoom = gvc->job->zoom; - GraphFocus = gvc->job->focus; - - CompScale.x = Zoom * gvc->job->dpi.x / POINTS_PER_INCH; - CompScale.y = Zoom * gvc->job->dpi.y / POINTS_PER_INCH; - FontScale = CompScale.y * 0.72; - - if (onetime) { - init_svg(); - onetime = FALSE; - } - isLatin1 = (GD_charset(g) == CHAR_LATIN1); - svg_fputs("\n", N_pages); - if (ROUND(gvc->job->dpi.x) == POINTS_PER_INCH && ROUND(gvc->job->dpi.y) == POINTS_PER_INCH) { - svg_printf("job->dpi.x * (Viewport.x + Margin.x * 2) / POINTS_PER_INCH), - ROUND(gvc->job->dpi.y * (Viewport.y + Margin.y * 2) / POINTS_PER_INCH)); - } - /* establish absolute units in points */ - svg_printf(" viewBox = \"%d %d %d %d\"\n", Margin.x, Margin.y, Viewport.x, Viewport.y); - /* namespace of svg */ - svg_fputs(" xmlns=\"http://www.w3.org/2000/svg\""); - /* namespace of xlink */ - svg_fputs(" xmlns:xlink=\"http://www.w3.org/1999/xlink\""); - svg_fputs(">\n"); -} - -static void svg_end_graph(void) -{ - svg_fputs("\n"); - switch (Output_lang) { - case SVGZ: -#ifdef HAVE_LIBZ - gzclose(Zfile); - break; -#else - agerr(AGERR, "No libz support\n"); - exit(1); -#endif - case SVG: - break; - } -} - -static void -svg_begin_page(graph_t * g, point page, double scale, int rot, - point offset) -{ - Rot = rot; - -#if 0 -fprintf(stderr,"Zoom=%g CompScale=%g,%f\n", Zoom, CompScale.x, CompScale.y); -fprintf(stderr,"font-size=%g Zoom=%g\n", cstk[0].fontsz, Zoom); -#endif - - /* its really just a page of the graph, but its still a graph, - * and it is the entire graph if we're not currently paging */ - svg_printf("\n", cstk[0].fontsz * FontScale); - svg_fputs(""); - svg_fputs(xml_namestring(g->name)); - svg_fputs("\n"); -} - -static void svg_end_page(void) -{ - svg_fputs("\n"); -} - -static void svg_begin_layer(char *layerName, int n, int nLayers) -{ - /* svg_printf("\n", xml_string(layerName)); */ - svg_fputs("\n"); -} - -static void svg_end_layer(void) -{ - svg_fputs("\n"); -} - -static void svg_begin_cluster(graph_t * g) -{ - svg_printf("", op[Obj], - g->meta_node->id); - svg_fputs(""); - svg_fputs(xml_namestring(g->name)); - svg_fputs("\n"); -} - -static void svg_end_cluster(void) -{ - svg_fputs("\n"); -} - -static void svg_begin_node(node_t * n) -{ - Curnode = n; - svg_printf("", op[Obj], n->id); - svg_fputs(""); - svg_fputs(xml_namestring(n->name)); - svg_fputs("\n"); -} - -static void svg_end_node(void) -{ - svg_fputs("\n"); -} - -static void svg_begin_edge(edge_t * e) -{ - char *edgeop; - - svg_printf("", op[Obj], e->id); - if (e->tail->graph->root->kind & AGFLAG_DIRECTED) - edgeop = "->"; - else - edgeop = "--"; - svg_fputs(""); - svg_fputs(xml_namestring(e->tail->name)); - svg_fputs(edgeop); - /* can't do this in single svg_printf because - * xml_string's buffer gets reused. */ - svg_fputs(xml_namestring(e->head->name)); - svg_fputs("\n"); -} - -static void svg_end_edge(void) -{ - svg_fputs("\n"); -} - -static void svg_begin_context(void) -{ - assert(SP + 1 < MAXNEST); - cstk[SP + 1] = cstk[SP]; - SP++; -} - -static void svg_begin_anchor(char *href, char *tooltip, char *target) -{ - svg_fputs("\n"); -} - -static void svg_end_anchor(void) -{ - svg_fputs("\n"); -} - -static void svg_end_context(void) -{ - int psp = SP - 1; - assert(SP > 0); - /*free(cstk[psp].fontfam); */ - SP = psp; -} - -static void svg_set_font(char *name, double size) -{ - char *p; -#if 0 -/* see below */ - char *q; -#endif - context_t *cp; - - cp = &(cstk[SP]); - cp->font_was_set = TRUE; - cp->fontsz = size; - p = strdup(name); -#if 0 -/* - * this doesn't work as originally intended - * fontnames can be things like: "Times-Roman" - * where "Roman" is not an ITALIC or BOLD indicator. - */ - if ((q = strchr(p, '-'))) { - *q++ = 0; - if (strcasecmp(q, "italic") == 0) - cp->fontopt = ITALIC; - else if (strcasecmp(q, "bold") == 0) - cp->fontopt = BOLD; - } - cp->fontfam = p; -#else - cp->fontfam = p; -#endif -} - -static void svg_set_pencolor(char *name) -{ - cstk[SP].pencolor = name; -} - -static void svg_set_fillcolor(char *name) -{ - cstk[SP].fillcolor = name; -} - -static void svg_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 { - agerr(AGERR, - "svg_set_style: unsupported style %s - ignoring\n", - line); - } - cp->style_was_set = TRUE; - } - /* if (cp->style_was_set) svg_style(cp); */ -} - -static void svg_textpara(point p, textpara_t * para) -{ - char *anchor, *string; - point mp; - context_t *cp; - - string = xml_string(para->str); - if (!string[0]) - return; - - cp = &(cstk[SP]); - if (cp->pen == P_NONE) { - /* its invisible, don't draw */ - return; - } -#if 0 -/* adobe svg doesn't like the dx propert */ - if (para->xshow) { - anchor = "start"; - switch (para->just) { - case 'l': - break; - case 'r': - p.x -= para->width; - break; - default: - case 'n': - p.x -= para->width / 2; - break; - } - } else { -#endif - switch (para->just) { - case 'l': - anchor = "start"; - break; - case 'r': - anchor = "end"; - break; - default: - case 'n': - anchor = "middle"; - break; - } -#if 0 -/* adobe svg doesn't like the dx propert */ - } -#endif - mp = svgpt(p); - - svg_printf("xshow) { - svg_fputs("\" dx=\""); - svg_fputs(para->xshow); - } -#endif - svg_fputs(">"); - svg_fputs(string); - svg_fputs("\n"); -} - -static void svg_ellipse(point p, int rx, int ry, int filled) -{ - point mp; - - if (cstk[SP].pen == P_NONE) { - /* its invisible, don't draw */ - return; - } - mp.x = p.x; - mp.y = p.y; - mp = svgpt(mp); - svg_fputs("\n", mp.x, mp.y); -} - -static void -svg_bezier(point * A, int n, int arrow_at_start, int arrow_at_end, int filled) -{ - if (cstk[SP].pen == P_NONE) { - /* its invisible, don't draw */ - return; - } - svg_fputs("\n"); -} - -static void svg_polygon(point * A, int n, int filled) -{ - int i; - point p; - - if (cstk[SP].pen == P_NONE) { - /* its invisible, don't draw */ - return; - } - svg_fputs("\n"); -} - -static void svg_polyline(point * A, int n) -{ - int i; - point p; - - if (cstk[SP].pen == P_NONE) { - /* its invisible, don't draw */ - return; - } - svg_fputs("\n"); -} - -static void svg_usershape(usershape_t *us, boxf b, point *A, int n, bool filled) -{ - char *imagefile; - - if (cstk[SP].pen == P_NONE) { - /* its invisible, don't draw */ - return; - } - if (us->f) - imagefile = us->name; - else - imagefile = NULL; - if (! imagefile) { - svg_polygon(A, n, filled); - return; - } - - svg_fputs("\n"); -} - -codegen_t SVG_CodeGen = { - svg_reset, - svg_begin_job, 0, /* svg_end_job */ - svg_begin_graph, svg_end_graph, - svg_begin_page, svg_end_page, - svg_begin_layer, svg_end_layer, - svg_begin_cluster, svg_end_cluster, - 0, /* svg_begin_nodes */ 0, /* svg_end_nodes */ - 0, /* svg_begin_edges */ 0, /* svg_end_edges */ - svg_begin_node, svg_end_node, - svg_begin_edge, svg_end_edge, - svg_begin_context, svg_end_context, - svg_begin_anchor, svg_end_anchor, - svg_set_font, svg_textpara, - svg_set_pencolor, svg_set_fillcolor, svg_set_style, - svg_ellipse, svg_polygon, - svg_bezier, svg_polyline, - 0, /* bezier_has_arrows */ - svg_comment, - svg_usershape -}; diff --git a/lib/common/vrmlgen.c b/lib/common/vrmlgen.c deleted file mode 100644 index 789413f07..000000000 --- a/lib/common/vrmlgen.c +++ /dev/null @@ -1,1052 +0,0 @@ -/* $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 * -**********************************************************/ - - -#include "render.h" -#include "gd.h" -#include "pathutil.h" - - -extern char *get_ttf_fontpath(char *fontreq, int warn); - -#ifdef HAVE_GD_PNG - -#ifndef MAXFLOAT -#define MAXFLOAT 10000000. -#endif - -#define NONE 0 -#define NODE 1 -#define EDGE 2 -#define CLST 3 - -#define BEZIERSUBDIVISION 10 - -/* font modifiers */ -#define REGULAR 0 -#define BOLD 1 -#define ITALIC 2 - -/* 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 */ - -/* bold line constant */ -#define WIDTH_NORMAL 1 -#define WIDTH_BOLD 3 - -typedef struct { - unsigned char r, g, b; -} Color; - - -/* static int N_pages; */ -/* static point Pages; */ -static double Scale; -static int Rot; -static box BB; -static double MinZ; -/* static int onetime = TRUE; */ -static int Saw_skycolor; - -static gdImagePtr im; -static FILE *PNGfile; -static node_t *Curnode; -static edge_t *Curedge; -static int IsSegment; /* set true if edge is line segment */ -static double CylHt; /* height of cylinder part of edge */ -static double EdgeLen; /* length between centers of endpoints */ -static double HeadHt, TailHt; /* height of arrows */ -static double Fstz, Sndz; /* z values of tail and head points */ - -typedef struct context_t { - unsigned char pencolor_ix, fillcolor_ix; - char *pencolor, *fillcolor; - char *fontfam, fontopt, font_was_set; - double r, g, b; /* fill color values */ - char pen, fill, penwidth; - double fontsz; -} context_t; - -#define MAXNEST 4 -static context_t cstk[MAXNEST]; -static int SP; - -static char *nodeURL(node_t * n, char *buf) -{ - sprintf(buf, "node%d.png", n->id); - return buf; -} - -/* gdirname: - * Returns directory pathname prefix - * Code adapted from dgk - */ -static char *gdirname(char *pathname) -{ - char *last; - - /* go to end of path */ - for (last = pathname; *last; last++); - /* back over trailing '/' */ - while (last > pathname && *--last == '/'); - /* back over non-slash chars */ - for (; last > pathname && *last != '/'; last--); - if (last == pathname) { - /* all '/' or "" */ - if (*pathname != '/') - *last = '.'; - /* preserve // */ - else if (pathname[1] == '/') - last++; - } else { - /* back over trailing '/' */ - for (; *last == '/' && last > pathname; last--); - /* preserve // */ - if (last == pathname && *pathname == '/' && pathname[1] == '/') - last++; - } - last++; - *last = '\0'; - - return pathname; -} - -static char *nodefilename(node_t * n, char *buf) -{ - static char *dir; - static char disposable[1024]; - char junkbuf[1024]; - - if (dir == 0) { - if (Output_file_name) - dir = gdirname(strcpy(disposable, Output_file_name)); - else - dir = "."; - } - sprintf(buf, "%s/%s", dir, nodeURL(n, junkbuf)); - return buf; -} - -static FILE *nodefile(node_t * n) -{ - FILE *rv; - char buf[1024]; - - rv = fopen(nodefilename(n, buf), "wb"); - return rv; -} - -static unsigned char vrml_resolve_color(char *name) -{ - gvcolor_t color; - - if (!(strcmp(name, "transparent"))) { - /* special case for "transparent" color */ - return gdImageColorResolve(im, 255, 255, 254); - } else { - colorxlate(name, &color, RGBA_BYTE); - return gdImageColorResolve(im, - color.u.rgba[0], color.u.rgba[1], - color.u.rgba[2]); - } -} - -static void vrml_set_pencolor(char *name) -{ - cstk[SP].pencolor = name; -} - -static void vrml_set_fillcolor(char *name) -{ - gvcolor_t color; - cstk[SP].fillcolor = name; - colorxlate(name, &color, RGBA_BYTE); - cstk[SP].r = (double) color.u.rgba[0] / 255.0; - cstk[SP].g = (double) color.u.rgba[1] / 255.0; - cstk[SP].b = (double) color.u.rgba[2] / 255.0; -} - -static void init_png(gdImagePtr im) -{ - int transparent; - - if ((transparent = gdImageGetTransparent(im)) == -1) { - transparent = gdImageColorResolve(im, 255, 255, 254); - gdImageColorTransparent(im, transparent); - } -} - -static pointf vrml_node_point(point p) -{ - pointf rv; - - /* make mp relative to PNG canvas */ - if (Rot == 0) { - rv.x = (p.x - ND_coord_i(Curnode).x + ND_lw_i(Curnode)) * Scale; - rv.y = - (ND_coord_i(Curnode).y - p.y + ND_ht_i(Curnode) / 2) * Scale; - } else { - rv.x = (p.y - ND_coord_i(Curnode).y + ND_lw_i(Curnode)) * Scale; - rv.y = - (ND_coord_i(Curnode).x - p.x + ND_ht_i(Curnode) / 2) * Scale; - } - return rv; -} - -static void vrml_font(context_t * cp) -{ -/* FIX - char *fw, *fa; - - fw = fa = "Regular"; - switch (cp->fontopt) { - case BOLD: - fw = "Bold"; - break; - case ITALIC: - fa = "Italic"; - break; - } -*/ -} - -/* warmed over VRML code starts here */ - -static void vrml_begin_job(FILE * ofp, graph_t * g, char **lib, char *user, - char *info[], point pages) -{ - fprintf(Output_file, "#VRML V2.0 utf8\n"); -} - -static void vrml_begin_graph(GVC_t * gvc, graph_t * g, box bb, point pb) -{ - g = g; - - Saw_skycolor = FALSE; - MinZ = MAXDOUBLE; - BB = bb; - fprintf(Output_file, "Group { children [\n"); - fprintf(Output_file, " Transform {\n"); - fprintf(Output_file, " scale %.3f %.3f %.3f\n", - .0278, .0278, .0278); - fprintf(Output_file, " children [\n"); - - SP = 0; - cstk[0].fillcolor = "white"; - cstk[0].fontfam = "times"; /* font family name */ - 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 void vrml_end_graph(void) -{ - double d, z; - box bb = BB; - - d = MAX(bb.UR.x - bb.LL.x,bb.UR.y - bb.LL.y); - /* Roughly fill 3/4 view assuming FOV angle of PI/4. - * Small graphs and non-square aspect ratios will upset this. - */ - z = (0.6667*d)/tan(PI/8.0) + MinZ; /* fill 3/4 of view */ - - if (!Saw_skycolor) - fprintf(Output_file, " Background { skyColor 1 1 1 }\n"); - fprintf(Output_file, " ] }\n"); - fprintf(Output_file, " Viewpoint {position %.3f %.3f %.3f}\n", - .0278 * (bb.UR.x + bb.LL.x) / 2.0, - .0278 * (bb.UR.y + bb.LL.y) / 2.0, .0278 * z); - fprintf(Output_file, "] }\n"); -} - -static void vrml_begin_page(graph_t * g, point page, double scale, int rot, - point offset) -{ -#if 0 /* scale not used */ - Scale = scale * (double) DEFAULT_DPI / POINTS_PER_INCH; -#else - Scale = (double) DEFAULT_DPI / POINTS_PER_INCH; -#endif - Rot = rot; -} - -static void vrml_begin_node(node_t * n) -{ - int width, height; - double z; - - fprintf(Output_file, "# node %s\n", n->name); - z = late_double(n, N_z, 0.0, -MAXFLOAT); - if (z < MinZ) MinZ = z; - if (shapeOf(n) != SH_POINT) { - PNGfile = nodefile(n); - width = (ND_lw_i(n) + ND_rw_i(n)) * Scale + 3; - height = (ND_ht_i(n)) * Scale + 3; - im = gdImageCreate(width, height); - init_png(im); - } - Curnode = n; -} - -static void vrml_end_node(void) -{ - if (shapeOf(Curnode) != SH_POINT) { - gdImagePng(im, PNGfile); - gdImageDestroy(im); - im = 0; - fclose(PNGfile); - } -} - -static void vrml_begin_edge(edge_t * e) -{ - Curedge = e; - IsSegment = 0; - fprintf(Output_file, "# edge %s -> %s\n", e->tail->name, e->head->name); - fprintf(Output_file, " Group { children [\n"); -} - -static void -finishSegment (void) -{ - point p0 = ND_coord_i(Curedge->tail); - point p1 = ND_coord_i(Curedge->head); - double o_x, o_y, o_z; - double x, y, y0, z, theta; - - o_x = ((double)(p0.x + p1.x))/2; - o_y = ((double)(p0.y + p1.y))/2; - o_z = (Fstz + Sndz)/2; - /* Compute rotation */ - /* Pick end point with highest y */ - if (p0.y > p1.y) { - x = p0.x; - y = p0.y; - z = Fstz; - } - else { - x = p1.x; - y = p1.y; - z = Sndz; - } - /* Translate center to the origin */ - x -= o_x; - y -= o_y; - z -= o_z; - if (p0.y > p1.y) - theta = acos(2*y/EdgeLen) + PI; - else - theta = acos(2*y/EdgeLen); - if (!x && !z) /* parallel to y-axis */ - x = 1; - - y0 = (HeadHt-TailHt)/2.0; - fprintf(Output_file, " ]\n"); - fprintf(Output_file, " center 0 %f 0\n", y0); - fprintf(Output_file, " rotation %f 0 %f %f\n", -z, x, -theta); - fprintf(Output_file, " translation %.3f %.3f %.3f\n", o_x, o_y - y0, o_z); - fprintf(Output_file, " }\n"); -} - -static void vrml_end_edge(void) -{ - if (IsSegment) { - finishSegment(); - } - fprintf(Output_file, "] }\n"); -} - -static void vrml_begin_context(void) -{ - assert(SP + 1 < MAXNEST); - cstk[SP + 1] = cstk[SP]; - SP++; -} - -static void vrml_end_context(void) -{ - int psp = SP - 1; - assert(SP > 0); - if (cstk[SP].font_was_set) - vrml_font(&(cstk[psp])); - /* free(cstk[psp].fontfam); */ - SP = psp; -} - -static void vrml_set_font(char *name, double size) -{ - char *p, *q; - context_t *cp; - - cp = &(cstk[SP]); - cp->font_was_set = TRUE; - cp->fontsz = size; - p = strdup(name); - if ((q = strchr(p, '-'))) { - *q++ = 0; - if (strcasecmp(q, "italic") == 0) - cp->fontopt = ITALIC; - else if (strcasecmp(q, "bold") == 0) - cp->fontopt = BOLD; - } - cp->fontfam = p; - vrml_font(&cstk[SP]); -} - -static void vrml_set_style(char **s) -{ - char *line; - context_t *cp; - - cp = &(cstk[SP]); - while ((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, "bold")) - cp->penwidth = WIDTH_BOLD; - else if (streq(line, "invis")) - cp->pen = P_NONE; - else if (streq(line, "filled")) - cp->fill = P_SOLID; - else if (streq(line, "unfilled")) - cp->fill = P_NONE; - else { - agerr(AGWARN, - "vrml_set_style: unsupported style %s - ignoring\n", - line); - } - } -} - -static void vrml_textpara(point p, textpara_t * para) -{ - char *fontlist, *err; - pointf mp; - int brect[8]; - extern gdFontPtr gdFontSmall; - - if (Obj != NODE) - return; - cstk[SP].pencolor_ix = vrml_resolve_color(cstk[SP].pencolor); - fontlist = (char*)(para->layout); /* FIXME - kluge */ - - switch (para->just) { - case 'l': - break; - case 'r': - p.x -= para->width; - break; - default: - case 'n': - p.x -= para->width / 2; - break; - } -/* p.y += cstk[SP].fontsz*2/3; */ - - mp = vrml_node_point(p); - - err = gdImageStringFT(im, brect, cstk[SP].pencolor_ix, fontlist, - cstk[SP].fontsz, (Rot ? 90.0 : 0.0) * PI / 180.0, - ROUND(mp.x), ROUND(mp.y), para->str); - if (err) { - /* revert to builtin fonts */ - gdImageString(im, gdFontSmall, ROUND(mp.x), ROUND(mp.y), - (unsigned char *) para->str, cstk[SP].pencolor_ix); - } -} - -/* interpolate_zcoord: - * Given 2 points in 3D p = (fst.x,fst.y,fstz) and q = (snd.x, snd.y, sndz), - * and a point p1 in the xy plane lying on the line segment connecting - * the projections of the p and q, find the z coordinate of p1 when it - * is projected up onto the segment (p,q) in 3-space. - * - * Why the special case for ranks? Is the arithmetic really correct? - */ -static double -interpolate_zcoord(pointf p1, point fst, double fstz, point snd, double sndz) -{ - double len, d, rv; - - if (fstz == sndz) - return fstz; - if (ND_rank(Curedge->tail) != ND_rank(Curedge->head)) { - if (snd.y == fst.y) - rv = (fstz + sndz) / 2.0; - else - rv = fstz + (sndz - fstz) * (p1.y - fst.y) / (snd.y - fst.y); - } - else { - len = DIST(fst, snd); - d = DIST(p1, fst)/len; - rv = fstz + d*(sndz - fstz); - } - return rv; -} - -/* collinear: - * Return true if the 3 points starting at A are collinear. - */ -static int -collinear (point * A) -{ - Ppoint_t a, b, c; - double w; - - a.x = A->x; - a.y = A->y; - A++; - b.x = A->x; - b.y = A->y; - A++; - c.x = A->x; - c.y = A->y; - - w = wind(a,b,c); - return (fabs(w) <= 1); -} - -/* straight: - * Return true if bezier points are collinear - * At present, just check with 4 points, the common case. - */ -static int -straight (point * A, int n) -{ - if (n != 4) return 0; - return (collinear(A) && collinear(A+1)); -} - -static void -doSegment (point* A, point p0, double z0, point p1, double z1) -{ - double d1, d0; - double delx, dely, delz; - - delx = p0.x - p1.x; - dely = p0.y - p1.y; - delz = z0 - z1; - EdgeLen = sqrt(delx*delx + dely*dely + delz*delz); - d0 = DIST(A[0],p0); - d1 = DIST(A[3],p1); - CylHt = EdgeLen - d0 - d1; - TailHt = HeadHt = 0; - - IsSegment = 1; - fprintf(Output_file, "Transform {\n"); - fprintf(Output_file, " children [\n"); - fprintf(Output_file, " Shape {\n"); - fprintf(Output_file, " geometry Cylinder {\n"); - fprintf(Output_file, " bottom FALSE top FALSE\n"); - fprintf(Output_file, " height %f radius %d }\n", CylHt, cstk[SP].penwidth); - fprintf(Output_file, " appearance Appearance {\n"); - fprintf(Output_file, " material Material {\n"); - fprintf(Output_file, " ambientIntensity 0.33\n"); - fprintf(Output_file, " diffuseColor %f %f %f\n", - cstk[SP].r,cstk[SP].g,cstk[SP].b); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " }\n"); -} - -static void -vrml_bezier(point * A, int n, int arrow_at_start, int arrow_at_end, int filled) -{ - pointf p1, V[4]; - int i, j, step; - double fstz, sndz; - context_t *cp; - - assert(Obj == EDGE); - - cp = &(cstk[SP]); - if (cp->pen == P_NONE) - return; - fstz = Fstz = late_double(Curedge->tail, N_z, 0.0, -1000.0); - sndz = Sndz = late_double(Curedge->head, N_z, 0.0, -MAXFLOAT); - if (straight(A,n)) { - doSegment (A, ND_coord_i(Curedge->tail),Fstz,ND_coord_i(Curedge->head),Sndz); - return; - } - - fprintf(Output_file, "Shape { geometry Extrusion {\n"); - fprintf(Output_file, " spine ["); - V[3].x = A[0].x; - V[3].y = A[0].y; - 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 = 0; step <= BEZIERSUBDIVISION; step++) { - p1 = Bezier(V, 3, (double) step / BEZIERSUBDIVISION, NULL, - NULL); - fprintf(Output_file, " %.3f %.3f %.3f", p1.x, p1.y, - interpolate_zcoord(p1, A[0], fstz, A[n - 1], sndz)); - } - } - fprintf(Output_file, " ]\n"); - fprintf(Output_file, " crossSection [ %d %d, %d %d, %d %d, %d %d ]\n", - (cp->penwidth), (cp->penwidth), -(cp->penwidth), - (cp->penwidth), -(cp->penwidth), -(cp->penwidth), - (cp->penwidth), -(cp->penwidth)); - fprintf(Output_file, "}\n"); - fprintf(Output_file, " appearance DEF E%d Appearance {\n", - Curedge->id); - fprintf(Output_file, " material Material {\n"); - fprintf(Output_file, " ambientIntensity 0.33\n"); - fprintf(Output_file, " diffuseColor %.3f %.3f %.3f\n", - cstk[SP].r, cstk[SP].g, cstk[SP].b); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " }\n"); - fprintf(Output_file, "}\n"); -} - -/* doArrowhead: - * If edge is straight, we attach a cone to the edge as a group. - */ -static void -doArrowhead (point* A) -{ - double rad, ht, y; - pointf p0; /* center of triangle base */ - point tp,hp; - - p0.x = (A[0].x + A[2].x)/2.0; - p0.y = (A[0].y + A[2].y)/2.0; - rad = DIST(A[0],A[2])/2.0; - ht = DIST(p0,A[1]); - - y = (CylHt + ht)/2.0; - - tp = ND_coord_i(Curedge->tail); - hp = ND_coord_i(Curedge->head); - fprintf(Output_file, "Transform {\n"); - if (DIST2(A[1], tp) < DIST2(A[1], hp)) { - TailHt = ht; - fprintf(Output_file, " translation 0 -%.3f 0\n", y); - fprintf(Output_file, " rotation 0 0 1 %.3f\n", PI); - } - else { - HeadHt = ht; - fprintf(Output_file, " translation 0 %.3f 0\n", y); - } - fprintf(Output_file, " children [\n"); - fprintf(Output_file, " Shape {\n"); - fprintf(Output_file, " geometry Cone {bottomRadius %.3f height %.3f }\n", - rad, ht); - fprintf(Output_file, " appearance Appearance {\n"); - fprintf(Output_file, " material Material {\n"); - fprintf(Output_file, " ambientIntensity 0.33\n"); - fprintf(Output_file, " diffuseColor %f %f %f\n", cstk[SP].r,cstk[SP].g,cstk[SP].b); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " ]\n"); - fprintf(Output_file, "}\n"); -} - -static void vrml_polygon(point * A, int n, int filled) -{ - pointf p, mp; - int i; - gdPoint *points; - int style[20]; - int pen, width; - gdImagePtr brush = NULL; - double theta, z; - node_t *endp; - char somebuf[1024]; - - switch (Obj) { - case NONE: /* GRAPH */ - fprintf(Output_file, " Background { skyColor %.3f %.3f %.3f }\n", - cstk[SP].r, cstk[SP].g, cstk[SP].b); - Saw_skycolor = TRUE; - break; - - case NODE: - - if (cstk[SP].pen != P_NONE) { - cstk[SP].pencolor_ix = vrml_resolve_color(cstk[SP].pencolor); - cstk[SP].fillcolor_ix = vrml_resolve_color(cstk[SP].fillcolor); - if (cstk[SP].pen == P_DASHED) { - for (i = 0; i < 10; i++) - style[i] = cstk[SP].pencolor_ix; - for (; i < 20; i++) - style[i] = gdTransparent; - gdImageSetStyle(im, style, 20); - pen = gdStyled; - } else if (cstk[SP].pen == P_DOTTED) { - for (i = 0; i < 2; i++) - style[i] = cstk[SP].pencolor_ix; - for (; i < 12; i++) - style[i] = gdTransparent; - gdImageSetStyle(im, style, 12); - pen = gdStyled; - } else { - pen = cstk[SP].pencolor_ix; - } - if (cstk[SP].penwidth != WIDTH_NORMAL) { - width = cstk[SP].penwidth; - brush = gdImageCreate(width, width); - gdImagePaletteCopy(brush, im); - gdImageFilledRectangle(brush, - 0, 0, width - 1, width - 1, - cstk[SP].pencolor_ix); - gdImageSetBrush(im, brush); - if (pen == gdStyled) - pen = gdStyledBrushed; - else - pen = gdBrushed; - } - points = N_GNEW(n, gdPoint); - for (i = 0; i < n; i++) { - mp = vrml_node_point(A[i]); - points[i].x = ROUND(mp.x); - points[i].y = ROUND(mp.y); - } - if (filled) - gdImageFilledPolygon(im, points, n, cstk[SP].fillcolor_ix); - gdImagePolygon(im, points, n, pen); - free(points); - if (brush) - gdImageDestroy(brush); - } - - z = late_double(Curnode, N_z, 0.0, -MAXFLOAT); - - fprintf(Output_file, "Shape {\n"); - fprintf(Output_file, " appearance Appearance {\n"); - fprintf(Output_file, " material Material {\n"); - fprintf(Output_file, " ambientIntensity 0.33\n"); - fprintf(Output_file, " diffuseColor 1 1 1\n"); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " texture ImageTexture { url \"%s\" }\n", - nodeURL(Curnode, somebuf)); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " geometry Extrusion {\n"); - fprintf(Output_file, " crossSection ["); - for (i = 0; i < n; i++) { - p.x = A[i].x - ND_coord_i(Curnode).x; - p.y = A[i].y - ND_coord_i(Curnode).y; - fprintf(Output_file, " %.3f %.3f,", p.x, p.y); - } - p.x = A[0].x - ND_coord_i(Curnode).x; - p.y = A[0].y - ND_coord_i(Curnode).y; - fprintf(Output_file, " %.3f %.3f ]\n", p.x, p.y); - fprintf(Output_file, " spine [ %d %d %.3f, %d %d %.3f ]\n", - ND_coord_i(Curnode).x, ND_coord_i(Curnode).y, z - .01, - ND_coord_i(Curnode).x, ND_coord_i(Curnode).y, z + .01); - fprintf(Output_file, " }\n"); - fprintf(Output_file, "}\n"); - break; - - case EDGE: - if (cstk[SP].pen == P_NONE) - return; - if (n != 3) { - static int flag; - if (!flag) { - flag++; - agerr(AGWARN, - "vrml_polygon: non-triangle arrowheads not supported - ignoring\n"); - } - } - if (IsSegment) { - doArrowhead (A); - return; - } - p.x = p.y = 0.0; - for (i = 0; i < n; i++) { - p.x += A[i].x; - p.y += A[i].y; - } - p.x = p.x / n; - p.y = p.y / n; - - /* it is bad to know that A[1] is the aiming point, but we do */ - theta = - atan2((A[0].y + A[2].y) / 2.0 - A[1].y, - (A[0].x + A[2].x) / 2.0 - A[1].x) + PI / 2.0; - - - /* this is gruesome, but how else can we get z coord */ - if (DIST2(p, ND_coord_i(Curedge->tail)) < - DIST2(p, ND_coord_i(Curedge->head))) - endp = Curedge->tail; - else - endp = Curedge->head; - z = late_double(endp, N_z, 0.0, -MAXFLOAT); - - /* FIXME: arrow vector ought to follow z coord of bezier */ - fprintf(Output_file, "Transform {\n"); - fprintf(Output_file, " translation %.3f %.3f %.3f\n", p.x, p.y, - z); - fprintf(Output_file, " children [\n"); - fprintf(Output_file, " Transform {\n"); - fprintf(Output_file, " rotation 0 0 1 %.3f\n", theta); - fprintf(Output_file, " children [\n"); - fprintf(Output_file, " Shape {\n"); - fprintf(Output_file, - " geometry Cone {bottomRadius %.3f height %.3f }\n", - cstk[SP].penwidth * 2.5, cstk[SP].penwidth * 10.0); - fprintf(Output_file, " appearance USE E%d\n", - Curedge->id); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " ]\n"); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " ]\n"); - fprintf(Output_file, "}\n"); - break; - default: - break; - } -} - -/* doSphere: - * Output sphere in VRML for point nodes. - */ -static void -doSphere (point p, int rx, int ry) -{ - pointf mp; - double z; - - if (!(strcmp(cstk[SP].fillcolor, "transparent"))) { - return; - } - - mp.x = ND_coord_i(Curnode).x; - mp.y = ND_coord_i(Curnode).y; - - z = late_double(Curnode, N_z, 0.0, -MAXFLOAT); - - fprintf(Output_file, "Transform {\n"); - fprintf(Output_file, " translation %.3f %.3f %.3f\n", mp.x, mp.y, - z); - fprintf(Output_file, " scale %d %d %d\n", rx, rx, rx); - fprintf(Output_file, " children [\n"); - fprintf(Output_file, " Transform {\n"); - fprintf(Output_file, " children [\n"); - fprintf(Output_file, " Shape {\n"); - fprintf(Output_file, - " geometry Sphere { radius 1.0 }\n"); - fprintf(Output_file, " appearance Appearance {\n"); - fprintf(Output_file, " material Material {\n"); - fprintf(Output_file, " ambientIntensity 0.33\n"); - fprintf(Output_file, " diffuseColor %f %f %f\n", - cstk[SP].r,cstk[SP].g,cstk[SP].b); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " ]\n"); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " ]\n"); - fprintf(Output_file, "}\n"); -} - -static void vrml_ellipse(point p, int rx, int ry, int filled) -{ - pointf mp; - int i; - node_t *endp; - int style[40]; /* need 2* size for arcs, I don't know why */ - int pen, width; - gdImagePtr brush = NULL; - double z; - char somebuf[1024]; - - switch (Obj) { - case NODE: - if (shapeOf(Curnode) == SH_POINT) { - doSphere (p, rx, ry); - return; - } - cstk[SP].pencolor_ix = vrml_resolve_color(cstk[SP].pencolor); - cstk[SP].fillcolor_ix = vrml_resolve_color(cstk[SP].fillcolor); - if (cstk[SP].pen != P_NONE) { - if (cstk[SP].pen == P_DASHED) { - for (i = 0; i < 20; i++) - style[i] = cstk[SP].pencolor_ix; - for (; i < 40; i++) - style[i] = gdTransparent; - gdImageSetStyle(im, style, 40); - pen = gdStyled; - } else if (cstk[SP].pen == P_DOTTED) { - for (i = 0; i < 2; i++) - style[i] = cstk[SP].pencolor_ix; - for (; i < 24; i++) - style[i] = gdTransparent; - gdImageSetStyle(im, style, 24); - pen = gdStyled; - } else { - pen = cstk[SP].pencolor_ix; - } - if (cstk[SP].penwidth != WIDTH_NORMAL) { - width = cstk[SP].penwidth; - brush = gdImageCreate(width, width); - gdImagePaletteCopy(brush, im); - gdImageFilledRectangle(brush, - 0, 0, width - 1, width - 1, - cstk[SP].pencolor_ix); - gdImageSetBrush(im, brush); - if (pen == gdStyled) - pen = gdStyledBrushed; - else - pen = gdBrushed; - } - mp = vrml_node_point(p); - - if (filled) { - gdImageFilledEllipse(im, ROUND(mp.x), ROUND(mp.y), - ROUND(Scale * (rx + rx)), - ROUND(Scale * (ry + ry)), - cstk[SP].fillcolor_ix); - } - gdImageArc(im, ROUND(mp.x), ROUND(mp.y), - ROUND(Scale * (rx + rx)), ROUND(Scale * (ry + ry)), - 0, 360, pen); - if (brush) - gdImageDestroy(brush); - } - - mp.x = ND_coord_i(Curnode).x; - mp.y = ND_coord_i(Curnode).y; - - z = late_double(Curnode, N_z, 0.0, -MAXFLOAT); - - fprintf(Output_file, "Transform {\n"); - fprintf(Output_file, " translation %.3f %.3f %.3f\n", mp.x, mp.y, - z); - fprintf(Output_file, " scale %d %d 1\n", rx, ry); - fprintf(Output_file, " children [\n"); - fprintf(Output_file, " Transform {\n"); - fprintf(Output_file, " rotation 1 0 0 1.57\n"); - fprintf(Output_file, " children [\n"); - fprintf(Output_file, " Shape {\n"); - fprintf(Output_file, - " geometry Cylinder { side FALSE }\n"); - fprintf(Output_file, " appearance Appearance {\n"); - fprintf(Output_file, " material Material {\n"); - fprintf(Output_file, " ambientIntensity 0.33\n"); - fprintf(Output_file, " diffuseColor 1 1 1\n"); - fprintf(Output_file, " }\n"); - fprintf(Output_file, - " texture ImageTexture { url \"%s\" }\n", - nodeURL(Curnode, somebuf)); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " ]\n"); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " ]\n"); - fprintf(Output_file, "}\n"); - break; - case EDGE: - if (cstk[SP].pen == P_NONE) - return; - mp.x = (double) p.x; - mp.y = (double) p.y; - /* this is gruesome, but how else can we get z coord */ - if (DIST2(mp, ND_coord_i(Curedge->tail)) < - DIST2(mp, ND_coord_i(Curedge->head))) - endp = Curedge->tail; - else - endp = Curedge->head; - z = late_double(endp, N_z, 0.0, -MAXFLOAT); - - fprintf(Output_file, "Transform {\n"); - fprintf(Output_file, " translation %.3f %.3f %.3f\n", mp.x, mp.y, - z); - fprintf(Output_file, " children [\n"); - fprintf(Output_file, " Shape {\n"); - fprintf(Output_file, " geometry Sphere {radius %.3f }\n", - (double) rx); - fprintf(Output_file, " appearance USE E%d\n", Curedge->id); - fprintf(Output_file, " }\n"); - fprintf(Output_file, " ]\n"); - fprintf(Output_file, "}\n"); - break; - default: - break; - } -} - -static void vrml_polyline(point * A, int n) -{ -/* - pointf p, p1; - int i; - - if (cstk[SP].pen != P_NONE) { - p.x = A[0].x; - p.y = A[0].y; - for (i = 1; i < n; i++) { - p1.x = A[i].x; - p1.y = A[i].y; -#ifdef NONEOFTHISEITHER - if (cstk[SP].pen == P_DASHED) { - gdImageDashedLine(im, ROUND(p.x), ROUND(p.y), - ROUND(p1.x), ROUND(p1.y), cstk[SP].color_ix); - } else { - gdImageLine(im, ROUND(p.x), ROUND(p.y), - ROUND(p1.x), ROUND(p1.y), cstk[SP].color_ix); - } -#endif - p.x = p1.x; - p.y = p1.y; - } - } -*/ -} - -static void vrml_usershape(usershape_t *us, boxf b, point *A, int n, bool filled) -{ -/* FIXME */ - vrml_polygon(A, n, filled); -} - -codegen_t VRML_CodeGen = { - 0, /* vrml_reset */ - vrml_begin_job, 0, /* vrml_end_job */ - vrml_begin_graph, vrml_end_graph, - vrml_begin_page, 0, /* vrml_end_page */ - 0, /* vrml_begin_layer */ 0, /* vrml_end_layer */ - 0, /* vrml_begin_cluster */ 0, /* vrml_end_cluster */ - 0, /* vrml_begin_nodes */ 0, /* vrml_end_nodes */ - 0, /* vrml_begin_edges */ 0, /* vrml_end_edges */ - vrml_begin_node, vrml_end_node, - vrml_begin_edge, vrml_end_edge, - vrml_begin_context, vrml_end_context, - 0, /* vrml_begin_anchor */ 0, /* vrml_end_anchor */ - vrml_set_font, vrml_textpara, - vrml_set_pencolor, vrml_set_fillcolor, vrml_set_style, - vrml_ellipse, vrml_polygon, - vrml_bezier, vrml_polyline, - 0, /* bezier_has_arrows */ - 0, /* comment */ - vrml_usershape -}; -#endif /* HAVE_GD_PNG */ -- 2.40.0