ps.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:17k
- /*
- * Postscript output for xgraph
- *
- * Rick Spickelmier
- * David Harrison
- */
- #include "copyright.h"
- #include <stdio.h>
- #include "xgraph.h"
- /*
- * Basic scaling parameters
- */
- #define VDPI 1200.0
- #define LDIM 11.0
- #define SDIM 8.5
- #define MICRONS_PER_INCH 2.54E+04
- #define POINTS_PER_INCH 72.0
- #define INCHES_PER_POINT 1.0/72.0
- /*
- * Aesthetic parameters (inches)
- */
- #define PS_BDR_PAD 0.075
- #define PS_AXIS_PAD 0.1
- #define PS_LEG_PAD 0.025
- #define PS_TICK_LEN 0.125
- #define BASE_DASH (1.0/48.0)
- #define BASE_WIDTH (1.0/8.0)
- #define PS_AXIS_WBASE 1
- #define PS_ZERO_WBASE 4
- #define PS_DATA_WBASE 7
- #define PS_PIXEL 4
- #define PS_DOT 12
- #define PS_MARK 12
- /*
- * Other constants
- */
- #define FONT_WIDTH_EST 0.55
- #define PS_MAX_SEGS 1000
- #define PS_NO_TSTYLE -1
- #define PS_NO_DSTYLE -1
- #define PS_NO_WIDTH -1
- #define PS_NO_LSTYLE -1
- #define PS_NO_COLOR -1
- /*
- * Working macros
- */
- #define OUT (void) fprintf
- #define PS(str) OUT(psFile, str)
- #define PSU(str) OUT(ui->psFile, str)
- #define IY(val) (ui->height_devs - val)
- #define TEXTCOLOR 0
- #define MAXCOLOR 8 /* Number of gray scales supported */
- /*
- * Globals
- */
- static double PS_scale; /* devs/micron */
- /*
- * Externals and forwards
- */
- static void psScale(), psFonts(), psMarks(), psText(), psSeg(), psDot(), psEnd();
- /*
- * Local structures
- */
- struct userInfo {
- FILE *psFile;
- int currentTextStyle;
- int currentDashStyle;
- int currentWidth;
- int currentLStyle;
- int currentColor;
- int baseWidth;
- int height_devs;
- char *title_family;
- double title_size;
- char *axis_family;
- double axis_size;
- int flags;
- };
- int
- rd(dbl)
- double dbl;
- /* Short and sweet rounding function */
- {
- if (dbl < 0.0) {
- return ((int) (dbl - 0.5));
- }
- else {
- return ((int) (dbl + 0.5));
- }
- }
- /*ARGSUSED*/
- int
- psInit(psFile, width, height, tf, ts, af, as, flags, outInfo, errmsg)
- FILE *psFile; /* Output file */
- int width,
- height; /* In microns */
- char *tf,
- *af; /* Title and axis font */
- double ts,
- as; /* Title and axis size */
- int flags; /* Predicate flags */
- xgOut *outInfo; /* Returned device info */
- char errmsg[ERRBUFSIZE]; /* Returned error message */
- /*
- * The basic coordinate system is points (roughly 1/72 inch).
- * However, most laser printers can do much better than that.
- * We invent a coordinate system based on VDPI dots per inch.
- * This goes along the long side of the page. The long side
- * of the page is LDIM inches in length, the short side
- * SDIM inches in length. We we call this unit a `dev'.
- * We map `width' and `height' into devs.
- */
- {
- struct userInfo *ui;
- double font_size;
- ui = (struct userInfo *) Malloc(sizeof(struct userInfo));
- ui->psFile = psFile;
- ui->currentTextStyle = PS_NO_TSTYLE;
- ui->currentDashStyle = PS_NO_DSTYLE;
- ui->currentWidth = PS_NO_WIDTH;
- ui->currentLStyle = PS_NO_LSTYLE;
- ui->currentColor = PS_NO_COLOR;
- ui->title_family = tf;
- ui->title_size = ts;
- ui->axis_family = af;
- ui->axis_size = as;
- /* Roughly, one-eighth a point in devs */
- ui->baseWidth = rd(VDPI / POINTS_PER_INCH * BASE_WIDTH);
- ui->flags = flags;
- PS_scale = VDPI / MICRONS_PER_INCH;
- outInfo->dev_flags = 0;
- outInfo->area_w = rd(((double) width) * PS_scale);
- outInfo->area_h = rd(((double) height) * PS_scale);
- ui->height_devs = outInfo->area_h;
- outInfo->bdr_pad = rd(PS_BDR_PAD * VDPI);
- outInfo->axis_pad = rd(PS_AXIS_PAD * VDPI);
- outInfo->legend_pad = rd(PS_LEG_PAD * VDPI);
- outInfo->tick_len = rd(PS_TICK_LEN * VDPI);
- /* Font estimates */
- font_size = as * INCHES_PER_POINT * VDPI;
- outInfo->axis_height = rd(font_size);
- outInfo->axis_width = rd(font_size * FONT_WIDTH_EST);
- font_size = ts * INCHES_PER_POINT * VDPI;
- outInfo->title_height = rd(font_size);
- outInfo->title_width = rd(font_size * FONT_WIDTH_EST);
- outInfo->max_segs = PS_MAX_SEGS;
- outInfo->xg_text = psText;
- outInfo->xg_seg = psSeg;
- outInfo->xg_dot = psDot;
- outInfo->xg_end = psEnd;
- outInfo->user_state = (char *) ui;
- /* Postscript file identification */
- PS("%%!n");
- /* Definitions */
- psScale(psFile, width, height, flags);
- psFonts(psFile);
- psMarks(psFile);
- PS("%%n%% Main body begins heren%%n");
- return 1;
- }
- static void
- psHeader(psFile, docu_flag)
- FILE *psFile;
- int docu_flag;
- /*
- * Prints out a standard greeting to the Postscript file.
- */
- {
- PS("%%%%EndCommentsn");
- PS("%%n");
- PS("%% Xgraph postscript outputn");
- PS("%% Rick Spickelmier and David Harrisonn");
- PS("%% University of California, Berkeleyn");
- if (docu_flag) {
- PS("%%n");
- PS("%% Output produced for inclusion in another document.n");
- PS("%% This file will not work properly if sent directly to a printer.n");
- }
- PS("%%n");
- }
- static void
- psScale(psFile, width, height, flags)
- FILE *psFile; /* Output stream */
- int width; /* Output width */
- int height; /* Output height */
- int flags; /* Output options */
- /*
- * This routine figures out how transform the basic postscript
- * transformation into one suitable for direct use by
- * the drawing primitives. Two variables X-CENTER-PLOT
- * and Y-CENTER-PLOT determine whether the plot is centered
- * on the page. If `flags' has D_DOCU set, then the plot
- * will not be rotated or centered and a bounding box will
- * be displayed.
- */
- {
- double factor;
- double pnt_width,
- pnt_height;
- if (flags & D_DOCU) {
- OUT(psFile, "%%%%BoundingBox: %ld %ld %ld %ldn",
- 0, 0,
- (int) (((double) width) /
- (MICRONS_PER_INCH * INCHES_PER_POINT) + 0.5),
- (int) (((double) height) /
- (MICRONS_PER_INCH * INCHES_PER_POINT) + 0.5)
- );
- psHeader(psFile, 1);
- PS("%% Rotation and centering are turned off for inclusion in a documentn");
- }
- else {
- psHeader(psFile, 0);
- PS("%% Scaling informationn");
- PS("%%n");
- PS("%% Change these if you would like to change the centeringn");
- PS("%% of the plot in either dimensionn");
- PS("/X-CENTER-PLOT 1 defn");
- PS("/Y-CENTER-PLOT 1 defn");
- PS("%%n");
- /*
- * Determine page size
- */
- PS("%% Page size computationn");
- PS("clippath pathbboxn");
- PS("/page-height exch defn");
- PS("/page-width exch defn");
- PS("pop popn");
- /*
- * First: rotation. If the width is greater than the short dimension,
- * do the rotation.
- */
- pnt_width = ((double) width) / MICRONS_PER_INCH * POINTS_PER_INCH;
- pnt_height = ((double) height) / MICRONS_PER_INCH * POINTS_PER_INCH;
- PS("%% Determine whether rotation is requiredn");
- OUT(psFile, "%lg page-width gtn", pnt_width);
- PS("{ %% Rotation requiredn");
- PS(" 90 rotaten");
- PS(" 0 page-width neg translaten");
- PS(" %% Handle centeringn");
- PS(" Y-CENTER-PLOT 1 eq { %% Center in yn");
- OUT(psFile, " page-height %lg sub 2 divn", pnt_width);
- PS(" } { %% Don't center in yn");
- PS(" 0n");
- PS(" } ifelsen");
- PS(" X-CENTER-PLOT 1 eq { %% Center in xn");
- OUT(psFile, " page-width %lg sub 2 divn", pnt_height);
- PS(" } { %% Don't center in xn");
- PS(" 0n");
- PS(" } ifelsen");
- PS(" translaten");
- PS("} { %% No rotation - just handle centeringn");
- PS(" X-CENTER-PLOT 1 eq { %% Center in xn");
- OUT(psFile, " page-width %lg sub 2 divn", pnt_width);
- PS(" } { %% Don't center in xn");
- PS(" 0n");
- PS(" } ifelsen");
- PS(" Y-CENTER-PLOT 1 eq { %% Center in yn");
- OUT(psFile, " page-height %lg sub 2 divn", pnt_height);
- PS(" } { %% Don't center in yn");
- PS(" 0n");
- PS(" } ifelsen");
- PS(" translaten");
- PS("} ifelsen");
- }
- /*
- * Now: scaling. We have points. We want devs.
- */
- factor = POINTS_PER_INCH / VDPI;
- PS("%% Set the scalen");
- OUT(psFile, "%lg %lg scalen", factor, factor);
- }
- static void
- psFonts(psFile)
- FILE *psFile; /* Output stream */
- /*
- * Downloads code for drawing title and axis labels
- */
- {
- PS("%% Font Handling Functionsn");
- PS("%%n");
- PS("%% Function giving y-offset to center of fontn");
- PS("%% Assumes font is set and uses numbers to gauge centern");
- PS("%%n");
- PS("/choose-font %% stack: fontsize fontname => ---n");
- PS("{n");
- PS(" findfont n");
- PS(" exch scalefont n");
- PS(" setfontn");
- PS(" newpathn");
- PS(" 0 0 moveto (0) true charpath flattenpath pathbboxn");
- PS(" /top exch def popn");
- PS(" /bottom exch def popn");
- PS(" bottom top bottom top add 2 divn");
- PS(" /center-font-val exch def n");
- PS(" /upper-font-val exch def n");
- PS(" /lower-font-val exch defn");
- PS("} defn");
- PS("%%n");
- PS("%% Justfication offset routinesn");
- PS("%%n");
- PS("/center-x-just %% stack: (string) x y => (string) newx yn");
- PS("{n");
- PS(" exch 2 index stringwidth pop 2 div sub exchn");
- PS("} defn");
- PS("%%n");
- PS("/left-x-just %% stack: (string) x y => (string) newx yn");
- PS("{ n");
- PS("} defn");
- PS("%%n");
- PS("/right-x-just %% stack: (string) x y => (string) newx yn");
- PS("{n");
- PS(" exch 2 index stringwidth pop sub exchn");
- PS("} defn");
- PS("%%n");
- PS("/center-y-just %% stack: (string) x y => (string) x newyn");
- PS("{n");
- PS(" center-font-val subn");
- PS("} defn");
- PS("%%n");
- PS("/lower-y-just %% stack: (string) x y => (string) x newyn");
- PS("{n");
- PS(" lower-font-val subn");
- PS("} defn");
- PS("%%n");
- PS("/upper-y-just %% stack: (string) x y => (string) x newyn");
- PS("{n");
- PS(" upper-font-val subn");
- PS("} defn");
- PS("%%n");
- PS("%% Shows a string on the page subject to justificationn");
- PS("%% n");
- PS("/just-string %% stack: (string) x y just => ---n");
- PS("{n");
- PS(" dup 0 eq { pop center-x-just center-y-just } ifn");
- PS(" dup 1 eq { pop left-x-just center-y-just } ifn");
- PS(" dup 2 eq { pop left-x-just upper-y-just } ifn");
- PS(" dup 3 eq { pop center-x-just upper-y-just } ifn");
- PS(" dup 4 eq { pop right-x-just upper-y-just } ifn");
- PS(" dup 5 eq { pop right-x-just center-y-just } ifn");
- PS(" dup 6 eq { pop right-x-just lower-y-just } ifn");
- PS(" dup 7 eq { pop center-x-just lower-y-just } ifn");
- PS(" dup 8 eq { pop left-x-just lower-y-just } ifn");
- PS(" moveto shown");
- PS("} defn");
- PS("%%n");
- }
- static void
- psMarks(psFile)
- FILE *psFile;
- /*
- * Writes out marker definitions
- */
- {
- PS("%% Marker definitionsn");
- PS("/mark0 {/size exch def /y exch def /x exch defn");
- PS("newpath x size sub y size sub moveton");
- PS("size size add 0 rlineto 0 size size add rlineton");
- PS("0 size size add sub 0 rlineto closepath fill} defn");
- PS("/mark1 {/size exch def /y exch def /x exch defn");
- PS("newpath x size sub y size sub moveton");
- PS("size size add 0 rlineto 0 size size add rlineton");
- PS("0 size size add sub 0 rlineto closepath stroke} defn");
- PS("/mark2 {/size exch def /y exch def /x exch defn");
- PS("newpath x y moveto x y size 0 360 arc stroke} defn");
- PS("/mark3 {/size exch def /y exch def /x exch defn");
- PS("newpath x size sub y size sub moveto x size add y size add lineton");
- PS("x size sub y size add moveto x size add y size sub lineto stroke} defn");
- PS("/mark4 {/size exch def /y exch def /x exch defn");
- PS("newpath x size sub y moveto x y size add lineton");
- PS("x size add y lineto x y size sub lineton");
- PS("closepath stroke} defn");
- PS("/mark5 {/size exch def /y exch def /x exch defn");
- PS("x y size mark1n");
- PS("newpath x size sub y moveto size size add 0 rlineto stroke} defn");
- PS("/mark6 {/size exch def /y exch def /x exch defn");
- PS("newpath x y moveto x y size 0 360 arc fill} defn");
- PS("/mark7 {/size exch def /y exch def /x exch defn");
- PS("newpath x y moveto x size sub y size sub lineton");
- PS("x size add y size sub lineto closepath filln");
- PS("newpath x y moveto x size add y size add lineton");
- PS("x size sub y size add lineto closepath fill} defn");
- }
- static void
- psText(state, x, y, text, just, style)
- char *state; /* Really (struct userInfo *) */
- int x,
- y; /* Text position (devs) */
- char *text; /* Text itself */
- int just; /* Justification */
- int style; /* Style */
- /*
- * Draws text at the given location with the given justification
- * and style.
- */
- {
- struct userInfo *ui = (struct userInfo *) state;
- if (TEXTCOLOR != ui->currentColor) {
- OUT(ui->psFile, "%lg setgrayn", (double) TEXTCOLOR / 8);
- ui->currentColor = TEXTCOLOR;
- }
- if (style != ui->currentTextStyle) {
- switch (style) {
- case T_AXIS:
- OUT(ui->psFile, "%lg /%s choose-fontn",
- ui->axis_size * INCHES_PER_POINT * VDPI, ui->axis_family);
- break;
- case T_TITLE:
- OUT(ui->psFile, "%lg /%s choose-fontn",
- ui->title_size * INCHES_PER_POINT * VDPI, ui->title_family);
- break;
- }
- ui->currentTextStyle = style;
- }
- OUT(ui->psFile, "(%s) %d %d %d just-stringn", text, x, IY(y), just);
- }
- /*ARGSUSED*/
- static void
- psSeg(state, ns, seglist, width, style, lappr, color)
- char *state; /* Really (struct userInfo *) */
- int ns; /* Number of segments */
- XSegment *seglist; /* X array of segments */
- int width; /* Width of lines (devcoords) */
- int style; /* L_AXIS, L_ZERO, L_VAR */
- int lappr; /* Zero to seven */
- int color; /* Zero to seven */
- /*
- * Draws a number of line segments. Grid lines are drawn using
- * light lines. Variable lines (L_VAR) are drawn wider. This
- * version ignores the color argument.
- */
- {
- struct userInfo *ui = (struct userInfo *) state;
- int newwidth = 0,
- i;
- if ((style != ui->currentLStyle) || (width != ui->currentWidth)) {
- switch (style) {
- case L_AXIS:
- newwidth = PS_AXIS_WBASE * ui->baseWidth;
- PSU("[] 0 setdashn");
- break;
- case L_ZERO:
- newwidth = PS_ZERO_WBASE * ui->baseWidth;
- PSU("[] 0 setdashn");
- break;
- case L_VAR:
- newwidth = PS_DATA_WBASE * ui->baseWidth;
- break;
- }
- ui->currentWidth = MAX(newwidth, width);
- ui->currentLStyle = style;
- OUT(ui->psFile, "%d setlinewidthn", ui->currentWidth);
- }
- if (width > 4) {
- if (color > MAXCOLOR)
- color -= MAXCOLOR;
- else
- lappr = 0;
- }
- else
- color = TEXTCOLOR;
- if ((lappr != ui->currentDashStyle) && (style == L_VAR)) {
- if (lappr == 0) {
- PSU("[] 0 setdashn");
- }
- else {
- OUT(ui->psFile, "[%lg] 0 setdashn",
- ((double) lappr) * BASE_DASH * VDPI);
- }
- ui->currentDashStyle = lappr;
- }
- if ((color != ui->currentColor) && (style == L_VAR)) {
- OUT(ui->psFile, "%lg setgrayn", (double) color / MAXCOLOR);
- ui->currentColor = color;
- }
- PSU("newpathn");
- OUT(ui->psFile, " %d %d moveton", seglist[0].x1, IY(seglist[0].y1));
- OUT(ui->psFile, " %d %d lineton", seglist[0].x2, IY(seglist[0].y2));
- for (i = 1; i < ns; i++) {
- if ((seglist[i].x1 != seglist[i - 1].x2) ||
- (seglist[i].y1 != seglist[i - 1].y2)) {
- OUT(ui->psFile, " %d %d moveton", seglist[i].x1, IY(seglist[i].y1));
- }
- OUT(ui->psFile, " %d %d lineton", seglist[i].x2, IY(seglist[i].y2));
- }
- PSU("stroken");
- }
- /*ARGSUSED*/
- static void
- psDot(state, x, y, style, type, color)
- char *state; /* state information */
- int x,
- y; /* coord of dot */
- int style; /* type of dot */
- int type; /* dot style variation */
- int color; /* color of dot */
- /*
- * Prints out a dot at the given location
- */
- {
- struct userInfo *ui = (struct userInfo *) state;
- if (ui->currentDashStyle != PS_NO_DSTYLE) {
- OUT(ui->psFile, "[] 0 setdash ");
- ui->currentDashStyle = PS_NO_DSTYLE;
- }
- if (ui->currentWidth != PS_ZERO_WBASE * ui->baseWidth) {
- ui->currentWidth = PS_ZERO_WBASE * ui->baseWidth;
- OUT(ui->psFile, "%d setlinewidth ", ui->currentWidth);
- }
- if (color > MAXCOLOR)
- color -= MAXCOLOR;
- if ((color != ui->currentColor)) {
- OUT(ui->psFile, "%lg setgrayn", (double) color / MAXCOLOR);
- ui->currentColor = color;
- }
- switch (style) {
- case P_PIXEL:
- OUT(ui->psFile, "newpath %d %d moveto %d %d %d 0 360 arc filln",
- x, IY(y), x, IY(y), PS_PIXEL * ui->baseWidth);
- break;
- case P_DOT:
- OUT(ui->psFile, "newpath %d %d moveto %d %d %d 0 360 arc filln",
- x, IY(y), x, IY(y), PS_DOT * ui->baseWidth);
- break;
- case P_MARK:
- OUT(ui->psFile, "%d %d %d mark%dn",
- x, IY(y), PS_MARK * ui->baseWidth, type);
- break;
- }
- return;
- }
- static void
- psEnd(userState)
- char *userState; /* state information */
- {
- struct userInfo *ui = (struct userInfo *) userState;
- if (!(ui->flags & D_DOCU)) {
- PSU("showpagen");
- }
- PSU("%% End of xgraph outputn");
- }