home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / XAP / XFIG / TRANSFIG.2 / TRANSFIG / transfig / fig2dev / dev / genps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-01  |  28.2 KB  |  1,053 lines

  1. /*
  2.  * TransFig: Facility for Translating Fig code
  3.  * Copyright (c) 1985 Supoj Sutantavibul
  4.  * Copyright (c) 1991 Micah Beck
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation. The authors make no representations about the suitability 
  11.  * of this software for any purpose.  It is provided "as is" without express 
  12.  * or implied warranty.
  13.  *
  14.  * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16.  * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  19.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  20.  * PERFORMANCE OF THIS SOFTWARE.
  21.  *
  22.  */
  23.  
  24. /* 
  25.  *    genps.c: PostScript driver for fig2dev
  26.  *
  27.  *    Modified by Herbert Bauer to support ISO-Characters,
  28.  *    multiple page output, color mode etc.
  29.  *    heb@regent.e-technik.tu-muenchen.de
  30.  *
  31.  *    Modified by Eric Picheral to support the whole set of ISO-Latin-1
  32.  *    Modified by Herve Soulard to allow non-iso coding on special fonts
  33.  *    Herve.Soulard@inria.fr (8 Apr 1993)
  34.  
  35. */
  36.  
  37. #include <sys/param.h>
  38. #if defined(hpux) || defined(SYSV) || defined(BSD4_3)
  39. #include <sys/types.h>
  40. #endif
  41. #include <sys/file.h>
  42. #include <stdio.h>
  43. #include <math.h>
  44. #include <pwd.h>
  45. #include <errno.h>
  46. extern char *sys_errlist[];
  47. #include "pi.h"
  48. #include "object.h"
  49. #include "fig2dev.h"
  50. #include "psfonts.h"
  51. #include <string.h>
  52. #include <time.h>
  53.  
  54. /* for the version nubmer */
  55. #include "../../patchlevel.h"
  56.  
  57. #ifdef A4
  58. #define        PAGE_WIDTH        595    /* points; 21cm */
  59. #define        PAGE_HEIGHT        842    /* points; 29.7cm */
  60. #else
  61. #define        PAGE_WIDTH        612    /* points; 8.5" */
  62. #define        PAGE_HEIGHT        792    /* points; 11" */
  63. #endif
  64. #define        TRUE            1
  65. #define        FALSE            0
  66. #define        POINT_PER_INCH        72
  67. #define        ULIMIT_FONT_SIZE    300
  68. #define     MAXCOLORS         16
  69.  
  70. int        pagewidth = PAGE_WIDTH;
  71. int        pageheight = PAGE_HEIGHT;
  72. static int    coord_system;
  73. int        show_page = 0;
  74. static int    cur_thickness;
  75. int        center = 0;
  76. int        landscape = 0;
  77. int        pages;
  78. int        no_obj = 0;
  79. int        multi_page = FALSE;
  80.  
  81. extern    int    v2_flag, v21_flag;
  82.  
  83. static    arc_tangent();
  84. static    draw_arrow_head();
  85. static    fill_area();
  86. static    iso_text_exist();
  87. static    encode_all_fonts();
  88. static    ellipse_exist();
  89. static    normal_spline_exist();
  90.  
  91. #define GRAYVAL(F)    ((F) <= 21 ? ((F)-1)/20.0 : 1.0)
  92.  
  93. #define        BEGIN_PROLOG    "\
  94. /$F2psDict 200 dict def \n\
  95. $F2psDict begin\n\
  96. $F2psDict /mtrx matrix put\n\
  97. /l {lineto} bind def\n\
  98. /m {moveto} bind def\n\
  99. /s {stroke} bind def\n\
  100. /n {newpath} bind def\n\
  101. /gs {gsave} bind def\n\
  102. /gr {grestore} bind def\n\
  103. /clp {closepath} bind def\n\
  104. /graycol {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul\n\
  105. 4 -2 roll mul setrgbcolor} bind def\n\
  106. /col-1 {} def\n\
  107. /col0 {0 0 0 setrgbcolor} bind def\n\
  108. /col1 {0 0 1 setrgbcolor} bind def\n\
  109. /col2 {0 1 0 setrgbcolor} bind def\n\
  110. /col3 {0 1 1 setrgbcolor} bind def\n\
  111. /col4 {1 0 0 setrgbcolor} bind def\n\
  112. /col5 {1 0 1 setrgbcolor} bind def\n\
  113. /col6 {1 1 0 setrgbcolor} bind def\n\
  114. /col7 {1 1 1 setrgbcolor} bind def\n\
  115. /col8 {.68 .85 .9 setrgbcolor} bind def\n\
  116. /col9 {0 .39 0 setrgbcolor} bind def\n\
  117. /col10 {.65 .17 .17 setrgbcolor} bind def\n\
  118. /col11 {1 .51 0 setrgbcolor} bind def\n\
  119. /col12 {.63 .13 .94 setrgbcolor} bind def\n\
  120. /col13 {1 .75 .8 setrgbcolor} bind def\n\
  121. /col14 {.7 .13 .13 setrgbcolor} bind def\n\
  122. /col15 {1 .84 0 setrgbcolor} bind def\n\
  123. "
  124.  
  125. #define        SPECIAL_CHAR_1    "\
  126. /reencdict 12 dict def /ReEncode { reencdict begin\n\
  127. /newcodesandnames exch def /newfontname exch def /basefontname exch def\n\
  128. /basefontdict basefontname findfont def /newfont basefontdict maxlength dict def\n\
  129. basefontdict { exch dup /FID ne { dup /Encoding eq\n\
  130. { exch dup length array copy newfont 3 1 roll put }\n\
  131. { exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall\n\
  132. newfont /FontName newfontname put newcodesandnames aload pop\n\
  133. 128 1 255 { newfont /Encoding get exch /.notdef put } for\n\
  134. newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat\n\
  135. newfontname newfont definefont pop end } def\n\
  136. /isovec [ \n\
  137. "
  138. #define        SPECIAL_CHAR_2    "\
  139. 8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde\n\
  140. 8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis\n\
  141. 8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron\n\
  142. 8#220 /dotlessi 8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling\n\
  143. 8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis\n\
  144. 8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot\n\
  145. 8#255 /endash 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus\n\
  146. 8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph\n\
  147. 8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine\n\
  148. 8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf \n\
  149. 8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute\n\
  150. 8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring\n\
  151. "
  152. #define        SPECIAL_CHAR_3    "\
  153. 8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute\n\
  154. 8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute\n\
  155. 8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve\n\
  156. 8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply\n\
  157. 8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex\n\
  158. 8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave\n\
  159. 8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring\n\
  160. 8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute\n\
  161. 8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute\n\
  162. 8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve\n\
  163. 8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide\n\
  164. 8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex\n\
  165. 8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis \
  166. ] def\n\
  167. "
  168.  
  169. #define        ELLIPSE_PS    " \
  170. /DrawEllipse {\n\
  171.     /endangle exch def\n\
  172.     /startangle exch def\n\
  173.     /yrad exch def\n\
  174.     /xrad exch def\n\
  175.     /y exch def\n\
  176.     /x exch def\n\
  177.     /savematrix mtrx currentmatrix def\n\
  178.     x y translate xrad yrad scale 0 0 1 startangle endangle arc\n\
  179.     savematrix setmatrix\n\
  180.     } def\n\
  181. "
  182. /* The original PostScript definition for adding a spline section to the
  183.  * current path uses recursive bisection.  The following definition using the
  184.  * curveto operator is more efficient since it executes at compiled rather
  185.  * than interpreted code speed.  The Bezier control points are 2/3 of the way
  186.  * from z1 (and z3) to z2.
  187.  *
  188.  * ---Rene Llames, 21 July 1988.
  189.  */
  190. #define        SPLINE_PS    " \
  191. /DrawSplineSection {\n\
  192.     /y3 exch def\n\
  193.     /x3 exch def\n\
  194.     /y2 exch def\n\
  195.     /x2 exch def\n\
  196.     /y1 exch def\n\
  197.     /x1 exch def\n\
  198.     /xa x1 x2 x1 sub 0.666667 mul add def\n\
  199.     /ya y1 y2 y1 sub 0.666667 mul add def\n\
  200.     /xb x3 x2 x3 sub 0.666667 mul add def\n\
  201.     /yb y3 y2 y3 sub 0.666667 mul add def\n\
  202.     x1 y1 lineto\n\
  203.     xa ya xb yb x3 y3 curveto\n\
  204.     } def\n\
  205. "
  206. #define        END_PROLOG    "\
  207.     end\n\
  208. /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def\n\
  209. /$F2psEnd {$F2psEnteredState restore end} def\n\
  210. %%EndProlog\n\
  211. "
  212.  
  213. static double        tx, scalex, scaley;
  214. static double        dx, dy, origx, origy;
  215.  
  216. void genps_option(opt, optarg)
  217. char opt;
  218. char *optarg;
  219. {
  220.     int i;
  221.  
  222.     switch (opt) {
  223.  
  224.     case 'f':
  225.         for ( i = 1; i <= MAX_PSFONT + 1; i++ )
  226.             if ( !strcmp(optarg, PSfontnames[i]) ) break;
  227.  
  228.         if ( i > MAX_PSFONT + 1 )
  229.             fprintf(stderr,
  230.                 "warning: non-standard font name %s\n", optarg);
  231.  
  232.             psfontnames[0] = psfontnames[1] = optarg;
  233.             PSfontnames[0] = PSfontnames[1] = optarg;
  234.             break;
  235.  
  236.     case 'c':
  237.             center = 1;
  238.         break;
  239.  
  240.     case 's':
  241.         if (font_size <= 0 || font_size > ULIMIT_FONT_SIZE) {
  242.             fprintf(stderr,
  243.                 "warning: font size %d out of bounds\n", font_size);
  244.         }
  245.         break;
  246.  
  247.     case 'P':
  248.         show_page = 1;
  249.         break;
  250.  
  251.           case 'm':
  252.           case 'L':
  253.         break;
  254.  
  255.           case 'l':
  256.         landscape = 1;
  257.         break;
  258.  
  259.     default:
  260.         put_msg(Err_badarg, opt, "ps");
  261.         exit(1);
  262.         break;
  263.     }
  264. }
  265.  
  266. void genps_start(objects)
  267. F_compound    *objects;
  268. {
  269.     char        host[256];
  270.     struct passwd    *who;
  271.     time_t        when;
  272.     int        itmp;
  273.     int        resolution;
  274.  
  275.     resolution = objects->nwcorner.x;
  276.     coord_system = objects->nwcorner.y;
  277.     scalex = scaley = mag * POINT_PER_INCH / (double)resolution;
  278.     /* convert to point unit */
  279.     llx = (int)ceil(llx * scalex); lly = (int)ceil(lly * scaley);
  280.     urx = (int)ceil(urx * scalex); ury = (int)ceil(ury * scaley);
  281.  
  282.  
  283.     if (landscape)
  284.     {
  285.        itmp = pageheight; pageheight = pagewidth; pagewidth = itmp;
  286.        itmp = llx; llx = lly; lly = itmp;
  287.        itmp = urx; urx = ury; ury = itmp;
  288.     }
  289.     if (show_page)
  290.     {
  291.        if (center)
  292.        {
  293.           if (landscape)
  294.           {
  295.          origx = (pageheight - urx - llx)/2.0;
  296.          origy = (pagewidth - ury - lly)/2.0;
  297.           }
  298.           else
  299.           {
  300.          origx = (pagewidth - urx - llx)/2.0;
  301.          origy = (pageheight + ury + lly)/2.0;
  302.           }
  303.        }
  304.        else
  305.        {
  306.           origx = 0.0;
  307.           origy = landscape ? 0.0 : pageheight;
  308.        }
  309.     }
  310.     else
  311.     {
  312.        origx = -llx;
  313.        origy = landscape ? -lly : ury;
  314.     }
  315.  
  316.     if (coord_system == 2) scaley = -scaley;
  317.  
  318.     if (show_page)
  319.         fprintf(tfp, "%%!PS-Adobe-2.0\n");        /* PostScript magic strings */
  320.     else
  321.         fprintf(tfp, "%%!PS-Adobe-2.0 EPSF-2.0\n");    /* Encapsulated PostScript */
  322.     who = getpwuid(getuid());
  323.     if (-1 == gethostname(host, sizeof(host)))
  324.         (void)strcpy(host, "unknown-host!?!?");
  325.     (void) time(&when);
  326.     fprintf(tfp, "%%%%Title: %s\n", ((from) ? from : "stdin"));
  327.     fprintf(tfp, "%%%%Creator: %s Version %s Patchlevel %s\n", 
  328.         prog, VERSION, PATCHLEVEL);
  329.     fprintf(tfp, "%%%%CreationDate: %s", ctime(&when));
  330.     if (who)
  331.        fprintf(tfp, "%%%%For: %s@%s (%s)\n",
  332.             who->pw_name, host, who->pw_gecos);
  333.  
  334.     if (!center)
  335.        if (landscape)
  336.         pages = (urx/pageheight+1)*(ury/pagewidth+1);
  337.        else
  338.         pages = (urx/pagewidth+1)*(ury/pageheight+1);
  339.     else
  340.        pages = 1;
  341.     if (landscape) {
  342.        fprintf(tfp, "%%%%Orientation: Landscape\n");
  343.        fprintf(tfp, "%%%%BoundingBox: %d %d %d %d\n", 
  344.           (int)origx+llx, (int)origy+lly, (int)origx+urx, (int)origy+ury);
  345.     } else {
  346.        fprintf(tfp, "%%%%Orientation: Portrait\n");
  347.        fprintf(tfp, "%%%%BoundingBox: %d %d %d %d\n", 
  348.           (int)origx+llx, (int)origy-ury, (int)origx+urx, (int)origy-lly);
  349.     }
  350.     fprintf(tfp, "%%%%Pages: %d\n", show_page ? pages : 0 );
  351.  
  352.     fprintf(tfp, "%%%%EndComments\n");
  353.     fprintf(tfp, "%s", BEGIN_PROLOG);
  354.     if (iso_text_exist(objects))
  355.     {
  356.        fprintf(tfp, "%s%s%s", SPECIAL_CHAR_1,SPECIAL_CHAR_2,SPECIAL_CHAR_3);
  357.        encode_all_fonts(objects);
  358.     }
  359.     if (ellipse_exist(objects)) fprintf(tfp, "%s\n", ELLIPSE_PS);
  360.     if (normal_spline_exist(objects)) fprintf(tfp, "%s\n", SPLINE_PS);
  361.     fprintf(tfp, "%s\n", END_PROLOG);
  362.     fprintf(tfp, "$F2psBegin\n");
  363.      fprintf(tfp, "0 setlinecap 0 setlinejoin\n");
  364.   
  365.      if ( pages > 1 && show_page && !center )
  366.         multi_page = TRUE;
  367.      else
  368.      {
  369.         fprintf (tfp, "%.1f %.1f translate", origx, origy);
  370.         if (landscape)
  371.         {
  372.            fprintf (tfp, " 90 rotate");
  373.         }
  374.         fprintf (tfp, " %.3f %.3f scale\n", scalex, scaley );
  375.     }
  376. }
  377.  
  378. void genps_end()
  379. {
  380.     double dx,dy;
  381.     int i, page;
  382.     int h,w;
  383.   
  384.     if (multi_page)
  385.     {
  386.        page = 1;
  387.        h = (landscape? pagewidth: pageheight);
  388.        w = (landscape? pageheight: pagewidth);
  389.        for (dy=0; dy < (ury-h*0.1); dy += h*0.9)
  390.        {
  391.      for (dx=0; dx < (urx-w*0.1); dx += w*0.9)
  392.      {
  393.         fprintf (tfp, "%%%%Page: %d %d\n%.1f %.1f translate", 
  394.         page,page,
  395.         -(origx+dx), (origy+(landscape?-dy:dy)));
  396.         if (landscape)
  397.         {
  398.            fprintf(tfp, " 90 rotate");
  399.         }
  400.         fprintf (tfp, " %.3f %.3f scale\n", scalex, scaley);
  401.         for (i=0; i<no_obj; i++)
  402.         {
  403.            fprintf(tfp, "o%d ", i);
  404.            if (!(i%20)) fprintf(tfp, "\n", i);
  405.         }
  406.         fprintf(tfp, "showpage\n");
  407.         page++;
  408.      }
  409.        }
  410.     }
  411.     else
  412.        if (show_page) fprintf(tfp, "showpage\n");
  413.     fprintf(tfp, "$F2psEnd\n");
  414. }
  415.  
  416. static set_style(s, v)
  417. int    s;
  418. double    v;
  419. {
  420.     if (s == DASH_LINE) {
  421.         if (v > 0.0) fprintf(tfp, "\t[%f] 0 setdash\n", v);
  422.         }
  423.     else if (s == DOTTED_LINE) {
  424.         if (v > 0.0) fprintf(tfp, "\t1 setlinecap [1 %f] %f setdash\n", v, v);
  425.         }
  426.     }
  427.  
  428. static reset_style(s, v)
  429. int    s;
  430. double    v;
  431. {
  432.     if (s == DASH_LINE) {
  433.         if (v > 0.0) fprintf(tfp, "\t[] 0 setdash\n");
  434.         }
  435.     else if (s == DOTTED_LINE) {
  436.         if (v > 0.0) fprintf(tfp, "\t[] 0 setdash 0 setlinecap\n");
  437.         }
  438.     }
  439.  
  440. static set_linewidth(w)
  441. int    w;
  442. {
  443.     extern int    cur_thickness;
  444.  
  445.     if (w != cur_thickness) {
  446.         cur_thickness = w;
  447.         fprintf(tfp, "%.3f setlinewidth\n", cur_thickness <= 1 ? 0.5* cur_thickness : cur_thickness -1.0);
  448.         }
  449.     }
  450.  
  451. void genps_line(l)
  452. F_line    *l;
  453. {
  454.     F_point        *p, *q;
  455.     /* JNT */
  456.     int        radius, i = 0;
  457.     FILE        *epsf;
  458.     char        buf[512];
  459.     char        *cp;
  460.     int        xmin,xmax,ymin,ymax;
  461.     int        eps_w, eps_h;
  462.     double        fllx, flly, furx, fury;
  463.     
  464.     if (multi_page)
  465.        fprintf(tfp, "/o%d {", no_obj++);
  466.     if (l->type != T_EPS_BOX)  /* eps object has no line thickness */
  467.         set_linewidth(l->thickness);
  468.     radius = l->radius;        /* radius of rounded-corner boxes */
  469.     p = l->points;
  470.     q = p->next;
  471.     if (q == NULL) { /* A single point line */
  472.         fprintf(tfp, "n %d %d m %d %d l gs col%d s gr\n",
  473.             p->x, p->y, p->x, p->y, l->color > MAXCOLORS ? -1 : l->color);
  474.         if (multi_page)
  475.            fprintf(tfp, "} bind def\n");
  476.         return;
  477.         }
  478.     if (l->back_arrow && l->thickness > 0)
  479.         draw_arrow_head((double)q->x, (double)q->y, (double)p->x,
  480.             (double)p->y, l->back_arrow->ht, l->back_arrow->wid,
  481.             l->color);
  482.     if (l->type != T_EPS_BOX)  /* eps object has no line style */
  483.         set_style(l->style, l->style_val);
  484.     fprintf(tfp, "%% Polyline\n");
  485.  
  486.     xmin = xmax = p->x;
  487.     ymin = ymax = p->y;
  488.     while (p->next != NULL) /* find lower left and upper right corne
  489. rs */
  490.     {
  491.         p=p->next;
  492.         if (xmin > p->x)
  493.             xmin = p->x;
  494.         else if (xmax < p->x)
  495.             xmax = p->x;
  496.         if (ymin > p->y)
  497.             ymin = p->y;
  498.         else if (ymax < p->y)
  499.             ymax = p->y;
  500.         }
  501.  
  502.     if (l->type == T_ARC_BOX)
  503.     {
  504.         fprintf(tfp, "n %d %d m",xmin+radius, ymin);
  505.         fprintf(tfp, " %d %d %d %d %d arcto 4 {pop} repeat",
  506.                 xmin, ymin, xmin, ymax-radius, radius);
  507.         fprintf(tfp, " %d %d %d %d %d arcto 4 {pop} repeat", /* arc through bl to br */
  508.                 xmin, ymax, xmax-radius, ymax, radius);
  509.         fprintf(tfp, " %d %d %d %d %d arcto 4 {pop} repeat", /* arc through br to tr */
  510.                 xmax, ymax, xmax, ymin+radius, radius);
  511.         fprintf(tfp, " %d %d %d %d %d arcto 4 {pop} repeat", /* arc through tr to tl */
  512.                 xmax, ymin, xmin+radius, ymin, radius);
  513.     }
  514.     else if (l->type == T_EPS_BOX)  /* encapsulated postscript (eps) file */
  515.     {
  516.         int             dx, dy, rotation;
  517.         int        llx, lly, urx, ury;
  518.         double          fllx, flly, furx, fury;
  519.  
  520.         dx = l->points->next->next->x - l->points->x;
  521.         dy = l->points->next->next->y - l->points->y;
  522.         rotation = 0;
  523.         if (dx < 0 && dy < 0)
  524.                rotation = 180;
  525.         else if (dx < 0 && dy >= 0)
  526.                rotation = 270;
  527.         else if (dy < 0 && dx >= 0)
  528.                rotation = 90;
  529.  
  530.         fprintf(tfp, "%%\n");
  531.         fprintf(tfp, "%% Begin Imported EPS File: %s\n", l->eps->file);
  532.         fprintf(tfp, "%%\n");
  533.         epsf = fopen(l->eps->file, "r");
  534.         if (epsf == NULL) {
  535.             fprintf (stderr, "Unable to open eps file: %s, error: (%d)\n",
  536.                 l->eps->file, sys_errlist[errno],errno);
  537.             return;
  538.         }
  539.         while (fgets(buf, 512, epsf) != NULL) {
  540.           lower(buf);
  541.           if (!strncmp(buf, "%%boundingbox", 13)) {
  542.             if (sscanf(buf, "%%%%boundingbox: %lf %lf %lf %lf",
  543.                        &fllx, &flly, &furx, &fury) < 4) {
  544.               fprintf(stderr,"Bad EPS bitmap file: %s", l->eps->file);
  545.               fclose(epsf);
  546.               return;
  547.             }
  548.             llx= floor(fllx);
  549.             lly= floor(flly);
  550.             urx= ceil(furx);
  551.             ury= ceil(fury);
  552.             break;
  553.           }
  554.         }
  555.         fclose(epsf);
  556.  
  557.         fprintf(tfp, "n gs\n");
  558.         if (((rotation == 90 || rotation == 270) && !l->eps->flipped) ||
  559.             (rotation != 90 && rotation != 270 && l->eps->flipped)) {
  560.             eps_h = urx - llx;
  561.             eps_w = ury - lly;
  562.         } else {
  563.             eps_w = urx - llx;
  564.             eps_h = ury - lly;
  565.         }
  566.  
  567.         /* translate the eps stuff to the right spot on the page */
  568.         fprintf(tfp, "%d %d translate\n", xmin, ymin);
  569.  
  570.         /* scale the eps stuff to fit into the bounding box */
  571.         /* Note: the origin for fig is in the upper-right corner;
  572.          *       for postscript its in the lower right hand corner.
  573.          *       To fix it, we use a "negative"-y scale factor, then
  574.          *       translate the image up on the page */
  575.         fprintf(tfp, "%f %f scale\n",
  576.             fabs((double)(xmax-xmin)/eps_w), -1.0*(double)(ymax-ymin)/eps_h);
  577.         fprintf(tfp, "0 %d translate\n", -eps_h);
  578.  
  579.         /* flip the eps stuff */
  580.         /* always translate it back so that the lower-left corner is at the origin */
  581.         if (l->eps->flipped && rotation==90) {
  582.             fprintf(tfp, "0 %d translate\n", eps_h);
  583.             fprintf(tfp, "1 -1 scale\n");
  584.         }
  585.         if (l->eps->flipped && rotation==270) {
  586.             fprintf(tfp, "%d 0 translate\n", eps_w);
  587.             fprintf(tfp, "-1 1 scale\n");
  588.         }
  589.  
  590.         /* note: fig measures rotation clockwise; postscript is counter-clockwise */
  591.         /* always translate it back so that the lower-left corner is at the origin */
  592.         switch (rotation) {
  593.            case 0:
  594.             break;
  595.            case 90:
  596.             if (l->eps->flipped) break;
  597.             fprintf(tfp, "%d %d translate\n", 0, eps_h);
  598.             fprintf(tfp, "%d rotate\n", 270);
  599.             break;
  600.            case 180:
  601.             fprintf(tfp, "%d %d translate\n", eps_w, eps_h);
  602.             fprintf(tfp, "%d rotate\n", 180);
  603.             break;
  604.            case 270:
  605.             if (l->eps->flipped) break;
  606.             fprintf(tfp, "%d %d translate\n", eps_w, 0);
  607.             fprintf(tfp, "%d rotate\n", 90);
  608.             break;
  609.         }
  610.  
  611.         /* translate the eps stuff so that the lower-left corner is at the origin */
  612.         fprintf(tfp, "%d %d translate\n", -llx, -lly);
  613.         /* save vm so eps file won't change anything */
  614.         fprintf(tfp, "save\n");
  615.         fprintf(tfp, "%% EPS file follows:\n");
  616.         epsf = fopen(l->eps->file, "r");
  617.         if (epsf == NULL) {
  618.             fprintf (stderr, "Unable to open eps file: %s, error: (%d)\n",
  619.                 l->eps->file, sys_errlist[errno],errno);
  620.             fprintf(tfp, "gr\n");
  621.             return;
  622.         }
  623.         while (fgets(buf, sizeof(buf), epsf) != NULL) {
  624.             if (*buf == '%')        /* skip comment lines */
  625.                 continue;
  626.             if ((cp=strstr(buf, "showpage")) != NULL)
  627.                 strcpy (cp, cp+8);    /* remove showpage */
  628.             fputs(buf, tfp);
  629.         }
  630.         fclose (epsf);
  631.         /* restore vm and gsave */
  632.         fprintf(tfp, "restore gr\n");
  633.         fprintf(tfp, "%%\n");
  634.         fprintf(tfp, "%% End Imported EPS File: %s\n", l->eps->file);
  635.         fprintf(tfp, "%%\n");
  636.     }
  637.     else
  638.     {
  639.         p = l->points;
  640.         q = p->next;
  641.         fprintf(tfp, "n %d %d m", p->x, p->y);
  642.         while (q->next != NULL) {
  643.             p = q;
  644.             q = q->next;
  645.             fprintf(tfp, " %d %d l ", p->x, p->y);
  646.                  if (!((++i)%5)) 
  647.             fprintf(tfp, "\n");
  648.         }
  649.     }
  650.     if (l->type != T_EPS_BOX) {
  651.         if (l->type == T_POLYLINE)
  652.             fprintf(tfp, " %d %d l ", q->x, q->y);
  653.         else 
  654.             fprintf(tfp, " clp ");
  655.         if (l->area_fill && (int)l->area_fill != DEFAULT)
  656.             fill_area(l->area_fill, l->color);
  657.         if (l->thickness > 0)
  658.              fprintf(tfp, "gs col%d s gr\n",
  659.                 l->color > MAXCOLORS ? -1 : l->color);
  660.  
  661.         reset_style(l->style, l->style_val);
  662.         if (l->for_arrow && l->thickness > 0)
  663.             draw_arrow_head((double)p->x, (double)p->y, (double)q->x,
  664.                 (double)q->y, l->for_arrow->ht, l->for_arrow->wid,
  665.                 l->color);
  666.     }
  667.     if (multi_page)
  668.        fprintf(tfp, "} bind def\n");
  669.     }
  670.  
  671. void genps_spline(s)
  672. F_spline    *s;
  673. {
  674.     if (multi_page)
  675.        fprintf(tfp, "/o%d {", no_obj++);
  676.     if (int_spline(s))
  677.         genps_itp_spline(s);
  678.     else
  679.         genps_ctl_spline(s);
  680.     if (multi_page)
  681.        fprintf(tfp, "} bind def\n");
  682.     }
  683.  
  684. genps_itp_spline(s)
  685. F_spline    *s;
  686. {
  687.     F_point        *p, *q;
  688.     F_control    *a, *b;
  689.  
  690.     set_linewidth(s->thickness);
  691.     a = s->controls;
  692.     p = s->points;
  693.     if (s->back_arrow && s->thickness > 0)
  694.         draw_arrow_head(a->rx, a->ry, (double)p->x,
  695.             (double)p->y, s->back_arrow->ht, s->back_arrow->wid,
  696.             s->color);
  697.  
  698.     set_style(s->style, s->style_val);
  699.     fprintf(tfp, "%% Interpolated spline\n");
  700.     fprintf(tfp, "n %d %d m\n", p->x, p->y);
  701.     for (q = p->next; q != NULL; p = q, q = q->next) {
  702.         b = a->next;
  703.         fprintf(tfp, "\t%.3f %.3f %.3f %.3f %d %d curveto\n",
  704.             a->rx, a->ry, b->lx, b->ly, q->x, q->y);
  705.         a = b;
  706.         }
  707.     if (closed_spline(s)) fprintf(tfp, " clp ");
  708.     if (s->area_fill && (int)s->area_fill != DEFAULT)
  709.         fill_area(s->area_fill, s->color);
  710.     if (s->thickness > 0)
  711.         fprintf(tfp, "gs col%d s gr\n", s->color > MAXCOLORS ? -1 : s->color);
  712.     reset_style(s->style, s->style_val);
  713.  
  714.     if (s->for_arrow && s->thickness > 0)
  715.         draw_arrow_head(a->lx, a->ly, (double)p->x,
  716.             (double)p->y, s->for_arrow->ht, s->for_arrow->wid,
  717.             s->color);
  718.     }
  719.  
  720. genps_ctl_spline(s)
  721. F_spline    *s;
  722. {
  723.     double        a, b, c, d, x1, y1, x2, y2, x3, y3;
  724.     F_point        *p, *q;
  725.  
  726.     /*
  727.     if (first) {
  728.         first = FALSE;
  729.         fprintf(tfp, "%s\n", SPLINE_PS);
  730.         }
  731.     */
  732.  
  733.     p = s->points;
  734.     x1 = p->x; y1 = p->y;
  735.     p = p->next;
  736.     c = p->x; d = p->y;
  737.     set_linewidth(s->thickness);
  738.     x3 = a = (x1 + c) / 2;
  739.     y3 = b = (y1 + d) / 2;
  740.     if (s->back_arrow && s->thickness > 0) {
  741.         draw_arrow_head(c, d, x1, y1, s->back_arrow->ht, s->back_arrow->wid,
  742.                 s->color);
  743.         }
  744.     set_style(s->style, s->style_val);
  745.     if (! closed_spline(s)) {
  746.         fprintf(tfp, "%% Open spline\n");
  747.         fprintf(tfp, "n %.3f %.3f m %.3f %.3f l\n",
  748.             x1, y1, x3, y3);
  749.         }
  750.     else {
  751.         fprintf(tfp, "%% Closed spline\n");
  752.         fprintf(tfp, "n %.3f %.3f m\n", a, b);
  753.         }
  754.     for (q = p->next; q != NULL; p = q, q = q->next) {
  755.         x1 = x3; y1 = y3;
  756.         x2 = c;  y2 = d;
  757.         c = q->x; d = q->y;
  758.         x3 = (x2 + c) / 2;
  759.         y3 = (y2 + d) / 2;
  760.         fprintf(tfp, "\t%.3f %.3f %.3f %.3f %.3f %.3f DrawSplineSection\n",
  761.             x1, y1, x2, y2, x3, y3);
  762.         }
  763.     /*
  764.     * At this point, (x2,y2) and (c,d) are the position of the 
  765.     * next-to-last and last point respectively, in the point list
  766.     */
  767.     if (closed_spline(s)) {
  768.         fprintf(tfp, "\t%.3f %.3f %.3f %.3f %.3f %.3f DrawSplineSection closepath ",
  769.             x3, y3, c, d, a, b);
  770.         }
  771.     else {
  772.         fprintf(tfp, "\t%.3f %.3f l ", c, d);
  773.         }
  774.     if (s->area_fill && (int)s->area_fill != DEFAULT)
  775.         fill_area(s->area_fill, s->color);
  776.     if (s->thickness > 0)
  777.         fprintf(tfp, "gs col%d s gr\n", s->color > MAXCOLORS ? -1 : s->color);
  778.     reset_style(s->style, s->style_val);
  779.     if (s->for_arrow && s->thickness > 0) {
  780.         draw_arrow_head(x2, y2, c, d, s->for_arrow->ht,
  781.                 s->for_arrow->wid, s->color);
  782.         }
  783.     }
  784.  
  785. void genps_ellipse(e)
  786. F_ellipse    *e;
  787. {
  788.     if (multi_page)
  789.        fprintf(tfp, "/o%d {", no_obj++);
  790.     set_linewidth(e->thickness);
  791.     set_style(e->style, e->style_val);
  792.     if (e->angle == 0)
  793.     {
  794.         fprintf(tfp, "%% Ellipse\n");
  795.         fprintf(tfp, "n %d %d %d %d 0 360 DrawEllipse ",
  796.           e->center.x, e->center.y, e->radiuses.x, e->radiuses.y);
  797.     }
  798.     else
  799.     {
  800.         fprintf(tfp, "%% Rotated Ellipse\n");
  801.         fprintf(tfp, "gs\n");
  802.         fprintf(tfp, "%d %d translate\n",e->center.x, e->center.y);
  803.         fprintf(tfp, "%6.3f rotate\n",-e->angle*180/M_PI);
  804.         fprintf(tfp, "n 0 0 %d %d 0 360 DrawEllipse ",
  805.          e->radiuses.x, e->radiuses.y);
  806.     }
  807.     if (e->area_fill && (int)e->area_fill != DEFAULT)
  808.         fill_area(e->area_fill, e->color);
  809.     if (e->thickness > 0)
  810.         fprintf(tfp, "gs col%d s gr\n", e->color > MAXCOLORS ? -1 : e->color);
  811.     if (e->angle != 0)
  812.         fprintf(tfp, "gr\n");
  813.     reset_style(e->style, e->style_val);
  814.     if (multi_page)
  815.        fprintf(tfp, "} bind def\n");
  816.     }
  817.  
  818. #define    TEXT_PS        "\
  819. /%s%s findfont %.2f scalefont setfont\n\
  820. "
  821. void genps_text(t)
  822. F_text    *t;
  823. {
  824.     unsigned char        *cp;
  825.  
  826.     if (multi_page)
  827.        fprintf(tfp, "/o%d {", no_obj++);
  828.     if (PSisomap[t->font+1] == TRUE)
  829.        fprintf(tfp, TEXT_PS, PSFONT(t), "-iso", PSFONTMAG(t));
  830.     else
  831.        fprintf(tfp, TEXT_PS, PSFONT(t), "", PSFONTMAG(t));
  832.  
  833.     fprintf(tfp, "%d %d m \ngs ", t->base_x,  t->base_y);
  834.     if (coord_system == 2) fprintf(tfp, "1 -1 scale ");
  835.  
  836.     if (t->angle != 0)
  837.        fprintf(tfp, " %.1f rotate ", t->angle*180/M_PI);
  838.     /* this loop escapes characters '(', ')', and '\' */
  839.     fputc('(', tfp);
  840.     for(cp = (unsigned char *)t->cstring; *cp; cp++) {
  841.         if (strchr("()\\", *cp)) 
  842.         fputc('\\', tfp);
  843.         if (*cp>=0x80)
  844.         fprintf(tfp,"\\%o", *cp);
  845.         else
  846.         fputc(*cp, tfp);
  847.         }
  848.     fputc(')', tfp);
  849.  
  850.     if ((t->type == T_CENTER_JUSTIFIED) || (t->type == T_RIGHT_JUSTIFIED)){
  851.  
  852.           fprintf(tfp, " dup stringwidth pop ");
  853.         if (t->type == T_CENTER_JUSTIFIED) fprintf(tfp, "2 div ");
  854.         fprintf(tfp, "neg 0 rmoveto ");
  855.         }
  856.  
  857.     else if ((t->type != T_LEFT_JUSTIFIED) && (t->type != DEFAULT))
  858.         fprintf(stderr, "Text incorrectly positioned\n");
  859.  
  860.     fprintf(tfp, " col%d show gr\n", t->color > MAXCOLORS ? -1 : t->color);
  861.  
  862.     if (multi_page)
  863.        fprintf(tfp, "} bind def\n");
  864.     }
  865.  
  866. void genps_arc(a)
  867. F_arc    *a;
  868. {
  869.     double        angle1, angle2, dx, dy, radius, x, y;
  870.     double        cx, cy, sx, sy, ex, ey;
  871.     int        direction;
  872.  
  873.     if (multi_page)
  874.        fprintf(tfp, "/o%d {", no_obj++);
  875.     cx = a->center.x; cy = a->center.y;
  876.     sx = a->point[0].x; sy = a->point[0].y;
  877.     ex = a->point[2].x; ey = a->point[2].y;
  878.  
  879.     if (coord_system == 2)
  880.         direction = !a->direction;
  881.     else
  882.         direction = a->direction;
  883.     set_linewidth(a->thickness);
  884.     if (a->for_arrow && a->thickness > 0) {
  885.         arc_tangent(cx, cy, ex, ey, direction, &x, &y);
  886.         draw_arrow_head(x, y, ex, ey, a->for_arrow->ht, a->for_arrow->wid, a->color);
  887.         }
  888.     if (a->back_arrow && a->thickness > 0) {
  889.         arc_tangent(cx, cy, sx, sy, !direction, &x, &y);
  890.         draw_arrow_head(x, y, sx, sy, a->back_arrow->ht, a->back_arrow->wid, a->color);
  891.         }
  892.     dx = cx - sx;
  893.     dy = cy - sy;
  894.     radius = sqrt(dx*dx+dy*dy);
  895.     angle1 = atan2(sy-cy, sx-cx) * 180 / M_PI;
  896.     angle2 = atan2(ey-cy, ex-cx) * 180 / M_PI;
  897.     /* direction = 1 -> Counterclockwise */
  898.     set_style(a->style, a->style_val);
  899.     fprintf(tfp, "n %.3f %.3f %.3f %.3f %.3f %s\n",
  900.         cx, cy, radius, angle1, angle2,
  901.         ((direction == 1) ? "arc" : "arcn"));
  902.     if (a->area_fill && (int)a->area_fill != DEFAULT)
  903.         fill_area(a->area_fill, a->color);
  904.     if (a->thickness > 0)
  905.         fprintf(tfp, "gs col%d s gr\n", a->color > MAXCOLORS ? -1 : a->color);
  906.     reset_style(a->style, a->style_val);
  907.     if (multi_page)
  908.        fprintf(tfp, "} bind def\n");
  909.     }
  910.  
  911. static arc_tangent(x1, y1, x2, y2, direction, x, y)
  912. double    x1, y1, x2, y2, *x, *y;
  913. int    direction;
  914. {
  915.     if (direction) { /* counter clockwise  */
  916.         *x = x2 + (y2 - y1);
  917.         *y = y2 - (x2 - x1);
  918.         }
  919.     else {
  920.         *x = x2 - (y2 - y1);
  921.         *y = y2 + (x2 - x1);
  922.         }
  923.     }
  924.  
  925. /*    draw arrow heading from (x1, y1) to (x2, y2)    */
  926.  
  927. static draw_arrow_head(x1, y1, x2, y2, arrowht, arrowwid, col)
  928. double    x1, y1, x2, y2, arrowht, arrowwid;
  929. int col;
  930. {
  931.     double    x, y, xb, yb, dx, dy, l, sina, cosa;
  932.     double    xc, yc, xd, yd;
  933.  
  934.     dx = x2 - x1;  dy = y1 - y2;
  935.     l = sqrt(dx*dx+dy*dy);
  936.     if (l == 0) {
  937.          return;
  938.     }
  939.     else {
  940.          sina = dy / l;  cosa = dx / l;
  941.     }
  942.     xb = x2*cosa - y2*sina;
  943.     yb = x2*sina + y2*cosa;
  944.     x = xb - arrowht;
  945.     y = yb - arrowwid / 2;
  946.     xc = x*cosa + y*sina;
  947.     yc = -x*sina + y*cosa;
  948.     y = yb + arrowwid / 2;
  949.     xd = x*cosa + y*sina;
  950.     yd = -x*sina + y*cosa;
  951.     fprintf(tfp, "n %.3f %.3f m %.3f %.3f l %.3f %.3f l gs 2 setlinejoin col%d s gr\n", xc, yc, x2, y2, xd, yd, col > MAXCOLORS ? -1 : col);
  952.     }
  953.  
  954. static fill_area(fill, color)
  955. int fill, color;
  956. {
  957.    if (color < 1)   /* use gray levels for default and black */
  958.     fprintf(tfp, "gs %.2f setgray fill gr\n", 1.0 - GRAYVAL(fill));
  959.    else
  960.     fprintf(tfp, "gs col%d %.2f graycol fill gr ",
  961.         color > MAXCOLORS ? -1 : color, GRAYVAL(fill));
  962. }
  963.  
  964. static iso_text_exist(ob)
  965. F_compound      *ob;
  966. {
  967.    F_compound    *c;
  968.    F_text          *t;
  969.    unsigned char   *s;
  970.  
  971.    if (ob->texts != NULL)
  972.    {
  973.       for (t = ob->texts; t != NULL; t = t->next)
  974.       {
  975.      for (s = (unsigned char*)t->cstring; *s != '\0'; s++)
  976.      {
  977.         /* look for characters >= 128 */
  978.         if (*s>127) return(1);
  979.      }
  980.       }
  981.    }
  982.  
  983.    for (c = ob->compounds; c != NULL; c = c->next) {
  984.        if (iso_text_exist(c)) return(1);
  985.        }
  986.    return(0);
  987. }
  988.  
  989. static encode_all_fonts(ob)
  990. F_compound    *ob;
  991. {
  992.    F_compound *c;
  993.    F_text     *t;
  994.  
  995.    if (ob->texts != NULL)
  996.    {
  997.     for (t = ob->texts; t != NULL; t = t->next)
  998.         if (PSisomap[t->font+1] == FALSE)
  999.         {
  1000.         fprintf(tfp, "/%s /%s-iso isovec ReEncode\n", PSFONT(t), PSFONT(t));
  1001.         PSisomap[t->font+1] = TRUE;
  1002.         }
  1003.    }
  1004.  
  1005.    for (c = ob->compounds; c != NULL; c = c->next) 
  1006.    {
  1007.     encode_all_fonts(c);
  1008.    }
  1009. }
  1010.  
  1011. static ellipse_exist(ob)
  1012. F_compound    *ob;
  1013. {
  1014.     F_compound    *c;
  1015.  
  1016.     if (NULL != ob->ellipses) return(1);
  1017.  
  1018.     for (c = ob->compounds; c != NULL; c = c->next) {
  1019.         if (ellipse_exist(c)) return(1);
  1020.         }
  1021.  
  1022.     return(0);
  1023.     }
  1024.  
  1025. static normal_spline_exist(ob)
  1026. F_compound    *ob;
  1027. {
  1028.     F_spline    *s;
  1029.     F_compound    *c;
  1030.  
  1031.     for (s = ob->splines; s != NULL; s = s->next) {
  1032.         if (normal_spline(s)) return(1);
  1033.         }
  1034.  
  1035.     for (c = ob->compounds; c != NULL; c = c->next) {
  1036.         if (normal_spline_exist(c)) return(1);
  1037.         }
  1038.  
  1039.     return(0);
  1040.     }
  1041.  
  1042. struct driver dev_ps = {
  1043.          genps_option,
  1044.     genps_start,
  1045.     genps_arc,
  1046.     genps_ellipse,
  1047.     genps_line,
  1048.     genps_spline,
  1049.     genps_text,
  1050.     genps_end,
  1051.     INCLUDE_TEXT
  1052. };
  1053.