ps.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:17k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Postscript output for xgraph
  3.  *
  4.  * Rick Spickelmier
  5.  * David Harrison
  6.  */
  7. #include "copyright.h"
  8. #include <stdio.h>
  9. #include "xgraph.h"
  10. /*
  11.  * Basic scaling parameters
  12.  */
  13. #define VDPI 1200.0
  14. #define LDIM 11.0
  15. #define SDIM 8.5
  16. #define MICRONS_PER_INCH 2.54E+04
  17. #define POINTS_PER_INCH 72.0
  18. #define INCHES_PER_POINT 1.0/72.0
  19. /*
  20.  * Aesthetic parameters (inches)
  21.  */
  22. #define PS_BDR_PAD 0.075
  23. #define PS_AXIS_PAD 0.1
  24. #define PS_LEG_PAD 0.025
  25. #define PS_TICK_LEN 0.125
  26. #define BASE_DASH (1.0/48.0)
  27. #define BASE_WIDTH (1.0/8.0)
  28. #define PS_AXIS_WBASE 1
  29. #define PS_ZERO_WBASE 4
  30. #define PS_DATA_WBASE 7
  31. #define PS_PIXEL 4
  32. #define PS_DOT 12
  33. #define PS_MARK 12
  34. /*
  35.  * Other constants
  36.  */
  37. #define FONT_WIDTH_EST 0.55
  38. #define PS_MAX_SEGS 1000
  39. #define PS_NO_TSTYLE -1
  40. #define PS_NO_DSTYLE -1
  41. #define PS_NO_WIDTH -1
  42. #define PS_NO_LSTYLE -1
  43. #define PS_NO_COLOR -1
  44. /*
  45.  * Working macros
  46.  */
  47. #define OUT (void) fprintf
  48. #define PS(str) OUT(psFile, str)
  49. #define PSU(str) OUT(ui->psFile, str)
  50. #define IY(val) (ui->height_devs - val)
  51. #define TEXTCOLOR 0
  52. #define MAXCOLOR 8 /* Number of gray scales supported */
  53. /*
  54.  * Globals
  55.  */
  56. static double PS_scale; /* devs/micron */
  57. /*
  58.  * Externals and forwards
  59.  */
  60. static void psScale(), psFonts(), psMarks(), psText(), psSeg(), psDot(), psEnd();
  61. /*
  62.  * Local structures
  63.  */
  64. struct userInfo {
  65.     FILE   *psFile;
  66.     int     currentTextStyle;
  67.     int     currentDashStyle;
  68.     int     currentWidth;
  69.     int     currentLStyle;
  70.     int     currentColor;
  71.     int     baseWidth;
  72.     int     height_devs;
  73.     char   *title_family;
  74.     double  title_size;
  75.     char   *axis_family;
  76.     double  axis_size;
  77.     int     flags;
  78. };
  79. int 
  80. rd(dbl)
  81. double  dbl;
  82. /* Short and sweet rounding function */
  83. {
  84.     if (dbl < 0.0) {
  85. return ((int) (dbl - 0.5));
  86.     }
  87.     else {
  88. return ((int) (dbl + 0.5));
  89.     }
  90. }
  91. /*ARGSUSED*/
  92. int 
  93. psInit(psFile, width, height, tf, ts, af, as, flags, outInfo, errmsg)
  94. FILE   *psFile; /* Output file            */
  95. int     width,
  96.         height; /* In microns             */
  97. char   *tf,
  98.        *af; /* Title and axis font    */
  99. double  ts,
  100.         as; /* Title and axis size    */
  101. int     flags; /* Predicate flags        */
  102. xgOut  *outInfo; /* Returned device info   */
  103. char    errmsg[ERRBUFSIZE]; /* Returned error message */
  104. /*
  105.  * The basic coordinate system is points (roughly 1/72 inch).
  106.  * However,  most laser printers can do much better than that.
  107.  * We invent a coordinate system based on VDPI dots per inch.
  108.  * This goes along the long side of the page.  The long side
  109.  * of the page is LDIM inches in length,  the short side
  110.  * SDIM inches in length.  We we call this unit a `dev'.
  111.  * We map `width' and `height' into devs.
  112.  */
  113. {
  114.     struct userInfo *ui;
  115.     double  font_size;
  116.     ui = (struct userInfo *) Malloc(sizeof(struct userInfo));
  117.     ui->psFile = psFile;
  118.     ui->currentTextStyle = PS_NO_TSTYLE;
  119.     ui->currentDashStyle = PS_NO_DSTYLE;
  120.     ui->currentWidth = PS_NO_WIDTH;
  121.     ui->currentLStyle = PS_NO_LSTYLE;
  122.     ui->currentColor = PS_NO_COLOR;
  123.     ui->title_family = tf;
  124.     ui->title_size = ts;
  125.     ui->axis_family = af;
  126.     ui->axis_size = as;
  127.     /* Roughly,  one-eighth a point in devs */
  128.     ui->baseWidth = rd(VDPI / POINTS_PER_INCH * BASE_WIDTH);
  129.     ui->flags = flags;
  130.     PS_scale = VDPI / MICRONS_PER_INCH;
  131.     outInfo->dev_flags = 0;
  132.     outInfo->area_w = rd(((double) width) * PS_scale);
  133.     outInfo->area_h = rd(((double) height) * PS_scale);
  134.     ui->height_devs = outInfo->area_h;
  135.     outInfo->bdr_pad = rd(PS_BDR_PAD * VDPI);
  136.     outInfo->axis_pad = rd(PS_AXIS_PAD * VDPI);
  137.     outInfo->legend_pad = rd(PS_LEG_PAD * VDPI);
  138.     outInfo->tick_len = rd(PS_TICK_LEN * VDPI);
  139.     /* Font estimates */
  140.     font_size = as * INCHES_PER_POINT * VDPI;
  141.     outInfo->axis_height = rd(font_size);
  142.     outInfo->axis_width = rd(font_size * FONT_WIDTH_EST);
  143.     font_size = ts * INCHES_PER_POINT * VDPI;
  144.     outInfo->title_height = rd(font_size);
  145.     outInfo->title_width = rd(font_size * FONT_WIDTH_EST);
  146.     outInfo->max_segs = PS_MAX_SEGS;
  147.     outInfo->xg_text = psText;
  148.     outInfo->xg_seg = psSeg;
  149.     outInfo->xg_dot = psDot;
  150.     outInfo->xg_end = psEnd;
  151.     outInfo->user_state = (char *) ui;
  152.     /* Postscript file identification */
  153.     PS("%%!n");
  154.     /* Definitions */
  155.     psScale(psFile, width, height, flags);
  156.     psFonts(psFile);
  157.     psMarks(psFile);
  158.     PS("%%n%% Main body begins heren%%n");
  159.     return 1;
  160. }
  161. static void 
  162. psHeader(psFile, docu_flag)
  163. FILE   *psFile;
  164. int     docu_flag;
  165. /*
  166.  * Prints out a standard greeting to the Postscript file.
  167.  */
  168. {
  169.     PS("%%%%EndCommentsn");
  170.     PS("%%n");
  171.     PS("%% Xgraph postscript outputn");
  172.     PS("%% Rick Spickelmier and David Harrisonn");
  173.     PS("%% University of California, Berkeleyn");
  174.     if (docu_flag) {
  175. PS("%%n");
  176. PS("%% Output produced for inclusion in another document.n");
  177. PS("%% This file will not work properly if sent directly to a printer.n");
  178.     }
  179.     PS("%%n");
  180. }
  181. static void 
  182. psScale(psFile, width, height, flags)
  183. FILE   *psFile; /* Output stream */
  184. int     width; /* Output width  */
  185. int     height; /* Output height */
  186. int     flags; /* Output options */
  187. /*
  188.  * This routine figures out how transform the basic postscript
  189.  * transformation into one suitable for direct use by
  190.  * the drawing primitives.  Two variables X-CENTER-PLOT
  191.  * and Y-CENTER-PLOT determine whether the plot is centered
  192.  * on the page.  If `flags' has D_DOCU set,  then the plot
  193.  * will not be rotated or centered and a bounding box will
  194.  * be displayed.
  195.  */
  196. {
  197.     double  factor;
  198.     double  pnt_width,
  199.             pnt_height;
  200.     if (flags & D_DOCU) {
  201. OUT(psFile, "%%%%BoundingBox: %ld %ld %ld %ldn",
  202.     0, 0,
  203.     (int) (((double) width) /
  204.    (MICRONS_PER_INCH * INCHES_PER_POINT) + 0.5),
  205.     (int) (((double) height) /
  206.    (MICRONS_PER_INCH * INCHES_PER_POINT) + 0.5)
  207.     );
  208. psHeader(psFile, 1);
  209. PS("%% Rotation and centering are turned off for inclusion in a documentn");
  210.     }
  211.     else {
  212. psHeader(psFile, 0);
  213. PS("%% Scaling informationn");
  214. PS("%%n");
  215. PS("%% Change these if you would like to change the centeringn");
  216. PS("%% of the plot in either dimensionn");
  217. PS("/X-CENTER-PLOT 1 defn");
  218. PS("/Y-CENTER-PLOT 1 defn");
  219. PS("%%n");
  220. /*
  221.  * Determine page size
  222.  */
  223. PS("%% Page size computationn");
  224. PS("clippath pathbboxn");
  225. PS("/page-height exch defn");
  226. PS("/page-width exch defn");
  227. PS("pop popn");
  228. /*
  229.  * First: rotation.  If the width is greater than the short dimension,
  230.  * do the rotation.
  231.  */
  232. pnt_width = ((double) width) / MICRONS_PER_INCH * POINTS_PER_INCH;
  233. pnt_height = ((double) height) / MICRONS_PER_INCH * POINTS_PER_INCH;
  234. PS("%% Determine whether rotation is requiredn");
  235. OUT(psFile, "%lg page-width gtn", pnt_width);
  236. PS("{ %% Rotation requiredn");
  237. PS("   90 rotaten");
  238. PS("   0 page-width neg translaten");
  239. PS("   %% Handle centeringn");
  240. PS("   Y-CENTER-PLOT 1 eq { %% Center in yn");
  241. OUT(psFile, "      page-height %lg sub 2 divn", pnt_width);
  242. PS("   } { %% Don't center in yn");
  243. PS("      0n");
  244. PS("   } ifelsen");
  245. PS("   X-CENTER-PLOT 1 eq { %% Center in xn");
  246. OUT(psFile, "      page-width %lg sub 2 divn", pnt_height);
  247. PS("   } { %% Don't center in xn");
  248. PS("      0n");
  249. PS("   } ifelsen");
  250. PS("   translaten");
  251. PS("} { %% No rotation - just handle centeringn");
  252. PS("   X-CENTER-PLOT 1 eq { %% Center in xn");
  253. OUT(psFile, "      page-width %lg sub 2 divn", pnt_width);
  254. PS("   } { %% Don't center in xn");
  255. PS("      0n");
  256. PS("   } ifelsen");
  257. PS("   Y-CENTER-PLOT 1 eq { %% Center in yn");
  258. OUT(psFile, "      page-height %lg sub 2 divn", pnt_height);
  259. PS("   } { %% Don't center in yn");
  260. PS("      0n");
  261. PS("   } ifelsen");
  262. PS("   translaten");
  263. PS("} ifelsen");
  264.     }
  265.     /*
  266.      * Now: scaling.  We have points.  We want devs.
  267.      */
  268.     factor = POINTS_PER_INCH / VDPI;
  269.     PS("%% Set the scalen");
  270.     OUT(psFile, "%lg %lg scalen", factor, factor);
  271. }
  272. static void 
  273. psFonts(psFile)
  274. FILE   *psFile; /* Output stream                */
  275. /*
  276.  * Downloads code for drawing title and axis labels
  277.  */
  278. {
  279.     PS("%% Font Handling Functionsn");
  280.     PS("%%n");
  281.     PS("%% Function giving y-offset to center of fontn");
  282.     PS("%% Assumes font is set and uses numbers to gauge centern");
  283.     PS("%%n");
  284.     PS("/choose-font %% stack: fontsize fontname => ---n");
  285.     PS("{n");
  286.     PS("   findfont n");
  287.     PS("   exch scalefont n");
  288.     PS("   setfontn");
  289.     PS("   newpathn");
  290.     PS("   0 0 moveto (0) true charpath flattenpath pathbboxn");
  291.     PS("   /top exch def popn");
  292.     PS("   /bottom exch def popn");
  293.     PS("   bottom top bottom top add 2 divn");
  294.     PS("   /center-font-val exch def n");
  295.     PS("   /upper-font-val exch def n");
  296.     PS("   /lower-font-val exch defn");
  297.     PS("} defn");
  298.     PS("%%n");
  299.     PS("%% Justfication offset routinesn");
  300.     PS("%%n");
  301.     PS("/center-x-just %% stack: (string) x y => (string) newx yn");
  302.     PS("{n");
  303.     PS("   exch 2 index stringwidth pop 2 div sub exchn");
  304.     PS("} defn");
  305.     PS("%%n");
  306.     PS("/left-x-just %% stack: (string) x y => (string) newx yn");
  307.     PS("{ n");
  308.     PS("} defn");
  309.     PS("%%n");
  310.     PS("/right-x-just %% stack: (string) x y => (string) newx yn");
  311.     PS("{n");
  312.     PS("   exch 2 index stringwidth pop sub exchn");
  313.     PS("} defn");
  314.     PS("%%n");
  315.     PS("/center-y-just %% stack: (string) x y => (string) x newyn");
  316.     PS("{n");
  317.     PS("   center-font-val subn");
  318.     PS("} defn");
  319.     PS("%%n");
  320.     PS("/lower-y-just %% stack: (string) x y => (string) x newyn");
  321.     PS("{n");
  322.     PS("   lower-font-val subn");
  323.     PS("} defn");
  324.     PS("%%n");
  325.     PS("/upper-y-just %% stack: (string) x y => (string) x newyn");
  326.     PS("{n");
  327.     PS("   upper-font-val subn");
  328.     PS("} defn");
  329.     PS("%%n");
  330.     PS("%% Shows a string on the page subject to justificationn");
  331.     PS("%%   n");
  332.     PS("/just-string %% stack: (string) x y just => ---n");
  333.     PS("{n");
  334.     PS("   dup 0 eq { pop center-x-just center-y-just  } ifn");
  335.     PS("   dup 1 eq { pop left-x-just center-y-just } ifn");
  336.     PS("   dup 2 eq { pop left-x-just upper-y-just   } ifn");
  337.     PS("   dup 3 eq { pop center-x-just upper-y-just  } ifn");
  338.     PS("   dup 4 eq { pop right-x-just upper-y-just   } ifn");
  339.     PS("   dup 5 eq { pop right-x-just center-y-just  } ifn");
  340.     PS("   dup 6 eq { pop right-x-just lower-y-just   } ifn");
  341.     PS("   dup 7 eq { pop center-x-just lower-y-just   } ifn");
  342.     PS("   dup 8 eq { pop left-x-just lower-y-just   } ifn");
  343.     PS("   moveto shown");
  344.     PS("} defn");
  345.     PS("%%n");
  346. }
  347. static void 
  348. psMarks(psFile)
  349. FILE   *psFile;
  350. /*
  351.  * Writes out marker definitions
  352.  */
  353. {
  354.     PS("%% Marker definitionsn");
  355.     PS("/mark0 {/size exch def /y exch def /x exch defn");
  356.     PS("newpath x size sub y size sub moveton");
  357.     PS("size size add 0 rlineto 0 size size add rlineton");
  358.     PS("0 size size add sub 0 rlineto closepath fill} defn");
  359.     PS("/mark1 {/size exch def /y exch def /x exch defn");
  360.     PS("newpath x size sub y size sub moveton");
  361.     PS("size size add 0 rlineto 0 size size add rlineton");
  362.     PS("0 size size add sub 0 rlineto closepath stroke} defn");
  363.     PS("/mark2 {/size exch def /y exch def /x exch defn");
  364.     PS("newpath x y moveto x y size 0 360 arc stroke} defn");
  365.     PS("/mark3 {/size exch def /y exch def /x exch defn");
  366.     PS("newpath x size sub y size sub moveto x size add y size add lineton");
  367.     PS("x size sub y size add moveto x size add y size sub lineto stroke} defn");
  368.     PS("/mark4 {/size exch def /y exch def /x exch defn");
  369.     PS("newpath x size sub y moveto x y size add lineton");
  370.     PS("x size add y lineto x y size sub lineton");
  371.     PS("closepath stroke} defn");
  372.     PS("/mark5 {/size exch def /y exch def /x exch defn");
  373.     PS("x y size mark1n");
  374.     PS("newpath x size sub y moveto size size add 0 rlineto stroke} defn");
  375.     PS("/mark6 {/size exch def /y exch def /x exch defn");
  376.     PS("newpath x y moveto x y size 0 360 arc fill} defn");
  377.     PS("/mark7 {/size exch def /y exch def /x exch defn");
  378.     PS("newpath x y moveto x size sub y size sub lineton");
  379.     PS("x size add y size sub lineto closepath filln");
  380.     PS("newpath x y moveto x size add y size add lineton");
  381.     PS("x size sub y size add lineto closepath fill} defn");
  382. }
  383. static void 
  384. psText(state, x, y, text, just, style)
  385. char   *state; /* Really (struct userInfo *) */
  386. int     x,
  387.         y; /* Text position (devs)       */
  388. char   *text; /* Text itself                */
  389. int     just; /* Justification              */
  390. int     style; /* Style                      */
  391. /*
  392.  * Draws text at the given location with the given justification
  393.  * and style.
  394.  */
  395. {
  396.     struct userInfo *ui = (struct userInfo *) state;
  397.     if (TEXTCOLOR != ui->currentColor) {
  398. OUT(ui->psFile, "%lg setgrayn", (double) TEXTCOLOR / 8);
  399. ui->currentColor = TEXTCOLOR;
  400.     }
  401.     if (style != ui->currentTextStyle) {
  402. switch (style) {
  403. case T_AXIS:
  404.     OUT(ui->psFile, "%lg /%s choose-fontn",
  405. ui->axis_size * INCHES_PER_POINT * VDPI, ui->axis_family);
  406.     break;
  407. case T_TITLE:
  408.     OUT(ui->psFile, "%lg /%s choose-fontn",
  409. ui->title_size * INCHES_PER_POINT * VDPI, ui->title_family);
  410.     break;
  411. }
  412. ui->currentTextStyle = style;
  413.     }
  414.     OUT(ui->psFile, "(%s) %d %d %d just-stringn", text, x, IY(y), just);
  415. }
  416. /*ARGSUSED*/
  417. static void 
  418. psSeg(state, ns, seglist, width, style, lappr, color)
  419. char   *state; /* Really (struct userInfo *) */
  420. int     ns; /* Number of segments         */
  421. XSegment *seglist; /* X array of segments        */
  422. int     width; /* Width of lines (devcoords) */
  423. int     style; /* L_AXIS, L_ZERO, L_VAR      */
  424. int     lappr; /* Zero to seven              */
  425. int     color; /* Zero to seven              */
  426. /*
  427.  * Draws a number of line segments.  Grid lines are drawn using
  428.  * light lines.  Variable lines (L_VAR) are drawn wider.  This
  429.  * version ignores the color argument.
  430.  */
  431. {
  432.     struct userInfo *ui = (struct userInfo *) state;
  433.     int     newwidth = 0,
  434.             i;
  435.     if ((style != ui->currentLStyle) || (width != ui->currentWidth)) {
  436. switch (style) {
  437. case L_AXIS:
  438.     newwidth = PS_AXIS_WBASE * ui->baseWidth;
  439.     PSU("[] 0 setdashn");
  440.     break;
  441. case L_ZERO:
  442.     newwidth = PS_ZERO_WBASE * ui->baseWidth;
  443.     PSU("[] 0 setdashn");
  444.     break;
  445. case L_VAR:
  446.     newwidth = PS_DATA_WBASE * ui->baseWidth;
  447.     break;
  448. }
  449. ui->currentWidth = MAX(newwidth, width);
  450. ui->currentLStyle = style;
  451. OUT(ui->psFile, "%d setlinewidthn", ui->currentWidth);
  452.     }
  453.     if (width > 4) {
  454. if (color > MAXCOLOR)
  455.     color -= MAXCOLOR;
  456. else
  457.     lappr = 0;
  458.     }
  459.     else
  460. color = TEXTCOLOR;
  461.     if ((lappr != ui->currentDashStyle) && (style == L_VAR)) {
  462. if (lappr == 0) {
  463.     PSU("[] 0 setdashn");
  464. }
  465. else {
  466.     OUT(ui->psFile, "[%lg] 0 setdashn",
  467. ((double) lappr) * BASE_DASH * VDPI);
  468. }
  469. ui->currentDashStyle = lappr;
  470.     }
  471.     if ((color != ui->currentColor) && (style == L_VAR)) {
  472. OUT(ui->psFile, "%lg setgrayn", (double) color / MAXCOLOR);
  473. ui->currentColor = color;
  474.     }
  475.     PSU("newpathn");
  476.     OUT(ui->psFile, "  %d %d moveton", seglist[0].x1, IY(seglist[0].y1));
  477.     OUT(ui->psFile, "  %d %d lineton", seglist[0].x2, IY(seglist[0].y2));
  478.     for (i = 1; i < ns; i++) {
  479. if ((seglist[i].x1 != seglist[i - 1].x2) ||
  480.     (seglist[i].y1 != seglist[i - 1].y2)) {
  481.     OUT(ui->psFile, "  %d %d moveton", seglist[i].x1, IY(seglist[i].y1));
  482. }
  483. OUT(ui->psFile, "  %d %d lineton", seglist[i].x2, IY(seglist[i].y2));
  484.     }
  485.     PSU("stroken");
  486. }
  487. /*ARGSUSED*/
  488. static void 
  489. psDot(state, x, y, style, type, color)
  490. char   *state; /* state information */
  491. int     x,
  492.         y; /* coord of dot */
  493. int     style; /* type of dot */
  494. int     type; /* dot style variation */
  495. int     color; /* color of dot */
  496. /*
  497.  * Prints out a dot at the given location
  498.  */
  499. {
  500.     struct userInfo *ui = (struct userInfo *) state;
  501.     if (ui->currentDashStyle != PS_NO_DSTYLE) {
  502. OUT(ui->psFile, "[] 0 setdash ");
  503. ui->currentDashStyle = PS_NO_DSTYLE;
  504.     }
  505.     if (ui->currentWidth != PS_ZERO_WBASE * ui->baseWidth) {
  506. ui->currentWidth = PS_ZERO_WBASE * ui->baseWidth;
  507. OUT(ui->psFile, "%d setlinewidth ", ui->currentWidth);
  508.     }
  509.     if (color > MAXCOLOR)
  510. color -= MAXCOLOR;
  511.     if ((color != ui->currentColor)) {
  512. OUT(ui->psFile, "%lg setgrayn", (double) color / MAXCOLOR);
  513. ui->currentColor = color;
  514.     }
  515.     switch (style) {
  516.     case P_PIXEL:
  517. OUT(ui->psFile, "newpath %d %d moveto %d %d %d 0 360 arc filln",
  518.     x, IY(y), x, IY(y), PS_PIXEL * ui->baseWidth);
  519. break;
  520.     case P_DOT:
  521. OUT(ui->psFile, "newpath %d %d moveto %d %d %d 0 360 arc filln",
  522.     x, IY(y), x, IY(y), PS_DOT * ui->baseWidth);
  523. break;
  524.     case P_MARK:
  525. OUT(ui->psFile, "%d %d %d mark%dn",
  526.     x, IY(y), PS_MARK * ui->baseWidth, type);
  527. break;
  528.     }
  529.     return;
  530. }
  531. static void 
  532. psEnd(userState)
  533. char   *userState; /* state information */
  534. {
  535.     struct userInfo *ui = (struct userInfo *) userState;
  536.     if (!(ui->flags & D_DOCU)) {
  537. PSU("showpagen");
  538.     }
  539.     PSU("%% End of xgraph outputn");
  540. }