home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Science / Science.zip / gmt_os2.zip / src / pslib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-08  |  78.2 KB  |  2,444 lines

  1. /*--------------------------------------------------------------------
  2.  *    The GMT-system:    @(#)pslib.c    2.51  5/3/95
  3.  *
  4.  *    Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith
  5.  *    See README file for copying and redistribution conditions.
  6.  *--------------------------------------------------------------------*/
  7. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  8.  * pslib is a library of plot functions that create PostScript.
  9.  * All the routines write their output to the same plotting file,
  10.  * which can be dumped to a Postscript output device (laserwriters).
  11.  * pslib can handle and mix text, line-drawings, and bit-map graphics
  12.  * in both black/white and color.
  13.  *
  14.  * pslib conforms to the Encapsulated PostScript Files Specification V 3.0,
  15.  * and pslib documents have successfully been used to make Encapsulated
  16.  * PostScript files on a Macintosh.
  17.  *
  18.  * C considerations:
  19.  *    All floating point data are assumed to be of type double.
  20.  *    All integer data are assumed to be of type int.
  21.  *    All logical data are assumed to be of type int (1 = TRUE, 0 = FALSE).
  22.  *
  23.  * Updated May, 1992 by J. Goff, WHOI to include FORTRAN interfaces
  24.  * Updated July, 1993 by P. Wessel to include more symbosl and binary image output
  25.  * Updated August, 1993 by P. Wessel to only warn about path length problems.
  26.  *
  27.  * FORTRAN considerations:
  28.  *    All floating point data are assumed to be DOUBLE PRECISION
  29.  *    All integer data are assumed to be INTEGER, i.e. INTEGER*4
  30.  *    All LOGICAL/int data are assumed to be of type INTEGER*4 (1 = TRUE, 0 = FALSE).
  31.  *
  32.  *    When passing (from FORTRAN to C) a fixed-length character variable which has 
  33.  *    blanks at the end, append "\0" (null character) after the last non-blank
  34.  *    character.  This is so that C will know where the character string ends.
  35.  *    It is NOT sufficient to pass, for example, "string(1:string_length)".
  36.  
  37.  *
  38.  * List of functions:
  39.  *    ps_arc            : Draws a circular arc
  40.  *    ps_axis            : Plots an axis with tickmarks and annotation/label
  41.  *    ps_circle        : Plots circle and [optionally] fills it
  42.  *    ps_clipoff        : Restores previous clipping path
  43.  *    ps_clipon        : Clips plot outside the specified polygon
  44.  *    ps_colorimage        : Plots a 24-bit 2-D image using the colorimage operator
  45.  *    ps_colortiles        : Plots a 24-bit 2-D image using tiling
  46.  *    ps_command        : Writes a given PostScript statement to the plot file
  47.  *    ps_comment        : Writes a comment statement to the plot file
  48.  *    ps_cross        : Plots a + 
  49.  *    ps_diamond        : Plots a diamond and [optionally] fills it
  50.  *    ps_ellipse        : Plots an ellipse and [optionally] fills it
  51.  *    ps_hexagon        : Plots a hexagon and {optionally] fills it
  52.  *    ps_image        : Plots a 1-to-8 bit 2-D image using grayshades
  53.  *    ps_imagefill        : Fills a polygon with a repeating n x n image pattern
  54.  *    ps_imagergb        : Plots a 24-bit 2-D image using color separations
  55.  *    ps_itriangle        : Plots an inverted triangle and [optionally] fills it
  56.  *    ps_line            : Plots a line
  57.  *    ps_patch        : Special case of ps_polygon:  Short polygons only (< 20 points, no path-shortening)
  58.  *    ps_pie            : Plots a sector of a circle and [optionally] fills it
  59.  *    ps_plot            : Absolute move to new position (pen up or down)
  60.  *    ps_plotend        : Close plotfile
  61.  *    ps_plotinit        : Initialize parameters/open plotfile etc.
  62.  *    ps_plotr        : Relative move to a new position (pen up or down)
  63.  *    ps_polygon        : Creates a polygon and optionally fills it
  64.  *    ps_rect            : Draws a rectangle and [optionally] fills it
  65.  *    ps_rotatetrans        : Rotates, then translates the coordinate system
  66.  *    ps_setdash        : Specify pattern for dashed line
  67.  *    ps_setfont        : Changes current font
  68.  *    ps_setformat        : Changes # of decimals used in color and gray specs [3]
  69.  *    ps_setline        : Sets linewidth
  70.  *    ps_setpaint        : Sets the current r/g/b for fill
  71.  *    ps_square        : Plots square and [optionally] shades it
  72.  *    ps_star            : Plots a star and {optionally] fills it
  73.  *    ps_text            : Plots textstring
  74.  *    ps_textbox        : Draw a filled box around a textstring
  75.  *    ps_transrotate        : Translates and rotates the coordinate system
  76.  *    ps_triangle        : Plots a triangle and [optionally] fills it
  77.  *    ps_vector        : Draws an vector as specified
  78.  *
  79.  *
  80.  * For information about usage, syntax etc, see the pslib.l manual pages
  81.  *
  82.  * Author:    Paul Wessel, Dept. of Geology and Geophysics
  83.  *        School of Ocean and Earth Science and Technology
  84.  *        2525 Correa Road, Honolulu, HI 96822
  85.  *        wessel@soest.hawaii.edu
  86.  * Date:    3-JAN-1995
  87.  * Version:    2.3a
  88.  *
  89.  * !! Must use -DLIBDIR=\"libdirpath\" when compiling, where libdirpath
  90.  *   is where pspatterns are stored
  91.  *            ***********************************
  92.  * Note above comment is true only under original unix code provided by
  93.  * Wessell and Smith. The OS/2 version relies on environmental variables
  94.  * [specifically,  GMTLIBDIR] to point to the proper data path where the
  95.  * pattens (pspatterns.*) are stored.
  96.  *
  97.  *
  98.  */
  99.  
  100. #include "pslib_inc.h"
  101. #include "pslib.h"
  102.  
  103. /* Define support functions called inside pslib functions */
  104.  
  105. int get_uppercase();
  106. char *get_icon();
  107. char *ps_prepare_text();
  108. void init_euro_header();
  109.  
  110. void ps_arc (x, y, radius, az1, az2, status)
  111. double x, y, radius, az1, az2;
  112. int status; {    /* 1 = set anchor, 2 = set end, 3 = both */
  113.     int ix, iy, ir;
  114.     
  115.     ix = rint (x * ps.scale);
  116.     iy = rint (y * ps.scale);
  117.     ir = rint (radius * ps.scale);
  118.     if (fabs (az1 - az2) > 360.0) az1 = 0.0, az2 = 360.0; 
  119.     if (status%2) {    /* Beginning of new segment */
  120.         fprintf (ps.fp, "S ");
  121.         ps.npath = 0;
  122.     }
  123.     else
  124.         ps.npath++;
  125.     if (az1 < az2)    /* Forward positive arc */
  126.         fprintf (ps.fp, "%d %d %d %lg %lg arc", ix ,iy, ir, az1, az2);
  127.     else    /* Negative arc */
  128.         fprintf (ps.fp, "%d %d %d %lg %lg arcn", ix ,iy, ir, az1, az2);
  129.     if (status > 1)    fprintf (ps.fp, " S");
  130.     fprintf (ps.fp, "\n");
  131. }
  132.     
  133. /* fortran interface */
  134. int ps_arc_ (x, y, radius, az1, az2, status)
  135. double *x, *y, *radius, *az1, *az2;
  136. int *status; {
  137.      ps_arc (*x, *y, *radius, *az1, *az2, *status);
  138. }
  139.     
  140. void ps_axis (x, y, length, val0, val1, anotation_int, label, anotpointsize, side)
  141. double x, y, length, val0, val1, anotation_int;
  142. int anotpointsize, side;
  143. char *label; {
  144.     int anot_justify, label_justify, i, j, ndig = 0;
  145.     int left = FALSE;
  146.     double angle, dy, scl, val, anot_off, label_off, xx, sign;
  147.     char text[80], format[20];
  148.     
  149.     if (anotation_int < 0.0) left = TRUE;
  150.     anotation_int = fabs (anotation_int);
  151.     sprintf (text, "%lg\0", anotation_int);
  152.     for (i = 0; text[i] && text[i] != '.'; i++);
  153.     if (text[i]) {    /* Found a decimal point */
  154.         for (j = i + 1; text[j]; j++);
  155.         ndig = j - i - 1;
  156.     }
  157.     if (ndig > 0)
  158.         sprintf (format, "%%.%dlf\0", ndig);
  159.     else
  160.         strcpy (format, "%lg");
  161.         
  162.     angle = (side%2) ? 90.0 : 0.0;
  163.     sign = (side < 2) ? -1.0 : 1.0;
  164.     anot_justify = label_justify = (side < 2) ? -10 : -2;
  165.     dy = sign * anotpointsize / ps.points_pr_unit;
  166.             
  167.     fprintf (ps.fp, "\nV %d %d T %lg R\n", (int)rint (x * ps.scale), (int)rint (y * ps.scale), angle);
  168.     ps_plot (0.0, 0.0, 3);
  169.     ps_plot (length, 0.0, 2);
  170.     if ((val1 - val0) == 0.0) {
  171.         fprintf (stderr, "pslib: ERROR: Axis val0 == val1!\n");
  172.         return;
  173.     }
  174.     scl = length / (val1 - val0);
  175.     anot_off = dy;
  176.     label_off = 2.5 * dy;
  177.     dy *= 0.5;
  178.     
  179.     i = 0;
  180.     val = val0;
  181.     while (val <= (val1+SMALL)) {
  182.         i++;
  183.         xx = (val - val0) * scl;
  184.         if (left) xx = length - xx;
  185.         ps_plot (xx, 0.0, 3);
  186.         ps_plot (xx, dy, 2);
  187.         sprintf( text, format, val);
  188.         ps_text (xx, anot_off, anotpointsize, text, 0.0, anot_justify, 0);
  189.         val = val0 + i * anotation_int;
  190.     }
  191.     ps_text (0.5*length, label_off, (int) (anotpointsize*1.5), label, 0.0, label_justify, 0);
  192.     fprintf (ps.fp, "U\n\n");
  193. }
  194.  
  195. /* fortran interface */
  196. int ps_axis_ (x, y, length, val0, val1, anotation_int, label, anotpointsize, side, nlen)
  197. double *x, *y, *length, *val0, *val1, *anotation_int;
  198. int *anotpointsize, *side;
  199. int nlen;
  200. char *label; {
  201.     ps_axis (*x, *y, *length, *val0, *val1, *anotation_int, label, *anotpointsize, *side);
  202. }
  203.  
  204. void ps_circle (x, y, size, r, g, b, outline)
  205. double x, y, size;
  206. int r, g, b;
  207. int outline; {
  208.     int ix, iy, ir;
  209.     
  210.     ix = rint (x * ps.scale);
  211.     iy = rint (y * ps.scale);
  212.     ir = rint (size * ps.scale);
  213.     if (r < 0)    /* Outline only */
  214.         fprintf (ps.fp, "N %d %d %d C4\n", ix, iy, ir);
  215.     else if (r != g || g != b)    /* Color */
  216.         fprintf (ps.fp, "N %.3lg %.3lg %.3lg %d %d %d C%d\n", r * I_255, g * I_255, b * I_255, ix, iy, ir, outline + 2);
  217.     else    /* Grayshade only */
  218.         fprintf (ps.fp, "N %.3lg %d %d %d C%d\n", r * I_255, ix, iy, ir, outline);
  219.     ps.npath = 0;
  220. }
  221.  
  222. /* fortran interface */
  223. int ps_circle_ (x, y, size, r, g, b, outline)
  224. double *x, *y, *size;
  225. int *r, *g, *b;
  226. int *outline; {
  227.      ps_circle (*x, *y, *size, *r, *g, *b, *outline);
  228. }
  229.  
  230. void ps_clipoff () {
  231.     fprintf (ps.fp, "\nS U\n%%Clipping is currently OFF\n");
  232.     ps.npath = ps.clip_path_length = 0;
  233. }
  234.  
  235. /* fortran interface */
  236. int ps_clipoff_ () {
  237.     ps_clipoff ();
  238. }
  239.  
  240. void ps_clipon (x, y, n, r, g, b, flag)
  241. double x[], y[];
  242. int n;    /* Path length */
  243. int r, g, b;    /* Optional paint (-1 to avoid paint) */
  244. int flag; {    /* combo of 1 | 2. 1 = Start, 2 = end */
  245.     /* Any plotting outside the path defined by x,y will be clipped.
  246.        use clipoff to restore the original clipping path. */
  247.     
  248.     int used;
  249.     char move[7];
  250.     
  251.     if (flag & 1) {    /* First segment in (possibly multi-segmented) clip-path */
  252.         strcpy (move, "M");
  253.         fprintf (ps.fp, "\n%%Start of clip path\nS V\n");
  254.         ps.npath = 0;
  255.     }
  256.     else
  257.         strcpy (move, "moveto");
  258.         
  259.     used = 0;
  260.     if (n > 0) {
  261.         ps.ix = rint (x[0]*ps.scale);
  262.         ps.iy = rint (y[0]*ps.scale);
  263.         ps.npath++;
  264.         used++;
  265.         fprintf (ps.fp, "%d %d %s\n", ps.ix, ps.iy, move);
  266.         used += ps_line (&x[1], &y[1], n-1, 0, TRUE, FALSE);
  267.     }
  268.     ps.clip_path_length += used;
  269.     ps.max_path_length = MAX (ps.clip_path_length, ps.max_path_length);
  270.     
  271.     if (flag & 2) {    /* End path and [optionally] fill */
  272.         if (r >= 0 && (r != g || g != b)) /* color*/
  273.             fprintf (ps.fp, "V %.3lg %.3lg %.3lg C eofill U ", r * I_255, g * I_255, b * I_255);
  274.         else if (r >= 0)
  275.             fprintf (ps.fp, "V %.3lg A eofill U ", r * I_255);
  276.         if (flag & 4)
  277.             fprintf (ps.fp, "eoclip\n%%End of clip path.  Clipping is currently ON\n");
  278.         else
  279.             fprintf (ps.fp, "eoclip N\n%%End of clip path.  Clipping is currently ON\n");
  280.         ps.npath = 0;
  281.     }
  282. }
  283.       
  284. /* fortran interface */
  285. int ps_clipon_ (x, y, n, r, g, b, flag)
  286. double x[], y[];
  287. int *n, *r, *g, *b, *flag; {
  288.     ps_clipon (x, y, *n, *r, *g, *b, *flag);
  289. }
  290.       
  291. void ps_colorimage (x, y, xsize, ysize, buffer, nx, ny)
  292. double x, y, xsize, ysize;
  293. unsigned char *buffer;
  294. int nx, ny; {
  295.     /* Plots a color bitmapped image. Each pixel is described by
  296.      * 3 hexadecimal numbers, each may take on values from
  297.      * 00(0) to FF(255).  buffer stores the colroinfo in
  298.      * r g b r g b r g b format. Kosher Adobe operator.
  299.      */
  300.     if (ps.hex_image)
  301.         ps_colorimage_hex (x, y, xsize, ysize, buffer, nx, ny);
  302.     else
  303.         ps_colorimage_bin (x, y, xsize, ysize, buffer, nx, ny);
  304. }
  305.  
  306. int ps_colorimage_hex (x, y, xsize, ysize, buffer, nx, ny)
  307. double x, y, xsize, ysize;
  308. unsigned char *buffer;
  309. int nx, ny; {
  310.     /* Writes output image using hex format */
  311.     char hex[16], pixel[61];
  312.     int ix, iy, lx, ly, mx, i, j, kk, ij;
  313.     
  314.     pixel[60] = 0;
  315.     hex[0] = '0';    hex[1] = '1';    hex[2] = '2';    hex[3] = '3';
  316.     hex[4] = '4';    hex[5] = '5';    hex[6] = '6';    hex[7] = '7';
  317.     hex[8] = '8';    hex[9] = '9';    hex[10] = 'A';    hex[11] = 'B';
  318.     hex[12] = 'C';    hex[13] = 'D';    hex[14] = 'E';    hex[15] = 'F';
  319.     
  320.     ix = rint (x * ps.scale);
  321.     iy = rint (y * ps.scale);
  322.     lx = rint (xsize * ps.scale);
  323.     ly = rint (ysize * ps.scale);
  324.     mx = 3 * nx;
  325.     fprintf (ps.fp, "\n%% Start of hex Adobe colorimage\n");
  326.     fprintf (ps.fp, "V N %d %d T %d %d scale\n", ix, iy, lx, ly);
  327.     fprintf (ps.fp, "%d string /pstr exch def\n", mx);
  328.     fprintf (ps.fp, "%d %d 8 [%d 0 0 %d 0 %d] {currentfile pstr readhexstring pop} false 3 colorimage\n",
  329.         nx, ny, nx, -ny, ny);
  330.     kk = 0;
  331.     for (j = ij = 0; j < ny; j++) {
  332.         for (i = 0; i < nx; i++) {
  333.             pixel[kk++] = hex[buffer[ij] / 16];
  334.             pixel[kk++] = hex[buffer[ij++] % 16];
  335.             pixel[kk++] = hex[buffer[ij] / 16];
  336.             pixel[kk++] = hex[buffer[ij++] % 16];
  337.             pixel[kk++] = hex[buffer[ij] / 16];
  338.             pixel[kk++] = hex[buffer[ij++] % 16];
  339.             if (kk == 60) {
  340.                 fprintf (ps.fp, "%s\n", pixel);
  341.                 kk = 0;
  342.             }
  343.         }
  344.     }
  345.     if (kk > 0) {
  346.         pixel[kk] = 0;
  347.         fprintf (ps.fp, "%s\n", pixel);
  348.     }
  349.     fprintf (ps.fp, "U\n%% End of colorimage\n\n");
  350. }
  351.  
  352. int ps_colorimage_bin (x, y, xsize, ysize, buffer, nx, ny)
  353. double x, y, xsize, ysize;
  354. unsigned char *buffer;
  355. int nx, ny; {
  356.     /* Writes output image using bin format */
  357.  
  358.     int ix, iy, lx, ly, mx;
  359.     
  360.     ix = rint (x * ps.scale);
  361.     iy = rint (y * ps.scale);
  362.     lx = rint (xsize * ps.scale);
  363.     ly = rint (ysize * ps.scale);
  364.     mx = 3 * nx;
  365.     fprintf (ps.fp, "\n%% Start of binary Adobe colorimage\n");
  366.     fprintf (ps.fp, "V N %d %d T %d %d scale\n", ix, iy, lx, ly);
  367.     fprintf (ps.fp, "%d string /pstr exch def\n", mx);
  368.     fprintf (ps.fp, "%d %d 8 [%d 0 0 %d 0 %d] {currentfile pstr readstring pop} false 3 colorimage\n",
  369.         nx, ny, nx, -ny, ny);
  370.     fwrite ((char *)buffer, sizeof (unsigned char), mx * ny, ps.fp);
  371.     fprintf (ps.fp, "\nU\n%% End of colorimage\n\n");
  372. }
  373.  
  374. /* fortran interface */
  375. int ps_colorimage_ (x, y, xsize, ysize, buffer, nx, ny, nlen)
  376. double *x, *y, *xsize, *ysize;
  377. unsigned char *buffer;
  378. int nlen;
  379. int *nx, *ny; {
  380.     ps_colorimage (*x, *y, *xsize, *ysize, buffer, *nx, *ny);
  381. }
  382.  
  383. void ps_colortiles (x0, y0, dx, dy, image, nx, ny)
  384. double x0, y0;        /* Lower left corner in inches */
  385. double dx, dy;        /* Size of cell in inches */
  386. unsigned char *image;    /* color image  */
  387. int nx, ny; {        /* image size */
  388.     int i, j, k, r, g, b;
  389.     double x1, x2, y1, y2, noise, noise2;
  390.     
  391.     noise = 2.0 / ps.scale;
  392.     noise2 = 2.0 * noise;
  393.     dx /= nx;
  394.     dy /= ny;
  395.  
  396.     ps_transrotate (x0, y0, 0.0);
  397.     y2 = (ny - 0.5) * dy + 0.5 * noise;
  398.     for (j = k = 0; j < ny; j++) {
  399.         y1 = (ny - j - 1.5) * dy - 0.5 * noise;
  400.         x1 = -0.5 * (dx + noise);
  401.         for (i = 0; i < nx; i++) {
  402.             x2 = (i + 0.5) * dx + noise;
  403.             r = image[k++];
  404.             g = image[k++];
  405.             b = image[k++];
  406.             ps_rect (x1, y1, x2, y2, r, g, b, FALSE);
  407.             x1 = x2 - noise2;
  408.         }
  409.         y2 = y1 + noise2;
  410.     }
  411.     ps_rotatetrans (-x0, -y0, 0.0);
  412. }
  413.  
  414. /* fortran interface */
  415. int ps_colortiles_ (x0, y0, dx, dy, image, nx, ny, nlen)
  416. double *x0, *y0;
  417. double *dx, *dy;
  418. unsigned char *image;
  419. int nlen;
  420. int *nx, *ny; {
  421.      ps_colortiles (*x0, *y0, *dx, *dy, image, *nx, *ny);
  422. }
  423.  
  424. void ps_command (text)
  425. char *text; {
  426.     fprintf (ps.fp, "%s\n", text);
  427. }
  428.  
  429. /* fortran interface */
  430. int ps_command_ (text, nlen)
  431. int nlen;
  432. char *text; {
  433.     ps_command (text);
  434. }
  435.  
  436. void ps_comment (text)
  437. char *text; {
  438.     fprintf (ps.fp, "%% %s\n", text);
  439. }
  440.  
  441. /* fortran interface */
  442. int ps_comment_ (text, nlen)
  443. int nlen;
  444. char *text; {
  445.     ps_comment (text);
  446. }
  447.  
  448. void ps_cross (x, y, size)
  449. double x, y, size; {
  450.     fprintf (ps.fp, "%d %d %d X\n", (int) rint (size * ps.scale), (int) rint ((x - 0.5 * size) * ps.scale), (int ) rint (y * ps.scale));
  451.     ps.npath = 0;
  452. }
  453.  
  454. /* fortran interface */
  455. int ps_cross_ (x, y, size)
  456. double *x, *y, *size; {
  457.      ps_cross (*x, *y, *size);
  458. }
  459.  
  460. void ps_diamond (x, y, side, r, g, b, outline)
  461. double x, y, side;
  462. int r, g, b;
  463. int outline; {    /* see circle */
  464.     int ix, iy, ds;
  465.     
  466.     side *= (1.0/M_SQRT2);
  467.     ds = rint (side * ps.scale);
  468.     ix = rint (x * ps.scale);
  469.     iy = rint ((y - side) * ps.scale);
  470.     if (r < 0)    /* Outline only */
  471.         fprintf (ps.fp, "%d %d %d D4\n", ds, ix, iy);
  472.     else if (r != g || g != b)    /* color */
  473.         fprintf (ps.fp, "%.3lg %.3lg %.3lg %d %d %d D%d\n", r * I_255, g * I_255, b * I_255, ds, ix, iy, outline+2);
  474.     else /* Grayshade only */
  475.         fprintf (ps.fp, "%.3lg %d %d %d D%d\n", r * I_255, ds, ix, iy, outline);
  476.     ps.npath = 0;
  477. }
  478.  
  479. /* fortran interface */
  480. int ps_diamond_ (x, y, side, r, g, b, outline)
  481. double *x, *y, *side;
  482. int *r, *g, *b;
  483. int *outline; {
  484.      ps_diamond (*x, *y, *side, *r, *g, *b, *outline);
  485. }
  486.  
  487. void ps_star (x, y, side, r, g, b, outline)
  488. double x, y, side;
  489. int r, g, b;
  490. int outline; {    /* see circle */
  491.     int ix, iy, ds;
  492.     
  493.     ds = rint (side * ps.scale);
  494.     ix = rint (x * ps.scale);
  495.     iy = rint (y * ps.scale);
  496.     if (r < 0)    /* Outline only */
  497.         fprintf (ps.fp, "%d %d %d E4\n", ds, ix, iy);
  498.     else if (r != g || g != b)    /* color */
  499.         fprintf (ps.fp, "%.3lg %.3lg %.3lg %d %d %d E%d\n", r * I_255, g * I_255, b * I_255, ds, ix, iy, outline+2);
  500.     else /* Grayshade only */
  501.         fprintf (ps.fp, "%.3lg %d %d %d E%d\n", r * I_255, ds, ix, iy, outline);
  502.     ps.npath = 0;
  503. }
  504.  
  505. /* fortran interface */
  506. int ps_star_ (x, y, side, r, g, b, outline)
  507. double *x, *y, *side;
  508. int *r, *g, *b;
  509. int *outline; {
  510.      ps_star (*x, *y, *side, *r, *g, *b, *outline);
  511. }
  512.  
  513. void ps_hexagon (x, y, side, r, g, b, outline)
  514. double x, y, side;
  515. int r, g, b;
  516. int outline; {    /* see circle */
  517.     int ix, iy, ds;
  518.     
  519.     ds = rint (side * ps.scale);
  520.     ix = rint (x * ps.scale);
  521.     iy = rint (y * ps.scale);
  522.     if (r < 0)    /* Outline only */
  523.         fprintf (ps.fp, "%d %d %d H4\n", ds, ix, iy);
  524.     else if (r != g || g != b)    /* color */
  525.         fprintf (ps.fp, "%.3lg %.3lg %.3lg %d %d %d H%d\n", r * I_255, g * I_255, b * I_255, ds, ix, iy, outline+2);
  526.     else /* Grayshade only */
  527.         fprintf (ps.fp, "%.3lg %d %d %d H%d\n", r * I_255, ds, ix, iy, outline);
  528.     ps.npath = 0;
  529. }
  530.  
  531. /* fortran interface */
  532. int ps_hexagon_ (x, y, side, r, g, b, outline)
  533. double *x, *y, *side;
  534. int *r, *g, *b;
  535. int *outline; {
  536.      ps_hexagon (*x, *y, *side, *r, *g, *b, *outline);
  537. }
  538.  
  539. void ps_ellipse (x, y, angle, major, minor, r, g, b, outline)
  540. double x, y, angle, major, minor;
  541. int r, g, b, outline; {
  542.     int ir;
  543.     double aspect;
  544.     
  545.     /* Feature: Pen thickness also affected by ascpect ratio */
  546.     
  547.     fprintf (ps.fp, "V %d %d T", (int) rint (x * ps.scale), (int) rint (y * ps.scale));
  548.     if (angle != 0.0) fprintf (ps.fp, " %lg R", angle);
  549.     aspect = minor / major;
  550.     fprintf (ps.fp, " 1 %lg scale\n", aspect);
  551.     ir = rint (major * ps.scale);
  552.     if (r < 0)    /* Outline only */
  553.         fprintf (ps.fp, " 0 0 %d C4 U\n", ir);
  554.     else if (r != g || g != b)    /* color */
  555.         fprintf (ps.fp, " %.3lg %.3lg %.3lg 0 0 %d C%d U\n", r * I_255, g * I_255, b * I_255, ir, outline + 2);
  556.     else /* Grayshade only */
  557.         fprintf (ps.fp, " %.3lg 0 0 %d C%d U\n", r * I_255, ir, outline);
  558. }
  559.  
  560. /* fortran interface */
  561. int ps_ellipse_ (x, y, angle, major, minor, r, g, b, outline)
  562. double *x, *y, *angle, *major, *minor;
  563. int *r, *g, *b, *outline; {
  564.      ps_ellipse (*x, *y, *angle, *major, *minor, *r, *g, *b, *outline);
  565. }
  566.  
  567. void ps_image (x, y, xsize, ysize, buffer, nx, ny, nbits)
  568. double x, y, xsize, ysize;
  569. unsigned char *buffer;
  570. int nx, ny, nbits; {
  571.     /* Plots a bitmapped image. Each pixel is described by
  572.      * a hexadecimal number, which may take on values from
  573.      * 00(0) to FF(255).
  574.      * nbits is no of bits/pixel. Can be 8,4, or 1.
  575.      * Eg. if 1 is used, the each element of buffer provides
  576.      * shade info for 8 pixels, going from left to right.
  577.      * Note that nx refers to number of buffer values, not pixels.
  578.      * nx must be an integral of 8/nbits.
  579.      */
  580.     if (ps.hex_image)
  581.         ps_image_hex (x, y, xsize, ysize, buffer, nx, ny, nbits);
  582.     else
  583.         ps_image_bin (x, y, xsize, ysize, buffer, nx, ny, nbits);
  584. }
  585.  
  586. int ps_image_hex (x, y, xsize, ysize, buffer, nx, ny, nbits)
  587. double x, y, xsize, ysize;
  588. unsigned char *buffer;
  589. int nx, ny, nbits; {
  590.     /* Write output image using hex notation */
  591.  
  592.     char hex[16], pixel[80];
  593.     int ix, iy, lx, ly, mx, i, j, kk, jj, width;
  594.     
  595.     hex[0] = '0';    hex[1] = '1';    hex[2] = '2';    hex[3] = '3';
  596.     hex[4] = '4';    hex[5] = '5';    hex[6] = '6';    hex[7] = '7';
  597.     hex[8] = '8';    hex[9] = '9';    hex[10] = 'A';    hex[11] = 'B';
  598.     hex[12] = 'C';    hex[13] = 'D';    hex[14] = 'E';    hex[15] = 'F';
  599.     
  600.     ix = rint (x * ps.scale);
  601.     iy = rint (y * ps.scale);
  602.     lx = rint (xsize * ps.scale);
  603.     ly = rint (ysize * ps.scale);
  604.     mx = nx * 8 / nbits;
  605.     fprintf (ps.fp, "\n%% Start of hex monochrome image\n");
  606.     fprintf (ps.fp, "V N %d %d T %d %d scale\n", ix, iy, lx, ly);
  607.     fprintf (ps.fp, "%d %d 8 div mul ceiling cvi string /pstr exch def\n", mx, nbits);
  608.     fprintf (ps.fp, "%d %d %d [%d 0 0 %d 0 %d] {currentfile pstr readhexstring pop} image\n",
  609.         mx, ny, nbits, mx, -ny, ny);
  610.     
  611.     width = (nx > 40) ? 80 : 2 * nx;
  612.     kk = 0;
  613.     for (j = jj = 0; j < ny; j++) {
  614.         for (i = 0; i < nx; i++, jj++) {
  615.             pixel[kk++] = hex[buffer[jj]/16];
  616.             pixel[kk++] = hex[buffer[jj]%16];
  617.             if (kk == width) {
  618.                 for (kk = 0; kk < width; kk++) putc (pixel[kk], ps.fp);
  619.                 putc ('\n', ps.fp);
  620.                 kk = 0;
  621.             }
  622.         }
  623.     }
  624.     if (kk > 0) {
  625.         for (i = 0; i < kk; i++) putc (pixel[i], ps.fp);
  626.         putc ('\n', ps.fp);
  627.     }
  628.     fprintf (ps.fp, "U\n%% End of image\n\n");
  629. }
  630.  
  631. int ps_image_bin (x, y, xsize, ysize, buffer, nx, ny, nbits)
  632. double x, y, xsize, ysize;
  633. unsigned char *buffer;
  634. int nx, ny, nbits; {
  635.     /* Write output image using bin notation */
  636.     int ix, iy, lx, ly, mx;
  637.     
  638.     ix = rint (x * ps.scale);
  639.     iy = rint (y * ps.scale);
  640.     lx = rint (xsize * ps.scale);
  641.     ly = rint (ysize * ps.scale);
  642.     mx = nx * 8 / nbits;
  643.     fprintf (ps.fp, "\n%% Start of binary monochrome image\n");
  644.     fprintf (ps.fp, "V N %d %d T %d %d scale\n", ix, iy, lx, ly);
  645.     fprintf (ps.fp, "%d %d 8 div mul ceiling cvi string /pstr exch def\n", mx, nbits);
  646.     fprintf (ps.fp, "%d %d %d [%d 0 0 %d 0 %d] {currentfile pstr readstring pop} image\n",
  647.         mx, ny, nbits, mx, -ny, ny);
  648.     
  649.     fwrite ((char *)buffer, sizeof (unsigned char), nx * ny, ps.fp);
  650.     fprintf (ps.fp, "\nU\n%% End of image\n\n");
  651. }
  652.  
  653. /* fortran interface */
  654. int ps_image_ (x, y, xsize, ysize, buffer, nx, ny, nbits, nlen)
  655. double *x, *y, *xsize, *ysize;
  656. unsigned char *buffer;
  657. int nlen;
  658. int *nx, *ny, *nbits; {
  659.     ps_image (*x, *y, *xsize, *ysize, buffer, *nx, *ny, *nbits);
  660. }
  661.  
  662. void ps_imagefill (x, y, n, image_no, imagefile, invert, image_size, outline)
  663. double x[], y[];
  664. double image_size;    /* Size of image on page in inches */
  665. int n;            /* No of points in path */
  666. int image_no;        /* no of image (1-32) or user (0) */
  667. char *imagefile;    /* Name of image file if image == 0 */
  668. int invert;        /* If invert == TRUE we interchange black and white pixels */
  669. int outline; {        /* TRUE will draw outline, -1 means clippath already in place */
  670.     int i, j, ix, iy, no, n_times = 0;
  671.     char op[15];
  672.     double xx, yy, xmin, xmax, ymin, ymax;
  673.     
  674.     image_no--;    /* Frome 1-32 to 0-31 */
  675.     if (image_no < 0) image_no = 32;    /* Usersupplied image */
  676.     if (ps_pattern_status[image_no][invert] != 1) {
  677.         no = (image_no == 32) ? -1 : image_no+1;
  678.         ps_imagefill_init (no, imagefile, invert, image_size);
  679.     }
  680.     
  681.     ps_comment ("\n%Start of user imagefill pattern");
  682.     if (invert)
  683.         sprintf (op, "fillimage%di\0", image_no);
  684.     else
  685.         sprintf (op, "fillimage%d\0", image_no);
  686.     
  687.     /* Print out clip-path */
  688.     
  689.     if (outline >= 0) ps_clipon (x, y, n, -1, -1, -1, 3);
  690.     
  691.     /* Find extreme bounds for area */
  692.     
  693.     xmin = xmax = x[0];
  694.     ymin = ymax = y[0];
  695.     for (i = 1; i < n; i++) {
  696.         xmin = MIN (xmin, x[i]);
  697.         ymin = MIN (ymin, y[i]);
  698.         xmax = MAX (xmax, x[i]);
  699.         ymax = MAX (ymax, y[i]);
  700.     }
  701.     
  702.     if (image_size <= 0.0) image_size = 64.0 / ps.scale;    /* Use device resolution */
  703.  
  704.     for (j = (int) floor (ymin / image_size); j <= (int) ceil (ymax / image_size); j++) {
  705.         yy = j * image_size;
  706.         for (i = (int) floor (xmin / image_size); i <= (int) ceil (xmax / image_size); i++) {
  707.             xx = i * image_size;
  708.             ix = rint (xx * ps.scale);
  709.             iy = rint (yy * ps.scale);
  710.             fprintf (ps.fp, "%d %d", ix, iy);
  711.             n_times++;
  712.             (n_times%5) ? putc (' ', ps.fp) : putc ('\n', ps.fp);
  713.             /* Prevent stack from getting too full by flushing every 200 times */
  714.                         if (!(n_times%200)) { fprintf (ps.fp, "200 {%s} repeat\n", op); n_times = 0;} 
  715.         }
  716.     }
  717.     if (n_times%5) putc ('\n', ps.fp);
  718.     fprintf (ps.fp, "%d {%s} repeat\n", n_times, op);
  719.     if (outline > 0) fprintf (ps.fp, "clippath S\n");
  720.     ps_clipoff ();
  721.     ps_comment ("End of user imagefill pattern\n");
  722. }
  723.  
  724. void ps_imagefill_init (image_no, imagefile, invert, image_size)
  725. double image_size;    /* Size of image on page in inches */
  726. int image_no;        /* no of image (1-32) or user (0) */
  727. int invert;        /* If invert == TRUE we interchange black and white pixels */
  728. char *imagefile; {    /* Name of image file if image == 0 */
  729.    char *gmt_data_path;  /*  variable pointing to directory for patterns  */
  730.     int i, nx, ny, dx, dump = FALSE;
  731.     char *string, tmp[65], name[10], file[512];
  732. /*  Added for OS/2 [but works under unix]         */
  733.    gmt_data_path = getenv (GMTDATAPATH); /* GMTDATAPATH defined in "gmt_os2.h" */
  734.     
  735.     if (image_size <= 0.0) {    /* Use device resolution */
  736.         dx = 64;
  737.         image_size = 64.0 / ps.scale;
  738.     }
  739.     else
  740.         dx = rint (image_size * ps.scale);
  741.     
  742.     image_no--;    /* Frome 1-32 to 0-31 */
  743.     if (image_no < 0) image_no = 32;
  744.     if (ps_pattern_status[image_no][invert]) return;    /* Already done this */
  745.     
  746.     if (image_no >= 0 && image_no < N_PATTERNS && ps_pattern_status[image_no][invert] == 0) {
  747.         sprintf (file, "%s/ps_pattern.%d\0", gmt_data_path, image_no);
  748. /*    -----------Original GMT code; modified for OS/2----------- */
  749. /*        sprintf (file, "%s/ps_pattern.%d\0", LIBDIR, image_no);    */
  750.         string = get_icon (file, &nx, &ny, invert);
  751.     }
  752.     else if (image_no == 32 && ps_pattern_status[32][invert] == 0)
  753.         string = get_icon (imagefile, &nx, &ny, invert);
  754.     else if (ps_pattern_status[image_no][invert] == 1) {
  755.         nx = ps_pattern_nx[image_no][invert];
  756.         ny = ps_pattern_ny[image_no][invert];
  757.         dx = ps_pattern_dx[image_no][invert];
  758.     }
  759.     ps_comment ("\n%Start of user imagefill pattern definition");
  760.     if (invert)
  761.         sprintf (name, "image%di\0", image_no);
  762.     else
  763.         sprintf (name, "image%d\0", image_no);
  764.     if (ps_pattern_status[image_no][invert] == 0) {
  765.         fprintf (ps.fp, "/%s <\n", name);
  766.         ps_pattern_status[image_no][invert] = 1;
  767.         ps_pattern_nx[image_no][invert] = nx;
  768.         ps_pattern_ny[image_no][invert] = ny;
  769.         ps_pattern_dx[image_no][invert] = dx;
  770.         dump = TRUE;
  771.     }
  772.     if (dump) {
  773.         for (i = 0; i < nx * ny / 256; i++) {
  774.             strncpy (tmp, &string[i*64], 64);
  775.             tmp[64] = 0;
  776.             fprintf (ps.fp, "\t%s\n", tmp);
  777.         }
  778.         fprintf (ps.fp, "> def\n");
  779.     }
  780.     fprintf (ps.fp, "/fill%s { V T %d dup scale %d %d 1 [%d 0 0 %d 0 %d] {%s} image U} def\n", name, dx, nx, ny, nx, -ny, ny, name);
  781.     if (dump) free (string);
  782.     
  783.     ps_comment ("End of user imagefill pattern definition\n");
  784. }
  785.  
  786. void ps_imagefill_cleanup () {
  787.     int image_no;
  788.     
  789.     for (image_no = 0; image_no < 32; image_no++) {
  790.         if (ps_pattern_status[image_no][0]) {
  791.             fprintf (ps.fp, "currentdict /image%d undef\n", image_no);
  792.             fprintf (ps.fp, "currentdict /fillimage%d undef\n", image_no);
  793.         }
  794.         if (ps_pattern_status[image_no][1]) {
  795.             fprintf (ps.fp, "currentdict /image%di undef\n", image_no);
  796.             fprintf (ps.fp, "currentdict /fillimage%di undef\n", image_no);
  797.         }
  798.     }
  799. }
  800.  
  801. /* fortran interface */
  802. int ps_imagefill_ (x, y, n, image_no, imagefile, invert, image_size, outline, nlen)
  803. double x[], y[];
  804. double *image_size; 
  805. int *n;
  806. int *image_no; 
  807. int *invert; 
  808. char *imagefile;
  809. int nlen;
  810. int *outline; {
  811.      ps_imagefill (x, y, *n, *image_no, imagefile, *invert, *image_size, *outline);
  812. }
  813.  
  814. void ps_imagergb (x, y, xsize, ysize, buffer, nx, ny)
  815. double x, y, xsize, ysize;
  816. unsigned char *buffer;
  817. int nx, ny; {
  818.     /* Plots a 24bit bitmapped image using three calls to image 
  819.        called rimage, gimage, bimage.  These will be defined and
  820.        undefined when psto24 is run.
  821.      * Temporary version untill colorimage is defined
  822.      */
  823.     
  824.     if (ps.hex_image)
  825.         ps_imagergb_hex (x, y, xsize, ysize, buffer, nx, ny);
  826.     else
  827.         ps_imagergb_bin (x, y, xsize, ysize, buffer, nx, ny);
  828. }
  829.  
  830. int ps_imagergb_hex (x, y, xsize, ysize, buffer, nx, ny)
  831. double x, y, xsize, ysize;
  832. unsigned char *buffer;
  833. int nx, ny; {
  834.     /* Writes output image using hex notation */ 
  835.     
  836.     char hex[16], pixel[80];
  837.     int ix, iy, lx, ly, i, j, kk, jj, color;
  838.     
  839.     hex[0] = '0';    hex[1] = '1';    hex[2] = '2';    hex[3] = '3';
  840.     hex[4] = '4';    hex[5] = '5';    hex[6] = '6';    hex[7] = '7';
  841.     hex[8] = '8';    hex[9] = '9';    hex[10] = 'A';    hex[11] = 'B';
  842.     hex[12] = 'C';    hex[13] = 'D';    hex[14] = 'E';    hex[15] = 'F';
  843.     ix = rint (x * ps.scale);
  844.     iy = rint (y * ps.scale);
  845.     lx = rint (xsize * ps.scale);
  846.     ly = rint (ysize * ps.scale);
  847.     fprintf (ps.fp, "\n%% Start of hex psto24 rgb colorimage\n");
  848.     fprintf (ps.fp, "V N %d %d T %d %d scale\n", ix, iy, lx, ly);
  849.     fprintf (ps.fp, "%d string /pstr exch def\n", nx);
  850.     
  851.     for (color = jj = 0; color < 3; color++) {
  852.         fprintf (ps.fp, "psto24pass %d eq\n", color);
  853.         fprintf (ps.fp, "{%d %d 8 [%d 0 0 %d 0 %d] {currentfile pstr readhexstring pop} image}\n",
  854.             nx, ny, nx, -ny, ny);
  855.         fprintf (ps.fp, "{%d {currentfile pstr readhexstring pop pop} repeat}\n", ny);
  856.         fprintf (ps.fp, "ifelse\n");
  857.         kk = 0;
  858.         for (j = 0; j < ny; j++) {
  859.             for (i = 0; i < nx; i++, jj++) {
  860.                 pixel[kk++] = hex[buffer[jj]/16];
  861.                 pixel[kk++] = hex[buffer[jj]%16];
  862.                 if (kk == 80) {
  863.                     for (kk = 0; kk < 80; kk++) putc (pixel[kk], ps.fp);
  864.                     putc ('\n', ps.fp);
  865.                     kk = 0;
  866.                 }
  867.             }
  868.         }
  869.         if (kk > 0) {
  870.             for (i = 0; i < kk; i++) putc (pixel[i], ps.fp);
  871.             putc ('\n', ps.fp);
  872.         }
  873.     }
  874.     fprintf (ps.fp, "U\n%% End of imagergb\n\n");
  875. }
  876.  
  877. int ps_imagergb_bin (x, y, xsize, ysize, buffer, nx, ny)
  878. double x, y, xsize, ysize;
  879. unsigned char *buffer;
  880. int nx, ny; {
  881.     /* Writes output image using bin notation */ 
  882.     
  883.     int ix, iy, lx, ly, color;
  884.     
  885.     ix = rint (x * ps.scale);
  886.     iy = rint (y * ps.scale);
  887.     lx = rint (xsize * ps.scale);
  888.     ly = rint (ysize * ps.scale);
  889.     fprintf (ps.fp, "\n%% Start of binary psto24 colorimage\n");
  890.     fprintf (ps.fp, "V N %d %d T %d %d scale\n", ix, iy, lx, ly);
  891.     fprintf (ps.fp, "%d string /pstr exch def\n", nx);
  892.     
  893.     for (color = 0; color < 3; color++) {
  894.         fprintf (ps.fp, "psto24pass %d eq\n", color);
  895.         fprintf (ps.fp, "{%d %d 8 [%d 0 0 %d 0 %d] {currentfile pstr readstring pop} image}\n",
  896.             nx, ny, nx, -ny, ny);
  897.         fprintf (ps.fp, "{%d {currentfile pstr readhexstring pop pop} repeat}\n", ny);
  898.         fprintf (ps.fp, "ifelse\n");
  899.         fwrite ((char *)buffer, sizeof (unsigned char), nx * ny, ps.fp);
  900.     }
  901.     fprintf (ps.fp, "\nU\n%% End of imagergb\n\n");
  902. }
  903.  
  904. /* fortran interface */
  905. int ps_imagergb_ (x, y, xsize, ysize, buffer, nx, ny, nlen)
  906. double *x, *y, *xsize, *ysize;
  907. unsigned char *buffer;
  908. int nlen;
  909. int *nx, *ny; {
  910.     ps_imagergb (*x, *y, *xsize, *ysize, buffer, *nx, *ny);
  911. }
  912.  
  913. int ps_line (x, y, n, type, close, split)
  914. double *x, *y;
  915. int n, type;    /* type: 1 means new anchor point, 2 means stroke line, 3 = both */
  916. int close;    /* TRUE if a closed polygon */
  917. int split; {    /* TRUE if we can split line segment into several sections */
  918.     int i, *ix, *iy, trim = FALSE;
  919.     char move = 'M';
  920.     
  921.     /* First remove unneccessary points that have zero curvature */
  922.     
  923.     ix = (int *) malloc ((unsigned) (n * sizeof (int)));
  924.     iy = (int *) malloc ((unsigned) (n * sizeof (int)));
  925.     
  926.     if ((n = ps_shorten_path (x, y, n, ix, iy)) < 2) {
  927.         free ((char *)ix);
  928.         free ((char *)iy);
  929.         return (0);
  930.     }
  931.     
  932.     if (close && ix[0] == ix[n-1] && iy[0] == iy[n-1]) {
  933.         trim = TRUE;
  934.         n--;
  935.     }
  936.     
  937.     if (type < 0) {    /* Do not stroke before moveto */
  938.         type = -type;
  939.         move = 'm';
  940.     }
  941.     
  942.     if (type%2) {
  943.         fprintf (ps.fp, "%d %d %c\n", ix[0], iy[0], move);
  944.         ps.npath = 1;
  945.     }
  946.     else
  947.         fprintf (ps.fp, "%d %d D\n", ix[0] - ps.ix, iy[0] - ps.iy);
  948.     ps.ix = ix[0];
  949.     ps.iy = iy[0];
  950.         
  951.     if (!split) ps.max_path_length = MAX ((n + ps.clip_path_length), ps.max_path_length);
  952.     
  953.     for (i = 1; i < n; i++) {
  954.         fprintf (ps.fp, "%d %d D\n", ix[i] - ps.ix, iy[i] - ps.iy);
  955.         ps.ix = ix[i];
  956.         ps.iy = iy[i];
  957.         ps.npath++;
  958.         if ((ps.npath + ps.clip_path_length) > ps.v1_path_length_limit && split) {
  959.             fprintf (ps.fp, "S %d %d M\n", ps.ix, ps.iy);
  960.             ps.npath = 1;
  961.             close = FALSE;
  962.             if (trim) {    /* Restore the duplicate point since close no longer is TRUE */
  963.                 n++;
  964.                 trim = FALSE;
  965.             }
  966.         }
  967.     }
  968.     if (close) fprintf (ps.fp, "P");    /* Close the path */
  969.     if (type > 1) {
  970.         fprintf (ps.fp, " S\n");    /* Stroke the path */
  971.         ps.npath = 0;
  972.     }
  973.     else if (close)
  974.         fprintf (ps.fp, "\n");
  975.     
  976.     free ((char *)ix);
  977.     free ((char *)iy);
  978.     
  979.     return (n);
  980. }
  981.  
  982. /* fortran interface */
  983. int ps_line_ (x, y, n, type, close, split)
  984. double x[], y[];
  985. int *n, *type;
  986. int *close, *split; {
  987.     ps_line (x, y, *n, *type, *close, *split);
  988. }
  989.  
  990. int ps_shorten_path (x, y, n, ix, iy)
  991. double x[], y[];
  992. int n;
  993. int ix[], iy[]; {
  994.     double old_slope, new_slope, dx, dy, old_dir, new_dir;
  995.     int i, j, k, *xx, *yy, fixed;
  996.     
  997.     if (n < 2) return (0);
  998.     
  999.     xx = (int *) malloc ( (unsigned) (n * sizeof (int)));
  1000.     yy = (int *) malloc ( (unsigned) (n * sizeof (int)));
  1001.     
  1002.     xx[0] = rint (x[0] * ps.scale);
  1003.     yy[0] = rint (y[0] * ps.scale);
  1004.     
  1005.     for (i = j = 1; i < n; i++) {
  1006.         xx[j] = rint (x[i] * ps.scale);
  1007.         yy[j] = rint (y[i] * ps.scale);
  1008.         if (xx[j] != xx[j-1] || yy[j] != yy[j-1]) j++;
  1009.     }
  1010.     n = j;
  1011.     
  1012.     if (n < 2) {
  1013.         free ((char *)xx);
  1014.         free ((char *)yy);
  1015.         return (0);
  1016.     }
  1017.     
  1018.     ix[0] = xx[0];    iy[0] = yy[0];    k = 1;
  1019.     
  1020.     dx = xx[1] - xx[0];
  1021.     dy = yy[1] - yy[0];
  1022.     fixed = (dx == 0.0 && dy == 0.0);
  1023.     old_slope = (fixed) ? 1.01e100 : ((dx == 0) ? copysign (1.0e100, dy) : dy / dx);
  1024.     old_dir = 1;
  1025.     
  1026.     for (i = 1; i < n-1; i++) {
  1027.         dx = xx[i+1] - xx[i];
  1028.         dy = yy[i+1] - yy[i];
  1029.         fixed = (dx == 0.0 && dy == 0.0);
  1030.         new_slope = (fixed) ? 1.01e100 : ((dx == 0) ? copysign (1.0e100, dy) : dy / dx);
  1031.         if (fixed) continue;    /* Didnt move */
  1032.         
  1033.         new_dir = (dx >= 0.0) ? 1 : -1;
  1034.         if (new_slope != old_slope || new_dir != old_dir) {
  1035.             ix[k] = xx[i];
  1036.             iy[k] = yy[i];
  1037.             k++;
  1038.             old_slope = new_slope;
  1039.             old_dir = new_dir;
  1040.         }
  1041.     }
  1042.     dx = xx[n-1] - xx[n-2];
  1043.     dy = yy[n-1] - yy[n-2];
  1044.     fixed = (dx == 0.0 && dy == 0.0 && (k > 1 && ix[k-1] == xx[n-1] && iy[k-1] == yy[n-1]));    /* Didnt move */
  1045.     if (!fixed) {
  1046.         ix[k] = xx[n-1];
  1047.         iy[k] = yy[n-1];
  1048.         k++;
  1049.     }
  1050.     
  1051.     free ((char *)xx);
  1052.     free ((char *)yy);
  1053.     
  1054.     return (k);
  1055. }
  1056.  
  1057. /* fortran interface */
  1058. int ps_shorten_path_ (x, y, n, ix, iy)
  1059. double x[], y[];
  1060. int *n;
  1061. int ix[], iy[]; {
  1062.     ps_shorten_path (x, y, *n, ix, iy);
  1063. }
  1064.  
  1065. void ps_pie (x, y, radius, az1, az2, r, g, b, outline)
  1066. double x, y, radius, az1, az2;
  1067. int r, g, b;
  1068. int outline; {
  1069.     int ix, iy, ir;
  1070.     
  1071.     ix = rint (x * ps.scale);
  1072.     iy = rint (y * ps.scale);
  1073.     ir = rint (radius * ps.scale);
  1074.     if (r < 0)    /* Outline only */
  1075.         fprintf (ps.fp, "%d %d M %d %d %d %lg %lg P4\n",
  1076.             ix, iy, ix, iy, ir, az1, az2);
  1077.     if (r != g || g != b)    /* color */
  1078.         fprintf (ps.fp, "%d %d M %.3lg %.3lg %.3lg %d %d %d %lg %lg P%d\n",
  1079.             ix, iy, r * I_255, g * I_255, b * I_255, ix, iy, ir, az1, az2, outline+2);
  1080.     else /* Grayshade */
  1081.         fprintf (ps.fp, "%d %d M %.3lg %d %d %d %lg %lg P%d\n", ix, iy, r * I_255, ix, iy, ir, az1, az2, outline);
  1082.     ps.npath = 0;
  1083. }
  1084.  
  1085. /* fortran interface */
  1086. int ps_pie_ (x, y, radius, az1, az2, r, g, b, outline)
  1087. double *x, *y, *radius, *az1, *az2;
  1088. int *r, *g, *b;
  1089. int *outline; {
  1090.      ps_pie (*x, *y, *radius, *az1, *az2, *r, *g, *b, *outline);
  1091. }
  1092.  
  1093. void ps_plot (x, y, pen)
  1094. double x, y;
  1095. int pen; {
  1096.     int ix, iy, idx, idy;
  1097.     
  1098.     ix = rint (x*ps.scale);
  1099.     iy = rint (y*ps.scale);
  1100.     if (abs (pen) == 2) {    /* Convert absolute draw to relative draw */
  1101.         idx = ix - ps.ix;
  1102.         idy = iy - ps.iy;
  1103.         if (idx == 0 && idy == 0) return;
  1104.         fprintf (ps.fp, "%d %d D\n", idx, idy);
  1105.         ps.npath++;
  1106.     }
  1107.     else {
  1108.         idx = ix;
  1109.         idy = iy;
  1110.         fprintf (ps.fp, "%d %d M\n", idx, idy);
  1111.         ps.npath = 1;
  1112.     }
  1113.     if (pen == -2) fprintf (ps.fp, "S\n");
  1114.     ps.ix = ix;
  1115.     ps.iy = iy;
  1116.     if ((ps.npath + ps.clip_path_length) > ps.v1_path_length_limit) {
  1117.         fprintf (ps.fp, "S %d %d M\n", ix, iy);
  1118.         ps.npath = 1;
  1119.     }
  1120. }
  1121.  
  1122. /* fortran interface */
  1123. int ps_plot_ (x, y, pen)
  1124. double *x, *y;
  1125. int *pen; {
  1126.     ps_plot (*x, *y, *pen);
  1127. }
  1128.  
  1129. void ps_plotend (lastpage)
  1130. int lastpage; {
  1131.  
  1132.     ps_imagefill_cleanup ();
  1133.     if (lastpage) {
  1134.         fprintf (ps.fp, "%%%%Trailer\n");
  1135.         fprintf (ps.fp, "%% Reset translations and scale and call showpage\n");
  1136.         fprintf (ps.fp, "S %d %d T", -(int) rint (ps.xoff * ps.scale), -(int) rint (ps.yoff * ps.scale));
  1137.         fprintf (ps.fp, " %lg %lg scale",
  1138.             ps.scale/(ps.points_pr_unit * ps.xscl), ps.scale/(ps.points_pr_unit * ps.yscl));
  1139.         if (ps.mode == 0) fprintf (ps.fp, " -90 R %d 0 T", -(int)rint (ps.p_width * ps.points_pr_unit));
  1140.         fprintf (ps.fp, " showpage\n\n");
  1141.         fprintf (ps.fp, "end\n");
  1142.     }
  1143.     else
  1144.         fprintf (ps.fp, "S\n");
  1145.     if (ps.fp != stdout) fclose (ps.fp);
  1146.     if (ps.max_path_length > ps.v1_path_length_limit) fprintf (stderr, "pslib Warning: Some polygons may have been too long (%d)!\n", ps.max_path_length);
  1147. }
  1148.  
  1149. /* fortran interface */
  1150. int ps_plotend_ (lastpage)
  1151. int *lastpage; {
  1152.     ps_plotend (*lastpage);
  1153. }
  1154.  
  1155. int ps_plotinit (plotfile, overlay, mode, xoff, yoff, xscl, yscl, ncopies, dpi, unit, page_width, rgb, eps)
  1156. char *plotfile;        /* Name of output file or NULL for standard output */
  1157. double xoff, yoff;    /* Sets a new origin relative to old */
  1158. double xscl, yscl;    /* Global scaling, usually left to 1,1 */
  1159. double page_width;    /* Physical width of paper used (8.5 inch for regular laserplotter) */
  1160. int overlay;        /* FALSE means print headers and macros first */
  1161. int mode;        /* First bit 0 = Landscape, 1 = Portrait, Second bit 1 = no Euro
  1162.                Third bit 1 = hex image, 0 = bin image */
  1163. int ncopies;        /* Number of copies for this plot */
  1164. int dpi;        /* Plotter resolution in dots-per-inch */
  1165. int unit;        /* 0 = cm, 1 = inch, 2 = meter */
  1166. int rgb[];        /* array with Color of page (paper) */
  1167. struct EPS *eps;    /* !! Fortran version (ps_plotinit_) does not have this argument !! */
  1168. {
  1169.     int i, euro;
  1170.     time_t right_now, time();
  1171.     char openmode[2];
  1172.     double scl;
  1173.     
  1174.     ps.hex_image = (mode & 4) ? TRUE : FALSE;
  1175.     ps.v1_path_length_limit = MAX_PATH;
  1176.     ps.p_width = page_width;
  1177.     ps.font_no = 0;
  1178.     ps.scale = (double)dpi;    /* Dots pr. unit resolution of output device */
  1179.     ps.points_pr_unit = 72.0;
  1180.     if (unit == 0) ps.points_pr_unit /= 2.54;
  1181.     if (unit == 2) ps.points_pr_unit /= 0.0254;
  1182.     euro = (mode & 2);    /* If 2nd bit set then European character encoding is wanted */
  1183.     mode &= 1;
  1184.     if (plotfile == NULL || plotfile[0] == 0)
  1185.         ps.fp = stdout;
  1186.     else {
  1187.         (overlay) ? strcpy (openmode, "a") : strcpy (openmode, "w");
  1188.         if ((ps.fp = fopen (plotfile, openmode)) == NULL) {
  1189.             fprintf (stderr, "pslib: Cannot create/open file : %s\n", plotfile);
  1190.             return (-1);
  1191.         }
  1192.     }
  1193.     right_now = time ((time_t *)0);
  1194.     fprintf (ps.fp, "%%!PS-Adobe-3.0 EPSF-3.0\n");
  1195.     ps.mode = !(overlay && mode);
  1196.     ps.xscl = xscl;
  1197.     ps.xoff = xoff;
  1198.     ps.yscl = yscl;
  1199.     ps.yoff = yoff;
  1200.     strcpy (ps.bw_format, "%.3lg ");            /* Default format used for grayshade value */
  1201.     strcpy (ps.rgb_format, "%.3lg %.3lg %.3lg ");    /* Same, for color triplets */
  1202.     if (!overlay) {
  1203.         /* Write definitions of macros to plotfile */
  1204.         
  1205.         if (eps) {
  1206.             if (mode == 0)
  1207.                 fprintf (ps.fp, "%%%%BoundingBox: %d %d %d %d\n", eps->x0, eps->y0, eps->y1, eps->x1);
  1208.             else
  1209.                 fprintf (ps.fp, "%%%%BoundingBox: %d %d %d %d\n", eps->x0, eps->y0, eps->x1, eps->y1);
  1210.             fprintf (ps.fp, "%%%%Title: %s\n", eps->title);
  1211.             fprintf (ps.fp, "%%%%Creator: %s\n", eps->name);
  1212.             fprintf (ps.fp, "%%%%DocumentNeededResources: font");
  1213.             for (i = 0; eps->font[i]; i++) fprintf (ps.fp, " %s", eps->font[i]);
  1214.             fprintf (ps.fp, "\n");
  1215.         }
  1216.         else {
  1217.             fprintf (ps.fp, "%%%%BoundingBox: 0 0 612 792\n");
  1218.             fprintf (ps.fp, "%%%%Title: pslib v%lg document\n", Version);
  1219.             fprintf (ps.fp, "%%%%Creator: ???\n");
  1220.         }
  1221.         fprintf (ps.fp, "%%%%CreationDate: %s", ctime(&right_now));
  1222.         fprintf (ps.fp, "%%%%Orientation: Portrait\n");
  1223.         fprintf (ps.fp, "%%%%EndComments\n\n");
  1224.         
  1225.         fprintf (ps.fp, "%%%%BeginProlog\n\n");
  1226.         fprintf (ps.fp, "%% Begin pslib header\n\n");
  1227.         
  1228.         fprintf (ps.fp, "250 dict begin\n\n");
  1229.         fprintf (ps.fp, "/A /setgray load def\n");
  1230.         fprintf (ps.fp, "/B /setdash load def\n");
  1231.         fprintf (ps.fp, "/C /setrgbcolor load def\n");
  1232.         fprintf (ps.fp, "/D /rlineto load def\n");
  1233.         fprintf (ps.fp, "/E {dup stringwidth pop} bind def\n");
  1234.         fprintf (ps.fp, "/F /fill load def\n");
  1235.         fprintf (ps.fp, "/G /rmoveto load def\n");
  1236.         fprintf (ps.fp, "/L /lineto load def\n"); 
  1237.         fprintf (ps.fp, "/M {stroke moveto} bind def\n");
  1238.         fprintf (ps.fp, "/m {moveto} bind def\n");
  1239.         fprintf (ps.fp, "/N /newpath load def\n");
  1240.         fprintf (ps.fp, "/O {M {D} repeat P V C F U S} def\n");
  1241.         fprintf (ps.fp, "/o {M {D} repeat P V A F U S} def\n");
  1242.         fprintf (ps.fp, "/P /closepath load def\n");
  1243.         fprintf (ps.fp, "/Q {M {D} repeat P V C F U N} def\n");
  1244.         fprintf (ps.fp, "/q {M {D} repeat P V A F U N} def\n");
  1245.         fprintf (ps.fp, "/t {M {D} repeat P S} def\n");
  1246.         fprintf (ps.fp, "/R /rotate load def\n");
  1247.         fprintf (ps.fp, "/S /stroke load def\n");
  1248.         fprintf (ps.fp, "/T /translate load def\n");
  1249.         fprintf (ps.fp, "/U /grestore load def\n");
  1250.         fprintf (ps.fp, "/V /gsave load def\n");
  1251.         fprintf (ps.fp, "/W /setlinewidth load def\n");
  1252.         fprintf (ps.fp, "/X {M dup 0 D dup -0.5 mul dup G 0 exch D S} bind def\n");
  1253.         fprintf (ps.fp, "/Y {findfont exch scalefont setfont} bind def\n");
  1254.         fprintf (ps.fp, "/Z /show load def\n");
  1255.         fprintf (ps.fp, "/A0 {0 exch M 0 D D D D D 0 D P V A F U N} bind def\n");
  1256.         fprintf (ps.fp, "/A1 {0 exch M 0 D D D D D 0 D P V A F U S} bind def\n");
  1257.         fprintf (ps.fp, "/A2 {0 exch M 0 D D D D D 0 D P V C F U N} bind def\n");
  1258.         fprintf (ps.fp, "/A3 {0 exch M 0 D D D D D 0 D P V C F U S} bind def\n");
  1259.         fprintf (ps.fp, "/A4 {0 exch M 0 D D D D D 0 D P S} bind def\n");
  1260.         fprintf (ps.fp, "/C0 {0 360 arc V A F U N} bind def\n");
  1261.         fprintf (ps.fp, "/C1 {0 360 arc V A F U S} bind def\n");
  1262.         fprintf (ps.fp, "/C2 {0 360 arc V C F U N} bind def\n");
  1263.         fprintf (ps.fp, "/C3 {0 360 arc V C F U S} bind def\n");
  1264.         fprintf (ps.fp, "/C4 {0 360 arc S} bind def\n");
  1265.         fprintf (ps.fp, "/D0 {M 5 {dup} repeat D neg exch D neg exch neg D P V A F U N} bind def\n");
  1266.         fprintf (ps.fp, "/D1 {M 5 {dup} repeat D neg exch D neg exch neg D P V A F U S} bind def\n");
  1267.         fprintf (ps.fp, "/D2 {M 5 {dup} repeat D neg exch D neg exch neg D P V C F U N} bind def\n");
  1268.         fprintf (ps.fp, "/D3 {M 5 {dup} repeat D neg exch D neg exch neg D P V C F U S} bind def\n");
  1269.         fprintf (ps.fp, "/D4 {M 5 {dup} repeat D neg exch D neg exch neg D P S} bind def\n");
  1270.         fprintf (ps.fp, "/R0 {M dup 0 D exch 0 exch D neg 0 D P V A F U N} bind def\n");
  1271.         fprintf (ps.fp, "/R1 {M dup 0 D exch 0 exch D neg 0 D P V A F U S} bind def\n");
  1272.         fprintf (ps.fp, "/R2 {M dup 0 D exch 0 exch D neg 0 D P V C F U N} bind def\n");
  1273.         fprintf (ps.fp, "/R3 {M dup 0 D exch 0 exch D neg 0 D P V C F U S} bind def\n");
  1274.         fprintf (ps.fp, "/R4 {M dup 0 D exch 0 exch D neg 0 D P S} bind def\n");
  1275.         fprintf (ps.fp, "/S0 {M dup dup 0 D 0 exch D neg 0 D P V A F U N} bind def\n");
  1276.         fprintf (ps.fp, "/S1 {M dup dup 0 D 0 exch D neg 0 D P V A F U S} bind def\n");
  1277.         fprintf (ps.fp, "/S2 {M dup dup 0 D 0 exch D neg 0 D P V C F U N} bind def\n");
  1278.         fprintf (ps.fp, "/S3 {M dup dup 0 D 0 exch D neg 0 D P V C F U S} bind def\n");
  1279.         fprintf (ps.fp, "/S4 {M dup dup 0 D 0 exch D neg 0 D P S} bind def\n");
  1280.         fprintf (ps.fp, "/T0 {M dup 0 D dup -0.5 mul exch 0.866025 mul D P V A F U N} bind def\n");
  1281.         fprintf (ps.fp, "/T1 {M dup 0 D dup -0.5 mul exch 0.866025 mul D P V A F U S} bind def\n");
  1282.         fprintf (ps.fp, "/T2 {M dup 0 D dup -0.5 mul exch 0.866025 mul D P V C F U N} bind def\n");
  1283.         fprintf (ps.fp, "/T3 {M dup 0 D dup -0.5 mul exch 0.866025 mul D P V C F U S} bind def\n");
  1284.         fprintf (ps.fp, "/T4 {M dup 0 D dup -0.5 mul exch 0.866025 mul D P S} bind def\n");
  1285.         fprintf (ps.fp, "/I0 {M dup 0 D dup -0.5 mul exch -0.866025 mul D P V A F U N} bind def\n");
  1286.         fprintf (ps.fp, "/I1 {M dup 0 D dup -0.5 mul exch -0.866025 mul D P V A F U S} bind def\n");
  1287.         fprintf (ps.fp, "/I2 {M dup 0 D dup -0.5 mul exch -0.866025 mul D P V C F U N} bind def\n");
  1288.         fprintf (ps.fp, "/I3 {M dup 0 D dup -0.5 mul exch -0.866025 mul D P V C F U S} bind def\n");
  1289.         fprintf (ps.fp, "/I4 {M dup 0 D dup -0.5 mul exch -0.866025 mul D P S} bind def\n");
  1290.         fprintf (ps.fp, "/E0 {V T dup 0 exch M 0.726542528 mul -72 R dup 0 D 4 {72 R dup 0 D -144 R dup 0 D} repeat pop P V A F U N U} bind def\n");
  1291.         fprintf (ps.fp, "/E1 {V T dup 0 exch M 0.726542528 mul -72 R dup 0 D 4 {72 R dup 0 D -144 R dup 0 D} repeat pop P V A F U S U} bind def\n");
  1292.         fprintf (ps.fp, "/E2 {V T dup 0 exch M 0.726542528 mul -72 R dup 0 D 4 {72 R dup 0 D -144 R dup 0 D} repeat pop P V C F U N U} bind def\n");
  1293.         fprintf (ps.fp, "/E3 {V T dup 0 exch M 0.726542528 mul -72 R dup 0 D 4 {72 R dup 0 D -144 R dup 0 D} repeat pop P V C F U S U} bind def\n");
  1294.         fprintf (ps.fp, "/E4 {V T dup 0 exch M 0.726542528 mul -72 R dup 0 D 4 {72 R dup 0 D -144 R dup 0 D} repeat pop P S U} bind def\n");
  1295.         fprintf (ps.fp, "/H0 {V T dup dup 0.5 mul exch 0.866025404 mul M 5 {-60 R dup 0 D} repeat pop P V A F U N U} bind def\n");
  1296.         fprintf (ps.fp, "/H1 {V T dup dup 0.5 mul exch 0.866025404 mul M 5 {-60 R dup 0 D} repeat pop P V A F U S U} bind def\n");
  1297.         fprintf (ps.fp, "/H2 {V T dup dup 0.5 mul exch 0.866025404 mul M 5 {-60 R dup 0 D} repeat pop P V C F U N U} bind def\n");
  1298.         fprintf (ps.fp, "/H3 {V T dup dup 0.5 mul exch 0.866025404 mul M 5 {-60 R dup 0 D} repeat pop P V C F U S U} bind def\n");
  1299.         fprintf (ps.fp, "/H4 {V T dup dup 0.5 mul exch 0.866025404 mul M 5 {-60 R dup 0 D} repeat pop P S U} bind def\n");
  1300.         fprintf (ps.fp, "/P0 {arc P V A F U N} bind def\n");
  1301.         fprintf (ps.fp, "/P1 {arc P V A F U S} bind def\n");
  1302.         fprintf (ps.fp, "/P2 {arc P V C F U N} bind def\n");
  1303.         fprintf (ps.fp, "/P3 {arc P V C F U S} bind def\n");
  1304.         fprintf (ps.fp, "/P4 {arc P S} bind def\n");
  1305.         fprintf (ps.fp, "/a {P V A F U N} def\n");
  1306.         fprintf (ps.fp, "/b {P V A F U S} def\n");
  1307.         fprintf (ps.fp, "/c {P V C F U N} def\n");
  1308.         fprintf (ps.fp, "/d {P V C F U S} def\n");
  1309.         fprintf (ps.fp, "/p {P S} def\n");
  1310.     
  1311.         /* Define font macros (see pslib.h for details on how to add fonts) */
  1312.         
  1313.         for (i = 0; i < N_FONTS; i++) fprintf (ps.fp, "/F%d {/%s Y} bind def\n", i, ps_font_name[i]);
  1314.  
  1315.         if (euro) init_euro_header(eps);
  1316.  
  1317.         fprintf (ps.fp, "/#copies %d def\n\n", ncopies);
  1318.         fprintf (ps.fp, "%%%%EndProlog\n\n");
  1319.         
  1320.         fprintf (ps.fp, "%%%%BeginSetup\n\n");
  1321.         fprintf (ps.fp, "%% Init coordinate system and scales\n");
  1322.         scl = ps.points_pr_unit / ps.scale;
  1323.         fprintf (ps.fp, "%% Scale is originally set to %lg, which means that\n", scl);
  1324.         if (unit == 0) {    /* CM used as unit */
  1325.             /* ps.scale /= 2.54; */
  1326.             fprintf (ps.fp, "%% 1 cm on the paper equals %d Postscript units\n", (int)ps.scale);
  1327.         }
  1328.         else if (unit == 1)    /* INCH used as unit */
  1329.             fprintf (ps.fp, "%% 1 inch on the paper equals %d Postscript units\n", (int)ps.scale);
  1330.         else if (unit == 2) {    /* M used as unit */
  1331.             /* ps.scale /= 0.0254; */
  1332.             fprintf (ps.fp, "%% 1 m on the paper equals %d Postscript units\n", (int)ps.scale);
  1333.         }
  1334.         else {
  1335.             fprintf (stderr, "pslib: Measure unit not valid!\n");
  1336.             exit (-1);
  1337.         }
  1338.         
  1339.         xscl *= scl;
  1340.         yscl *= scl;
  1341.         if (mode == 0)    /* Landscape, 1 == Portrait */
  1342.             fprintf (ps.fp, "%d 0 T 90 R\n", (int)rint (ps.p_width * ps.points_pr_unit));
  1343.         fprintf (ps.fp, "%lg %lg scale\n", xscl, yscl);
  1344.     }
  1345.     if (!(xoff == 0.0 && yoff == 0.0)) fprintf (ps.fp, "%d %d T\n", (int)rint(xoff*ps.scale), (int)rint(yoff*ps.scale));
  1346.     ps_setpaint (0, 0, 0);
  1347.     fprintf (ps.fp, "%% End of pslib header\n");
  1348.     if (!overlay) fprintf (ps.fp, "%%%%EndSetup\n");
  1349.     if (!overlay && !(rgb[0] == rgb[1] && rgb[1] == rgb[2] && rgb[0] == 255)) {    /* Change background color */
  1350.         if (rgb[0] != rgb[1] || rgb[1] != rgb[2])
  1351.             fprintf (ps.fp, "clippath %.3lg %.3lg %.3lg C F N\n", rgb[0] * I_255, rgb[1] * I_255, rgb[2] * I_255);
  1352.         else
  1353.             fprintf (ps.fp, "clippath %.3lg A F N\n", rgb[0] * I_255);
  1354.     }
  1355.     
  1356.     /* Initialize global variables */
  1357.     
  1358.     ps.npath = ps.clip_path_length = ps.max_path_length = 0;
  1359.     memset ((char *) ps_pattern_status, 0, 2 * N_PATTERNS);
  1360.     return (0);
  1361. }
  1362.  
  1363. /* fortran interface */
  1364. int ps_plotinit_ (plotfile, overlay, mode, xoff, yoff, xscl, yscl, ncopies, dpi, unit, page_width, rgb, nlen)
  1365. char *plotfile;    
  1366. double *xoff, *yoff;
  1367. double *xscl, *yscl;
  1368. double *page_width;
  1369. int *overlay;
  1370. int *mode;
  1371. int *ncopies;
  1372. int *dpi;
  1373. int *unit;
  1374. int rgb[];
  1375. int nlen; {
  1376.      ps_plotinit (plotfile, *overlay, *mode, *xoff, *yoff, *xscl, *yscl, *ncopies, *dpi, *unit, *page_width, rgb, (struct EPS *)NULL);
  1377. }
  1378.  
  1379. void ps_plotr (x, y, pen)
  1380. double x, y;
  1381. int pen; {
  1382.     int ix, iy;
  1383.     
  1384.     ix = rint (x * ps.scale);
  1385.     iy = rint (y * ps.scale);
  1386.     if (ix == 0 && iy == 0) return;
  1387.     ps.npath++;
  1388.     if (abs (pen) == 2)
  1389.         fprintf (ps.fp, "%d %d D\n", ix, iy);
  1390.     else {
  1391.         fprintf (ps.fp, "%d %d G\n", ix, iy);
  1392.         ps.npath = 1;
  1393.     }
  1394.     if (pen == -2) fprintf (ps.fp, "S\n");
  1395.     ps.ix += ix;    /* Update absolute position */
  1396.     ps.iy += iy;
  1397. }
  1398.  
  1399. /* fortran interface */
  1400. int ps_plotr_ (x, y, pen)
  1401. double *x, *y;
  1402. int *pen; {
  1403.     ps_plotr (*x, *y, *pen);
  1404. }
  1405.  
  1406. void ps_polygon (x, y, n, r, g, b, outline)
  1407. double *x, *y;
  1408. int n, r, g, b;
  1409. int outline; {
  1410.     int split;
  1411.     char mode;
  1412.     
  1413.     split = (r < 0);    /* Can only split if we need outline only */
  1414.     if (outline >= 0) ps_line (x, y, n, 1, FALSE, split);    /* No stroke or close path yet */
  1415.     ps.npath = 0;
  1416.  
  1417.     ps.max_path_length = MAX ((n + ps.clip_path_length), ps.max_path_length);
  1418.     
  1419.     if (split) {    /* Outline only */
  1420.         mode = 'p';
  1421.         outline = 0;
  1422.     }
  1423.     else if (r != g || g != b) {
  1424.         mode = 'c';
  1425.         fprintf (ps.fp, ps.rgb_format, r * I_255, g * I_255, b * I_255);
  1426.     }
  1427.     else {
  1428.         mode = 'a';
  1429.         fprintf (ps.fp, ps.bw_format, r * I_255);
  1430.     }
  1431.     if (outline > 0) mode += outline;
  1432.     fprintf (ps.fp, "%c\n", mode);
  1433.     if (outline < 0) {
  1434.         fprintf (ps.fp, "\nN U\n%%Clipping is currently OFF\n");
  1435.         ps.clip_path_length = 0;
  1436.     }
  1437. }
  1438.  
  1439. /* fortran interface */
  1440. int ps_polygon_ (x, y, n, r, g, b, outline)
  1441. double x[], y[];
  1442. int *n, *r, *g, *b;
  1443. int *outline; {
  1444.     ps_polygon (x, y, *n, *r, *g, *b, *outline);
  1445. }
  1446.  
  1447.   
  1448. void ps_patch (x, y, np, r, g, b, outline)
  1449. double x[], y[];
  1450. int np, r, g, b;
  1451. int outline; {
  1452.     /* Like ps_polygon but intended for small polygons (< 20 points).  No checking for
  1453.      * shorter path by calling ps_shorten_path as in ps_polygon.
  1454.      *
  1455.      * Thus, the usage is (with xi,yi being absolute coordinate for point i and dxi the increment
  1456.      * from point i to i+1, and r,g,b in the range 0.0-1.0.  Here, n = np-1.  O means draw outline,
  1457.      * Q means no outline.  Upper case for rgb, lower case for gray.
  1458.      *
  1459.      *    r g b dx2 dy2 dx1 dy1 dx0 dy0 n x0 y0 Q
  1460.      *    r dx2 dy2 dx1 dy1 dx0 dy0 n x0 y0 q
  1461.      *    r g b dx1 dy1 dx0 dy0 n x0 y0 O
  1462.      *    r dx1 dy1 dx0 dy0 n x0 y0 o
  1463.      *    dx1 dy1 dx0 dy0 n x0 y0 t    (If r < 0 then outline only)
  1464.      */
  1465.      
  1466.     int i, n, n1, ix[20], iy[20];
  1467.     char mode;
  1468.     
  1469.     if (np > 20) {    /* Must call ps_polygon instead */
  1470.         ps_polygon ( x, y, np, r, g, b, outline);
  1471.         return;
  1472.     }
  1473.     
  1474.     ix[0] = rint (x[0] * ps.scale);    /* Convert inch to absolute pixel position for start of quadrilateral */
  1475.     iy[0] = rint (y[0] * ps.scale);
  1476.     
  1477.     for (i = n = 1, n1 = 0; i < np; i++) {    /* Same but check if new point represent a different pixel */
  1478.         ix[n] = rint (x[i] * ps.scale);
  1479.         iy[n] = rint (y[i] * ps.scale);
  1480.         if (ix[n] != ix[n1] || iy[n] != iy[n1]) n++, n1++;
  1481.     }
  1482.     if (ix[0] == ix[n1] && iy[0] == iy[n1]) n--, n1--;    /* Closepath will do this automatically */
  1483.     
  1484.     if (n < 3) return;    /* 2 points or less don't make a polygon */
  1485.     
  1486.     mode = (outline) ? 'O' : 'Q';
  1487.  
  1488.     if (r < 0)    /* Outline only */
  1489.         mode = 't';
  1490.     else if (r != g || r != b)    /* Must use color */
  1491.         fprintf (ps.fp, ps.rgb_format, r * I_255, g * I_255, b * I_255);    /* Convert from 0-255 to 0-1 */
  1492.     else {    /* Grayshade */
  1493.         mode += ('a' - 'A');    /* Change mode from upper to lower case for grayshade operator */
  1494.         fprintf (ps.fp, ps.bw_format, r * I_255);
  1495.     }
  1496.     
  1497.     n--;
  1498.     n1 = n;
  1499.     for (i = n - 1; i != -1; i--, n--) fprintf (ps.fp, "%d %d ", ix[n] - ix[i], iy[n] - iy[i]);
  1500.     fprintf (ps.fp, "%d %d %d %c\n", n1, ix[0], iy[0], mode);
  1501. }
  1502.  
  1503. /* fortran interface */
  1504.  
  1505. int ps_patch_ (x, y, n, r, g, b, outline)
  1506. double x[], y[];
  1507. int *n, *r, *g, *b, *outline; {
  1508.     ps_patch (x, y, *n, *r, *g, *b, *outline);
  1509. }
  1510.  
  1511. void ps_rect (x1, y1, x2, y2, r, g, b, outline)
  1512. double x1, y1, x2, y2;
  1513. int r, g, b;
  1514. int outline; {
  1515.     int ix, iy, idx, idy;
  1516.     
  1517.     ix = rint (x1 * ps.scale);
  1518.     iy = rint (y1 * ps.scale);
  1519.     idx = rint (x2 * ps.scale) - ix;
  1520.     idy = rint (y2 * ps.scale) - iy;
  1521.     if (r < 0) /* Outline only */
  1522.         fprintf (ps.fp, "%d %d %d %d R4\n", idy, idx, ix, iy);
  1523.     else if (r != g || g != b) /* color */
  1524.         fprintf (ps.fp, "%.3lg %.3lg %.3lg %d %d %d %d R%d\n", r * I_255, g * I_255, b * I_255, idy, idx, ix, iy, outline+2);
  1525.     else /* Grayshade */
  1526.         fprintf (ps.fp, "%.3lg %d %d %d %d R%d\n", r * I_255, idy, idx, ix, iy, outline);
  1527.     ps.npath = 0;
  1528. }
  1529.  
  1530. /* fortran interface */
  1531. int ps_rect_ (x1, y1, x2, y2, r, g, b, outline)
  1532. double *x1, *y1, *x2, *y2;
  1533. int *r, *g, *b;
  1534. int *outline; {
  1535.     ps_rect (*x1, *y1, *x2, *y2, *r, *g, *b, *outline);
  1536. }
  1537.  
  1538. void ps_rotatetrans (x, y, angle)
  1539. double x, y, angle; {
  1540.     int ix, iy;
  1541.     int go = FALSE;
  1542.     
  1543.     ix = rint (x * ps.scale);
  1544.     iy = rint (y * ps.scale);
  1545.     if (angle != 0.0) {
  1546.         fprintf (ps.fp, "%lg R", angle);
  1547.         go = TRUE;
  1548.     }
  1549.     if (ix != 0 || iy != 0) {
  1550.         if (go) putc (' ', ps.fp);
  1551.         fprintf (ps.fp, "%d %d T", ix, iy);
  1552.     }
  1553.     putc ('\n', ps.fp);
  1554. }
  1555.  
  1556. /* fortran interface */
  1557. int ps_rotatetrans_ (x, y, angle)
  1558. double *x, *y, *angle; {
  1559.      ps_rotatetrans (*x, *y, *angle);
  1560. }
  1561.  
  1562. void ps_setdash (pattern, offset)
  1563. char *pattern;    /* Line structure in Postscript units */
  1564. int offset; {    /* offset from plotpoint in " units */
  1565.     /* Examples:
  1566.      * pattern = "4 4", offset = 0:
  1567.      *   4 units of line, 4 units of space, start at current point
  1568.      * pattern = "5 3 1 3", offset = 2:
  1569.      *   5 units line, 3 units space, 1 unit line, 3 units space, start
  1570.      *    2 units from curr. point.
  1571.      */
  1572.     if (pattern)
  1573.         fprintf (ps.fp, "S [%s] %d B\n", pattern, offset);
  1574.     else
  1575.         fprintf (ps.fp, "S [] 0 B\n");    /* Reset to continous line */
  1576.     ps.npath = 0;
  1577. }
  1578.  
  1579. /* fortran interface */
  1580. int ps_setdash_ (pattern, offset, nlen)
  1581. char *pattern;
  1582. int nlen;
  1583. int *offset; {
  1584.     ps_setdash (pattern, *offset);
  1585. }
  1586.  
  1587. void ps_setfont (font_no)
  1588. int font_no; {
  1589.     if (font_no < 0 || font_no >= N_FONTS)
  1590.         fprintf (stderr, "pslib: Selected font out of range (%d), ignored\n", font_no);
  1591.     else
  1592.         ps.font_no = font_no;
  1593. }
  1594.  
  1595. /* fortran interface */
  1596. int ps_setfont_ (font_no)
  1597. int *font_no; {
  1598.     ps_setfont (*font_no);
  1599. }
  1600.  
  1601. void ps_setformat (n_decimals)
  1602. int n_decimals; {
  1603.     /* Sets nmber of decimals used for rgb/gray specifications [3] */
  1604.     if (n_decimals < 1 || n_decimals > 3)
  1605.         fprintf (stderr, "pslib: Selected decimals for color out of range (%d), ignored\n", n_decimals);
  1606.     else {
  1607.           sprintf (ps.bw_format, "%%.%dlf \0", n_decimals);
  1608.           sprintf (ps.rgb_format, "%%.%dlf %%.%dlf %%.%dlf \0", n_decimals, n_decimals, n_decimals);
  1609.       }
  1610. }
  1611.  
  1612. /* fortran interface */
  1613. int ps_setformat_ (n_decimals)
  1614. int *n_decimals; {
  1615.     ps_setformat (*n_decimals);
  1616. }
  1617.  
  1618. void ps_setline (linewidth)
  1619. int linewidth; {
  1620.     if (linewidth < 0)
  1621.         fprintf (stderr, "pslib: Selected linewidth is negative (%d), ignored\n", linewidth);
  1622.     else
  1623.         fprintf (ps.fp, "S %d W\n",linewidth);
  1624. }
  1625.  
  1626. /* fortan interface */
  1627. int ps_setline_ (linewidth)
  1628. int *linewidth; {
  1629.      ps_setline (*linewidth);
  1630. }
  1631.  
  1632. void ps_setpaint (r, g, b)
  1633. int r, g, b; {
  1634.     if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
  1635.         fprintf (stderr, "pslib: Selected color is out of range (%d/%d/%d), ignored\n", r, g, b);
  1636.     else {
  1637.         if (r != g || g != b)    /* color */
  1638.             fprintf (ps.fp, "S %.3lg %.3lg %.3lg C\n", (r * I_255), (g * I_255), (b * I_255));
  1639.         else
  1640.             fprintf (ps.fp, "S %.3lg A\n", (r * I_255));
  1641.     }
  1642. }
  1643.  
  1644. /* fortran interface */
  1645. int ps_setpaint_ (r, g, b)
  1646. int *r, *g, *b; {
  1647.      ps_setpaint (*r, *g, *b);
  1648. }
  1649.  
  1650. void ps_square (x, y, side, r, g, b, outline)
  1651. double x, y, side;
  1652. int r, g, b;
  1653. int outline; {    /* see circle */
  1654.     int ds, ix, iy;
  1655.     
  1656.     ds = rint (side * ps.scale);
  1657.     side *= 0.5;
  1658.     ix = rint ((x - side) * ps.scale);
  1659.     iy = rint ((y - side) * ps.scale);
  1660.     if (r < 0) /* Outline only */
  1661.         fprintf (ps.fp, "%d %d %d S4\n", ds, ix, iy);
  1662.     else if (r != g || g != b) /* color */
  1663.         fprintf (ps.fp, "%.3lg %.3lg %.3lg %d %d %d S%d\n", r * I_255, g * I_255, b * I_255, ds, ix, iy, outline+2);
  1664.     else /* Grayshade */
  1665.         fprintf (ps.fp, "%.3lg %d %d %d S%d\n", r * I_255, ds, ix, iy, outline);
  1666.     ps.npath = 0;
  1667. }
  1668.  
  1669. /* fortran interface */
  1670. int ps_square_ (x, y, side, r, g, b, outline)
  1671. double *x, *y, *side;
  1672. int *r, *g, *b;
  1673. int *outline; {
  1674.     ps_square (*x, *y, *side, *r, *g, *b, *outline);
  1675. }
  1676.  
  1677. void ps_text (x, y, pointsize, text, angle, justify, form)
  1678. double x, y, angle;
  1679. char *text;
  1680. int pointsize;
  1681. int justify;    /* indicates what x,y refers to, see fig */
  1682. int form; {    /* 0 = normal text, 1 = outline */
  1683.   /*
  1684.    *    9    10    11
  1685.    *   |----------------|
  1686.    *   5  <textstring>  7
  1687.    *   |----------------|
  1688.    *   1     2     3
  1689.    */
  1690.     char *tempstring, *piece, *piece2, *ptr, *string, op[16];
  1691.     int dy, i = 0, j, font;
  1692.     int sub, super, small, old_font;
  1693.     double height, small_size, size, scap_size, step, y0;
  1694.  
  1695.     if (strlen (text) >= 511) {
  1696.         fprintf (stderr, "pslib: text_item > 512 long!\n");
  1697.         return;
  1698.     }
  1699.     
  1700.     if (justify < 0)  {    /* Strip leading and trailing blanks */
  1701.         for (i = 0; text[i] == ' '; i++);
  1702.         for (j = strlen (text) - 1; text[j] == ' '; j--) text[j] = 0;
  1703.     }
  1704.     string = ps_prepare_text (&text[i]);    /* Check for escape sequences */
  1705.     
  1706.     justify = abs (justify);
  1707.       height = pointsize / ps.points_pr_unit;
  1708.       
  1709.       /* Got to anchor point */
  1710.       
  1711.       ps.npath = 0;
  1712.     ps.ix = rint (x*ps.scale);
  1713.     ps.iy = rint (y*ps.scale);
  1714.     fprintf (ps.fp, "%d %d M ", ps.ix, ps.iy);
  1715.     
  1716.     if (angle != 0.0) fprintf (ps.fp, "V %.3lg R ", angle);
  1717.     y0 = -0.5 * height * ps_font_height[ps.font_no] * (justify/4);
  1718.     if (y0 != 0.0) fprintf (ps.fp, "0 %d G ",(int) rint(y0 * ps.scale));
  1719.     if (!strchr (string, '@')) {    /* Plain text string */
  1720.         fprintf (ps.fp, "%d F%d ", (int) rint (height * ps.scale), ps.font_no);
  1721.         fprintf (ps.fp, "(%s) ", string);
  1722.         if ((justify %= 4) > 1) fprintf (ps.fp, "E %d div 0 G ",(justify - 4));
  1723.         (form == 0) ? fprintf (ps.fp, "Z") : fprintf (ps.fp, "true charpath S");
  1724.         (angle != 0.0) ? fprintf (ps.fp, " U\n") : fprintf (ps.fp, "\n");
  1725.         free (string);
  1726.         return;
  1727.     }
  1728.     
  1729.     /* Here, we have special request for Symbol font and sub/superscript
  1730.      * @~ toggles between Symbol font and default font
  1731.      * @%<fontno>% switches font number <fontno>; give @%% to reset
  1732.      * @- toggles between subscript and normal text
  1733.      * @+ toggles between superscript and normal text
  1734.      * @# toggles between Small caps and normal text
  1735.      * @! will make a composite character of next two characters
  1736.      * Use @@ to print a single @
  1737.      */
  1738.     
  1739.     piece = malloc (2048);    piece[0] = 0;
  1740.     piece2 = malloc (512);    piece2[0] = 0;
  1741.      
  1742.     font = old_font = ps.font_no;
  1743.     size = height;
  1744.     small_size = height * 0.7;
  1745.     scap_size = height * 0.85;
  1746.     step = 0.3 * height;
  1747.     sub = super = small = FALSE;
  1748.     
  1749.     if ((justify %= 4 ) > 1) {
  1750.         /* First we need to compute the justification.  The PS interpreter must do this for us */
  1751.         tempstring = malloc ((unsigned) (strlen (string)+1));    /* Since strtok steps on it */
  1752.         strcpy (tempstring, string);
  1753.         ptr = strtok (tempstring, "@");
  1754.         fprintf (ps.fp, "0 ");    /* Initialize stringlength */
  1755. /*
  1756.   Modifications by J.Lillibridge: 5/18/94
  1757.   Handle the case where string starts with "~,-,+,#,!" WITHOUT a preceding "@".
  1758.   But, in addition, there IS an "@" escape sequence within the string (that's
  1759.   why we're here... plain text has already been printed above & we returned).
  1760.  
  1761.   This is a problem because "strtok" returns the first part of the string even
  1762.   if there isn't a leading "@".  The "while(ptr)" loop below assumes each 
  1763.   "piece" is preceded by the "@" escape character.
  1764. */
  1765.         if(string[0] != '@') {
  1766.             fprintf (ps.fp, "%d F%d (%s) stringwidth pop add ",
  1767.             (int)rint(size*ps.scale), font, ptr);
  1768.             ptr = strtok ((char *)NULL, "@");
  1769.         }
  1770.  
  1771.         while (ptr) {
  1772.             if (ptr[0] == '!') {    /* Composite character */
  1773.                 ptr++;
  1774.                 if (ptr[0] == '\\')    /* Octal code */
  1775.                     ptr += 4;
  1776.                 else
  1777.                     ptr++;
  1778.                 strcpy (piece, ptr);
  1779.             }
  1780.             else if (ptr[0] == '~') {    /* Symbol font toggle */
  1781.                 font = (font == 12) ? ps.font_no : 12;
  1782.                 ptr++;
  1783.                 strcpy (piece, ptr);
  1784.             }
  1785.             else if (ptr[0] == '%') {    /* Switch font option */
  1786.                 ptr++;
  1787.                 if (ptr[0] == '%')
  1788.                     font = old_font;
  1789.                 else {
  1790.                     old_font = font;
  1791.                     font = atoi (ptr);
  1792.                 }
  1793.                 while (*ptr != '%') ptr++;
  1794.                 ptr++;
  1795.                 strcpy (piece, ptr);
  1796.             }
  1797.             else if (ptr[0] == '-') {    /* Subscript toggle  */
  1798.                 sub = !sub;
  1799.                 size = (sub) ? small_size : height;
  1800.                 ptr++;
  1801.                 strcpy (piece, ptr);
  1802.             }
  1803.             else if (ptr[0] == '+') {    /* Superscript toggle */
  1804.                 super = !super;
  1805.                 size = (super) ? small_size : height;
  1806.                 ptr++;
  1807.                 strcpy (piece, ptr);
  1808.             }
  1809.             else if (ptr[0] == '#') {    /* Small caps toggle */
  1810.                 small = !small;
  1811.                 size = (small) ? scap_size : height;
  1812.                 ptr++;
  1813.                 (small) ? get_uppercase (piece, ptr) : (int) strcpy (piece, ptr);
  1814.             }
  1815.             else    /* Not recognized or @@ for a single @ */
  1816.                 strcpy (piece, ptr);
  1817.             if (strlen (piece) > 0) fprintf (ps.fp, "%d F%d (%s) stringwidth pop add ",
  1818.                 (int)rint(size*ps.scale), font, piece);
  1819.             ptr = strtok ((char *)NULL, "@");
  1820.         }
  1821.         /* Now move currentpoint to reflect the justification */
  1822.         fprintf (ps.fp, "%d div 0 G\n", justify - 4);
  1823.         free (tempstring);
  1824.     }
  1825.     
  1826.     /* Now we can start printing text items */
  1827.     
  1828.     font = old_font = ps.font_no;
  1829.     if (form == 0)
  1830.         strcpy (op, "Z");
  1831.     else
  1832.         strcpy (op, "true charpath S");
  1833.     sub = super = small = FALSE;
  1834.     ptr = strtok (string, "@");
  1835.     size = height;
  1836. /*
  1837.   Modifications by J.Lillibridge: 5/18/94
  1838.   Handle the case where string starts with "~,-,+,#,!" WITHOUT a preceding "@".
  1839.   But, in addition, there IS an "@" escape sequence within the string (that's
  1840.   why we're here... plain text has already been printed above & we returned).
  1841.  
  1842.   This is a problem because "strtok" returns the first part of the string even
  1843.   if there isn't a leading "@".  The "while(ptr)" loop below assumes each 
  1844.   "piece" is preceded by the "@" escape character.
  1845. */
  1846.     if(string[0] != '@') {
  1847.         fprintf (ps.fp, "%d F%d (%s) %s\n",
  1848.         (int)rint(size*ps.scale), font, ptr, op);
  1849.         ptr = strtok ((char *)NULL, "@");
  1850.     }
  1851.  
  1852.     while (ptr) {
  1853.         if (ptr[0] == '!') {    /* Composite character */
  1854.             ptr++;
  1855.             if (ptr[0] == '\\') {    /* Octal code */
  1856.                 strncpy (piece, ptr, 4);
  1857.                 piece[4] = 0;
  1858.                 ptr += 4;
  1859.             }
  1860.             else {
  1861.                 piece[0] = ptr[0];    piece[1] = 0;
  1862.                 ptr++;
  1863.             }
  1864.             if (ptr[0] == '\\') {    /* Octal code again*/
  1865.                 strncpy (piece2, ptr, 4);
  1866.                 piece2[4] = 0;
  1867.                 ptr += 4;
  1868.             }
  1869.             else {
  1870.                 piece2[0] = ptr[0];    piece2[1] = 0;
  1871.                 ptr++;
  1872.             }
  1873.             fprintf (ps.fp, "%d F%d (%s) dup stringwidth pop exch %s -2 div dup 0 G\n", (int)rint(size*ps.scale), font, piece2, op);
  1874.             fprintf (ps.fp, "%d F%d (%s) E -2 div dup 0 G exch %s sub neg dup 0 lt {pop 0} if 0 G\n", (int)rint(size*ps.scale), font, piece, op);
  1875.             strcpy (piece, ptr);
  1876.         }
  1877.         else if (ptr[0] == '~') {    /* Symbol font */
  1878.             font = (font == 12) ? ps.font_no : 12;
  1879.             ptr++;
  1880.             strcpy (piece, ptr);
  1881.         }
  1882.         else if (ptr[0] == '%') {    /* Switch font option */
  1883.             ptr++;
  1884.             if (*ptr == '%')
  1885.                 font = old_font;
  1886.             else {
  1887.                 old_font = font;
  1888.                 font = atoi (ptr);
  1889.             }
  1890.             while (*ptr != '%') ptr++;
  1891.             ptr++;
  1892.             strcpy (piece, ptr);
  1893.         }
  1894.         else if (ptr[0] == '-') {    /* Subscript */
  1895.             sub = !sub;
  1896.             size = (sub) ? small_size : height;
  1897.             dy = (sub) ? rint(-step*ps.scale) : rint(step*ps.scale);
  1898.             fprintf (ps.fp, "0 %d G\n", dy);
  1899.             ptr++;
  1900.             strcpy (piece, ptr);
  1901.         }
  1902.         else if (ptr[0] == '+') {    /* Superscript */
  1903.             super = !super;
  1904.             size = (super) ? small_size : height;
  1905.             dy = (super) ? rint(step*ps.scale) : rint(-step*ps.scale);
  1906.             fprintf (ps.fp, "0 %d G\n", dy);
  1907.             ptr++;
  1908.             strcpy (piece, ptr);
  1909.         }
  1910.         else if (ptr[0] == '#') {    /* Small caps */
  1911.             small = !small;
  1912.             size = (small) ? scap_size : height;
  1913.             ptr++;
  1914.             (small) ? get_uppercase (piece, ptr) : (int) strcpy (piece, ptr);
  1915.         }
  1916.         else
  1917.             strcpy (piece, ptr);
  1918.         if (strlen (piece) > 0)
  1919.             fprintf (ps.fp, "%d F%d (%s) %s\n",(int)rint(size*ps.scale), font, piece, op);
  1920.         ptr = strtok ((char *)NULL, "@");
  1921.     }
  1922.     if (angle != 0.0) fprintf (ps.fp, "U\n");
  1923.     free (piece);
  1924.     free (piece2);
  1925.     free (string);
  1926. }
  1927.  
  1928. /* fortan interface */
  1929. int ps_text_ (x, y, pointsize, text, angle, justify, form, nlen)
  1930. double *x, *y, *angle;
  1931. char *text;
  1932. int *pointsize;
  1933. int *justify;
  1934. int nlen;
  1935. int *form; {
  1936.     ps_text (*x, *y, *pointsize, text, *angle, *justify, *form);
  1937. }
  1938.  
  1939. void ps_textbox2 (x, y, pointsize, text, angle, justify, outline, dx, dy, r, g, b)
  1940. double x, y, angle;
  1941. char *text;
  1942. int pointsize, justify;    /* indicates what x,y refers to, see fig */
  1943. int outline;
  1944. double dx, dy;    /* Space between box border and text, in inches (or cm) */
  1945. int r, g, b; {    /* If r == -1 set up continued clip path instead */
  1946.   /*
  1947.    *    9    10    11
  1948.    *   |----------------|
  1949.    *   5  <textstring>  7
  1950.    *   |----------------|
  1951.    *   1     2     3
  1952.    */
  1953.     char *string;
  1954.     int i = 0, j, idx, idy;
  1955.     double height, y0;
  1956.  
  1957.     if (strlen (text) >= 511) {
  1958.         fprintf (stderr, "pslib: text_item > 512 long!\n");
  1959.         return;
  1960.     }
  1961.     
  1962.     if (justify < 0)  {    /* Strip leading and trailing blanks */
  1963.         for (i = 0; text[i] == ' '; i++);
  1964.         for (j = strlen (text) - 1; text[j] == ' '; j--) text[j] = 0;
  1965.     }
  1966.     
  1967.     string = ps_prepare_text (&text[i]);
  1968.     
  1969.     if (strchr (string, '@')) {
  1970.         free (string);
  1971.         return;    /* Text string still contains escape sequence, box not yet supported */
  1972.     }
  1973.     
  1974.     fprintf (ps.fp, "\n%% ps_textbox begin:\n");
  1975.     
  1976.       height = pointsize / ps.points_pr_unit;
  1977.     justify = abs (justify);
  1978.     idx = rint (dx * ps.scale);    idy = rint (dy * ps.scale);
  1979.       
  1980.       /* Got to anchor point */
  1981.       
  1982.     ps.ix = rint (x * ps.scale);
  1983.     ps.iy = rint (y * ps.scale);
  1984.     fprintf (ps.fp, "%d %d T 0 0 m ", ps.ix, ps.iy);
  1985.     
  1986.     y0 = -0.5 * height * ps_font_height[ps.font_no] * (justify/4);
  1987.     if (y0 != 0.0) fprintf (ps.fp, "0 %d G ",(int)rint (y0 * ps.scale));
  1988.     fprintf (ps.fp, "%d F%d (%s) ", (int)rint (height * ps.scale), ps.font_no, string);
  1989.     if ((justify %= 4) > 1) fprintf (ps.fp, "E %d div 0 G ",(justify - 4));
  1990.     fprintf (ps.fp, "false charpath flattenpath pathbbox\n");
  1991.     fprintf (ps.fp, "%d add /y2 exch def %d add /x2 exch def %d sub /y1 exch def %d sub /x1 exch def N\n",
  1992.         idy, idx, idy, idx);
  1993.     if (angle != 0.0) fprintf (ps.fp, "%.3lg R ", angle);
  1994.     fprintf (ps.fp, "x1 y1 m x2 y1 L x2 y2 L x1 y2 L P ");
  1995.     if (r != g || g != b)
  1996.         fprintf (ps.fp, "V %.3lg %.3lg %.3lg C F U ", (r * I_255), (g * I_255), (b * I_255));
  1997.     else if (r >= 0)
  1998.         fprintf (ps.fp, "V %.3lg A F U ", (r * I_255));
  1999.     if (r != -1)
  2000.         (outline) ? fprintf (ps.fp, "S\n") : fprintf (ps.fp, "N\n");
  2001.     if (angle != 0.0) fprintf (ps.fp, "%.3lg R ", -angle);
  2002.     fprintf (ps.fp, "%d %d T\n", -ps.ix, -ps.iy);
  2003.     fprintf (ps.fp, "%% ps_textbox end:\n\n");
  2004.     
  2005.     free (string);
  2006. }
  2007.  
  2008. void ps_textbox (x, y, pointsize, text, angle, justify, outline, dx, dy, r, g, b)
  2009. double x, y, angle;
  2010. char *text;
  2011. int pointsize, justify;    /* indicates what x,y refers to, see fig */
  2012. int outline;
  2013. double dx, dy;    /* Space between box border and text, in inches */
  2014. int r, g, b; {
  2015.   /*
  2016.    *    9    10    11
  2017.    *   |----------------|
  2018.    *   5  <textstring>  7
  2019.    *   |----------------|
  2020.    *   1     2     3
  2021.    */
  2022.     char *string;
  2023.     int i = 0, j, idx, idy;
  2024.     double height, y0;
  2025.  
  2026.     if (strlen (text) >= 511) {
  2027.         fprintf (stderr, "pslib: text_item > 512 long!\n");
  2028.         return;
  2029.     }
  2030.     
  2031.     if (justify < 0)  {    /* Strip leading and trailing blanks */
  2032.         for (i = 0; text[i] == ' '; i++);
  2033.         for (j = strlen (text) - 1; text[j] == ' '; j--) text[j] = 0;
  2034.     }
  2035.     
  2036.     string = ps_prepare_text (&text[i]);
  2037.     
  2038.     if (strchr (string, '@')) {
  2039.         free (string);
  2040.         return;    /* Text string still contains escape sequence, box not yet supported */
  2041.     }
  2042.     
  2043.     fprintf (ps.fp, "\n%% ps_textbox begin:\n");
  2044.     
  2045.       height = pointsize / ps.points_pr_unit;
  2046.     justify = abs (justify);
  2047.     idx = rint (dx * ps.scale);    idy = rint (dy * ps.scale);
  2048.       
  2049.       /* Got to anchor point */
  2050.       
  2051.     ps.ix = rint (x * ps.scale);
  2052.     ps.iy = rint (y * ps.scale);
  2053.     fprintf (ps.fp, "V %d %d T 0 0 M ", ps.ix, ps.iy);
  2054.     
  2055.     y0 = -0.5 * height * ps_font_height[ps.font_no] * (justify/4);
  2056.     if (y0 != 0.0) fprintf (ps.fp, "0 %d G ",(int)rint (y0 * ps.scale));
  2057.     fprintf (ps.fp, "%d F%d (%s) ", (int)rint (height * ps.scale), ps.font_no, string);
  2058.     if ((justify %= 4) > 1) fprintf (ps.fp, "E %d div 0 G ",(justify - 4));
  2059.     fprintf (ps.fp, "false charpath flattenpath pathbbox\n");
  2060.     fprintf (ps.fp, "%d add /y2 exch def %d add /x2 exch def %d sub /y1 exch def %d sub /x1 exch def N\n",
  2061.         idy, idx, idy, idx);
  2062.     if (angle != 0.0) fprintf (ps.fp, "%.3lg R ", angle);
  2063.     fprintf (ps.fp, "x1 y1 M x2 y1 L x2 y2 L x1 y2 L P V ");
  2064.     if (r != g || g != b)
  2065.         fprintf (ps.fp, "%.3lg %.3lg %.3lg C F U ", (r * I_255), (g * I_255), (b * I_255));
  2066.     else
  2067.         fprintf (ps.fp, "%.3lg A F U ", (r * I_255));
  2068.     (outline) ? fprintf (ps.fp, "S U\n") : fprintf (ps.fp, "N U\n");
  2069.     fprintf (ps.fp, "%% ps_textbox end:\n\n");
  2070.     
  2071.     free (string);
  2072. }
  2073.  
  2074. /* fortran interface */
  2075. int ps_textbox_ (x, y, pointsize, text, angle, justify, outline, dx, dy, r, g, b, nlen)
  2076. double *x, *y, *angle;
  2077. char *text;
  2078. int *pointsize, *justify;
  2079. int *outline;
  2080. double *dx, *dy;
  2081. int nlen;
  2082. int *r, *g, *b; {
  2083.      ps_textbox (*x, *y, *pointsize, text, *angle, *justify, *outline, *dx, *dy, *r, *g, *b);
  2084. }
  2085.  
  2086. void ps_transrotate (x, y, angle)
  2087. double x, y, angle; {
  2088.     int ix, iy;
  2089.     int go = FALSE;
  2090.     
  2091.     ix = rint (x * ps.scale);
  2092.     iy = rint (y * ps.scale);
  2093.     if (ix != 0 || iy != 0) {
  2094.         fprintf (ps.fp, "%d %d T", ix, iy);
  2095.         go = TRUE;
  2096.     }
  2097.     if (angle != 0.0) {
  2098.         if (go) putc (' ', ps.fp);
  2099.         fprintf (ps.fp, "%lg R", angle);
  2100.     }
  2101.     putc ('\n', ps.fp);
  2102. }
  2103.  
  2104. /* fortran interface */
  2105. int ps_transrotate_ (x, y, angle)
  2106. double *x, *y, *angle; {
  2107.     ps_transrotate (*x, *y, *angle);
  2108. }
  2109.  
  2110. void ps_triangle (x, y, side, r, g, b, outline)
  2111. double x, y, side;
  2112. int r, g, b;
  2113. int outline; {    /* see circle */
  2114.     int ix, iy, is;
  2115.     
  2116.     ix = rint ((x-0.5*side) * ps.scale);
  2117.     iy = rint ((y-0.2886751*side) * ps.scale);
  2118.     is = rint (side * ps.scale);
  2119.     if (r < 0) /* Outline only */
  2120.         fprintf (ps.fp, "%d %d %d T4\n", is, ix, iy);
  2121.     else if (r != g || g != b) /* color */
  2122.         fprintf (ps.fp, "%.3lg %.3lg %.3lg %d %d %d T%d\n", r * I_255, g * I_255, b * I_255, is, ix, iy, outline+2);
  2123.     else /* Grayshade */
  2124.         fprintf (ps.fp, "%.3lg %d %d %d T%d\n", r * I_255, is, ix, iy, outline);
  2125.     ps.npath = 0;
  2126. }
  2127.  
  2128. /* fortran interface */
  2129. int ps_triangle_ (x, y, side, r, g, b, outline)
  2130. double *x, *y, *side;
  2131. int *r, *g, *b;
  2132. int *outline; {
  2133.     ps_triangle (*x, *y, *side, *r, *g, *b, *outline);
  2134. }
  2135.  
  2136. void ps_itriangle (x, y, side, r, g, b, outline)    /* Inverted triangle */
  2137. double x, y, side;
  2138. int r, g, b;
  2139. int outline; {    /* see circle */
  2140.     int ix, iy, is;
  2141.     
  2142.     ix = rint ((x-0.5*side) * ps.scale);
  2143.     iy = rint ((y+0.2886751*side) * ps.scale);
  2144.     is = rint (side * ps.scale);
  2145.     if (r < 0) /* Outline only */
  2146.         fprintf (ps.fp, "%d %d %d I4\n", is, ix, iy);
  2147.     else if (r != g || g != b) /* color */
  2148.         fprintf (ps.fp, "%.3lg %.3lg %.3lg %d %d %d I%d\n", r * I_255, g * I_255, b * I_255, is, ix, iy, outline+2);
  2149.     else /* Grayshade */
  2150.         fprintf (ps.fp, "%.3lg %d %d %d I%d\n", r * I_255, is, ix, iy, outline);
  2151.     ps.npath = 0;
  2152. }
  2153.  
  2154. /* fortran interface */
  2155. int ps_itriangle_ (x, y, side, r, g, b, outline)
  2156. double *x, *y, *side;
  2157. int *r, *g, *b;
  2158. int *outline; {
  2159.     ps_itriangle (*x, *y, *side, *r, *g, *b, *outline);
  2160. }
  2161.  
  2162. void ps_vector (xtail, ytail, xtip, ytip, tailwidth, headlength, headwidth, headshape, r, g, b, outline)
  2163. double xtail, ytail, xtip, ytip, tailwidth, headlength, headwidth, headshape;
  2164. int r, g, b;
  2165. int outline; {
  2166.     /* Will make sure that arrow has a finite width in PS coordinates */
  2167.     
  2168.     double angle;
  2169.     int w2, length, hw, hl, hl2, hw2, l2;
  2170.     
  2171.     length = rint (hypot ((xtail-xtip), (ytail-ytip)) * ps.scale);
  2172.     if (length == 0) return;
  2173.  
  2174.     angle = atan2 ((ytip-ytail),(xtip-xtail)) * R2D;
  2175.     fprintf (ps.fp, "V %d %d T", (int)rint (xtail * ps.scale), (int)rint (ytail * ps.scale));
  2176.     if (angle != 0.0) fprintf (ps.fp, " %lg R", angle);
  2177.     w2 = rint (0.5 * tailwidth * ps.scale);    if (w2 == 0) w2 = 1;
  2178.     hw = rint (headwidth * ps.scale);    if (hw == 0) hw = 1;
  2179.     hl = rint (headlength * ps.scale);
  2180.     hl2 = rint (0.5 * headshape * headlength * ps.scale);
  2181.     hw2 = hw - w2;
  2182.     l2 = length - hl + hl2;
  2183.     if (r < 0) /* Outline only */
  2184.         fprintf (ps.fp, " %d %d %d %d %d %d %d %d %d %d %d A4 U\n",
  2185.             -l2, hl2, -hw2, -hl, hw, hl, hw, -hl2, -hw2, l2, -w2);
  2186.     else if (r != g || g != b) /* color */
  2187.         fprintf (ps.fp, " %.3lg %.3lg %.3lg %d %d %d %d %d %d %d %d %d %d %d A%d U\n",
  2188.             r * I_255, g * I_255, b * I_255, -l2, hl2, -hw2, -hl, hw, hl, hw, -hl2, -hw2, l2, -w2, outline+2);
  2189.     else /* grayshade */
  2190.         fprintf (ps.fp, " %.3lg %d %d %d %d %d %d %d %d %d %d %d A%d U\n",
  2191.             r * I_255, -l2, hl2, -hw2, -hl, hw, hl, hw, -hl2, -hw2, l2, -w2, outline);
  2192. }
  2193.  
  2194. /* fortran interface */
  2195. int ps_vector_ (xtail, ytail, xtip, ytip, tailwidth, headlength, headwidth, headshape, r, g, b, outline)
  2196. double *xtail, *ytail, *xtip, *ytip, *tailwidth, *headlength, *headwidth, *headshape;
  2197. int *r, *g, *b;
  2198. int *outline; {
  2199.      ps_vector (*xtail, *ytail, *xtip, *ytip, *tailwidth, *headlength, *headwidth, *headshape, *r, *g, *b, *outline);
  2200. }
  2201.  
  2202. /* Support functions used in ps_* functions.  No Fortran bindings needed */
  2203.  
  2204. char *get_icon (file, nx, ny, invert)
  2205. char *file;
  2206. int *nx, *ny, invert; {
  2207.     int i, n_items, n_int, j, k, n_read, integer, n_alloc, n_lines, last;
  2208.     unsigned short int *pattern;
  2209.     char *out, t[8][7], line[80], width[12], height[12];
  2210.     FILE *fp;
  2211.     
  2212.     if ((fp = fopen (file, "r")) == NULL) {
  2213.         fprintf (stderr, "pslib: Cannot open file %s\n", file);
  2214.         return ((char *)NULL);
  2215.     }
  2216.     
  2217.     fgets (line, 80, fp);
  2218.     line[strlen(line)-1] = 0;
  2219.     sscanf (&line[3], "%*[^,], %[^,], %[^,]", width, height);
  2220.     i = 0;    while (width[i] != '=') i++;
  2221.     *nx = atoi (&width[i+1]);
  2222.     i = 0;    while (height[i] != '=') i++;
  2223.     *ny = atoi (&height[i+1]);
  2224.     fgets (line, 80, fp);
  2225.     line[strlen(line)-1] = 0;
  2226.     n_items = (*nx) * (*ny) / 4;
  2227.     n_int = n_items / 4;
  2228.     out = malloc ( (unsigned) (n_items+1));
  2229.     out[0] = 0;
  2230.     n_alloc = ceil (n_int / 8.0) * n_int;
  2231.     pattern = (unsigned short int *) malloc ((unsigned)n_alloc);
  2232.     n_lines = n_items / 32;
  2233.     for (i = k = 0; i < n_lines; i++) {
  2234.         fgets (line, 80, fp);
  2235.         line[strlen(line)-1] = 0;
  2236.         last = (i == (n_lines - 1));
  2237.         if (last) {
  2238.             n_read = sscanf (&line[1], "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,]", t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]);
  2239.             if (n_read == 4) sscanf (&line[1], "%[^,],%[^,],%[^,],%[^,]", t[4], t[5], t[6], t[7]);    /* New style icon file */
  2240.         }
  2241.         else {
  2242.             n_read = sscanf (&line[1], "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],", t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]);
  2243.             if (n_read == 4) sscanf (&line[1], "%[^,],%[^,],%[^,],%[^,],", t[4], t[5], t[6], t[7]);    /* New style icon file */
  2244.         }
  2245.         for (j = 0; j < 8; j++, k++) {
  2246.             sscanf (&t[j][2], "%x", &integer);
  2247.             pattern[k] = integer;
  2248.         }
  2249.     }
  2250.     fclose (fp);
  2251.     if (invert) for (k = 0; k < n_int; k++) pattern[k] = ~pattern[k];
  2252.     for (k = 0; k < n_int; k++) {
  2253.         sprintf (t[0], "%.4x", (int)pattern[k]);
  2254.         strcat (out, t[0]);
  2255.     }
  2256.     out[n_items] = 0;
  2257.     free ((char *)pattern);
  2258.     return (out);
  2259. }
  2260.  
  2261. int get_uppercase (new, old)
  2262. char *new, *old; {
  2263.     int i = 0;
  2264.     while (old[i]) {
  2265.         new[i] = toupper ((int)old[i]);
  2266.         i++;
  2267.     }
  2268.     new[i] = 0;
  2269. }
  2270.  
  2271. void init_euro_header(eps)
  2272. struct EPS *eps;
  2273. /*-------------- European header definition -------------------*/
  2274. {
  2275.     int i;
  2276.     
  2277.         fprintf (ps.fp,"%% START OF EUROPEAN FONT DEFINITION\n");
  2278.     fprintf (ps.fp, "%% Reencode standard font map to European font map\n\
  2279. %%\n\
  2280. /reencsmalldict 12 dict def\n\
  2281. /ReEncodeSmall\n\
  2282. { reencsmalldict begin\n\
  2283.         /newcodesandnames exch def\n\
  2284.         /newfontname exch def\n\
  2285.         /basefontname exch def\n\
  2286.         /basefontdict basefontname findfont def\n\
  2287.         /newfont basefontdict maxlength dict def\n\
  2288.         basefontdict\n\
  2289.         { exch dup /FID ne \n\
  2290.             { dup /Encoding eq\n\
  2291.                 { exch dup length array copy\n\
  2292.                     newfont 3 1 roll put }\n\
  2293.                 { exch newfont 3 1 roll put }\n\
  2294.                 ifelse\n\
  2295.                 }\n\
  2296.                 { pop pop }\n\
  2297.                 ifelse\n\
  2298.         } forall\n\
  2299.         newfont /FontName newfontname put\n\
  2300.         newcodesandnames aload pop\n\
  2301.         newcodesandnames length 2 idiv\n\
  2302.         { newfont /Encoding get 3 1 roll put }\n\
  2303.         repeat\n\
  2304.         newfontname newfont definefont pop\n\
  2305.         end\n\
  2306. } def\n\
  2307. \n\
  2308. /eurovec[\n\
  2309. 8#260 /Aacute\n\
  2310. 8#265 /Acircumflex\n\
  2311. 8#276 /Adieresis\n\
  2312. 8#300 /Agrave\n\
  2313. 8#311 /Eacute\n\
  2314. 8#314 /Ecircumflex\n\
  2315. 8#321 /Edieresis\n\
  2316. 8#322 /Egrave\n\
  2317. 8#323 /Iacute\n\
  2318. 8#324 /Icircumflex\n\
  2319. 8#325 /Idieresis\n\
  2320. 8#326 /Igrave\n\
  2321. 8#327 /Oacute\n\
  2322. 8#330 /Ocircumflex\n\
  2323. 8#331 /Odieresis\n\
  2324. 8#332 /Ograve\n\
  2325. 8#333 /Uacute\n\
  2326. 8#334 /Ucircumflex\n\
  2327. 8#335 /Udieresis\n\
  2328. 8#336 /Ugrave\n\
  2329. 8#337 /aacute\n\
  2330. 8#340 /acircumflex\n\
  2331. 8#342 /adieresis\n\
  2332. 8#344 /agrave\n\
  2333. 8#345 /eacute\n\
  2334. 8#346 /ecircumflex\n\
  2335. 8#347 /edieresis\n\
  2336. 8#350 /egrave\n\
  2337. 8#354 /iacute\n\
  2338. 8#355 /icircumflex\n\
  2339. 8#356 /idieresis\n\
  2340. 8#357 /igrave\n\
  2341. 8#360 /oacute\n\
  2342. 8#362 /ocircumflex\n\
  2343. 8#363 /odieresis\n\
  2344. 8#364 /ograve\n\
  2345. 8#366 /uacute\n\
  2346. 8#367 /ucircumflex\n\
  2347. 8#370 /udieresis\n\
  2348. 8#374 /ugrave\n\
  2349. 8#375 /Aring\n\
  2350. 8#376 /aring\n\
  2351. ] def\n");
  2352.  
  2353.     /* Define European fonts */
  2354.     /* Only reencode fonts actually used */
  2355.     if (eps)
  2356.         for (i = 0; eps->font[i]; i++) ps_def_euro_font (eps->font[i]);
  2357.     else
  2358.     /* Must output all */
  2359.         for (i = 0; i < N_FONTS; i++) ps_def_euro_font (ps_font_name[i]);
  2360.         
  2361.         fprintf (ps.fp,"%% END OF EUROPEAN FONT DEFINITION\n");
  2362. }
  2363.  
  2364. void ps_def_euro_font (font)
  2365. char *font; {
  2366.     fprintf (ps.fp, "/%s /%s eurovec ReEncodeSmall\n", font, font);
  2367. }
  2368.  
  2369. char *ps_prepare_text (text)
  2370. char *text;
  2371. /*    Adds escapes for misc parenthesis, brackets etc.
  2372.     Will also translate to some European characters from the @a, @e
  2373.     etc escape sequences. Calling function must REMEMBER to free memory
  2374.     allocated by string */
  2375. {
  2376.     char *string;
  2377.     int i=0, j=0;
  2378.  
  2379.     string = (char *) calloc (2048, sizeof(char));
  2380.     while (text[i]) {
  2381.         if (text[i] == '@') {
  2382.             i++;
  2383.             switch (text[i]) {
  2384.                 case 'A':
  2385.                     strcat (string, "\\375"); j += 4; i++;
  2386.                     break;
  2387.                 case 'E':
  2388.                     strcat (string, "\\341"); j += 4; i++;
  2389.                     break;
  2390.                 case 'O':
  2391.                     strcat (string, "\\351"); j += 4; i++;
  2392.                     break;
  2393.                 case 'a':
  2394.                     strcat (string, "\\376"); j += 4; i++;
  2395.                     break;
  2396.                 case 'e':
  2397.                     strcat (string, "\\372"); j += 4; i++;
  2398.                     break;
  2399.                 case 'o':
  2400.                     strcat (string, "\\371"); j += 4; i++;
  2401.                     break;
  2402.                 case '@':
  2403. /*    Also now converts "@@" to the octal code for "@" = "\100".
  2404.        This was necessary since the system routine "strtok" gobbles up
  2405.        multiple @'s when parsing the string inside "ps_text", and thus
  2406.        didn't properly output a single "@" sign when encountering "@@".
  2407.        John L. Lillibridge: 4/6/95 [This was a problem on SGI; PW]
  2408. */
  2409.  
  2410.                     strcat (string, "\\100"); j += 4; i++;
  2411.                     break;
  2412.                 default:
  2413.                     string[j++] = '@';
  2414.                     string[j++] = text[i++];
  2415.                     break;
  2416.             }
  2417.         }
  2418.         else {
  2419.             switch (text[i]) {    /* NEED TO BE ESCAPED!!!! for PostScript*/
  2420.                 case '{':
  2421.                 case '}':
  2422.                 case '[':
  2423.                 case ']':
  2424.                 case '(':
  2425.                 case ')':
  2426.                 case '<':
  2427.                 case '>':
  2428.                     if (j > 0 && string[MAX(j-1,0)] == '\\')        /* ALREADY ESCAPED... */
  2429.                         string[j++] = text[i++];
  2430.                     else {
  2431.                         strcat(string, "\\"); j++;
  2432.                         string[j++] = text[i++];
  2433.                     }
  2434.                     break;
  2435.                 default:
  2436.                     string[j++] = text[i++];
  2437.                     break;
  2438.             }
  2439.         }
  2440.     }
  2441.     return (string);
  2442. }
  2443.  
  2444.