home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume8 / xfig2.8 / part14 / f2ps.c next >
C/C++ Source or Header  |  1990-07-03  |  20KB  |  832 lines

  1. /* 
  2.  *    F2ps : Fig-to-PostScript translator
  3.  *
  4.  *    Copyright (c) 1986 by Supoj Sutanthavibul (supoj@sally.UTEXAS.EDU)
  5.  *    June 1986.
  6.  *    1st revision : March 1988 - read fig 1.4 or 1.4X format
  7.  *
  8.  *    Version 2.0 additions (protocol 1.4X) by B.V. Smith 2/90
  9.  *
  10.  *    %W%    %G%
  11. */
  12. #include "fig.h"
  13. #include "object.h"
  14. #include "resources.h"
  15. #include "psfonts.h"
  16.  
  17. #define        PAGE_WIDTH        612    /* points; 8.5" */
  18. #define        PAGE_HEIGHT        792    /* points; 11" */
  19. #define        POINT_PER_INCH        72
  20. #define        DEFAULT_FONT_SIZE    11
  21. #define        DEFAULT_FONT        "Times-Roman"
  22.  
  23. extern    struct _fstruct fontnames[];    /* printer font names */
  24.  
  25. char        Usage[] = "Usage: %s [-P][-L][-f font][-s size][-e scale][-N][-c] [input [output]]\n";
  26. char        *prog;
  27. char        *font = DEFAULT_FONT;
  28. int        font_size = DEFAULT_FONT_SIZE;
  29. int        cur_thickness;
  30. int        cur_areafill=0;
  31. int        show_page = 1;
  32. int        center = 0;
  33. int        landscape = 1;
  34. double        scale = 1.0;
  35. double        reduction;    /* converts screen ppi to printer points */
  36. extern int    num_object;
  37. char        *from = NULL, *to = NULL;
  38. FILE        *tfp = NULL;
  39. char        Err_incomp[] = "Incomplete %s object at line %d.";
  40. char        Err_mem[] = "Running out of memory.";
  41.  
  42. int        line_thickness; /* not needed for f2ps, arrow.c needs it for fig */
  43.  
  44. get_args(argc, argv)
  45. int     argc;
  46. char    *argv[];
  47. {
  48.     char    *a;
  49.     int    first = 1;
  50.  
  51.     prog = *argv;
  52.     while (--argc) {
  53.         a = *++argv;
  54.         if (*a == '-') {
  55.         if (*++a == 'f') {    /* Font name followed */
  56.             if (--argc)
  57.             font = *++argv;
  58.             else
  59.             goto error_exit;
  60.             }
  61.         else if (*a == 'c') {    /* Centering */
  62.             center = 1;
  63.             }
  64.         else if (*a == 'l' || *a == 'L') {    /* Landscape */
  65.             landscape = 1;
  66.             }
  67.         else if (*a == 'p' || *a == 'P') {    /* Portrait */
  68.             landscape = 0;
  69.             }
  70.         else if (*a == 's') {    /* Font size followed */
  71.             if (--argc) {
  72.             font_size = atoi(*++argv);
  73.             }
  74.             else
  75.             goto error_exit;
  76.             }
  77.         else if (*a == 'e') {    /* Enlarging factor followed */
  78.             if (--argc)
  79.             scale = atof(*++argv);
  80.             else
  81.             goto error_exit;
  82.             }
  83.         else if (*a == 'N') {    /* No "showpage" */
  84.             show_page = 0;
  85.             }
  86.         else
  87.             goto error_exit;
  88.         }
  89.         else if (first) {
  90.         from = a;    /*  from file  */
  91.         first = 0;
  92.         }
  93.         else if (first == 0) {
  94.         to = a;        /*  to file  */
  95.         first = -1;
  96.         }
  97.         else
  98.         goto error_exit;
  99.         }
  100.     return;
  101.  
  102.     error_exit:
  103.     fprintf(stderr, Usage, prog);
  104.     exit(1);
  105.     }
  106.  
  107. main(argc, argv)
  108. int     argc;
  109. char    *argv[];
  110. {
  111.     F_compound    objects;
  112.     int        status;
  113.  
  114.     get_args(argc, argv);
  115.  
  116.     if (to == NULL)
  117.         tfp = stdout;
  118.     else if ((tfp = fopen(to, "w")) == NULL) {
  119.         fprintf(stderr, "%s: Couldn't open %s", prog, to);
  120.         fprintf(stderr, Usage, prog);
  121.         exit(1);
  122.         }
  123.  
  124.     if (from)
  125.         status = read_fig(from, &objects);
  126.     else     /* read from stdin */
  127.         status = readfp_fig(stdin, &objects);
  128.  
  129.     if (status != 0) {
  130.         if (from) read_fail_message(from, status);
  131.         exit(1);
  132.         }
  133.     genps_objects(&objects);
  134.     if (tfp != stdout) (void)fclose(tfp);
  135.     exit(0); }
  136.  
  137. #define        BEGIN_PROLOG    "\
  138. /$F2psDict 32 dict def \
  139. $F2psDict begin\
  140.  $F2psDict /mtrx matrix put\
  141. "
  142. #define        ELLIPSE_PS    " \
  143. /DrawEllipse {\
  144.  /endangle exch def\
  145.  /startangle exch def\
  146.  /yrad exch def\
  147.  /xrad exch def\
  148.  /y exch def\
  149.  /x exch def\
  150.  /savematrix mtrx currentmatrix def\
  151.  x y translate xrad yrad scale 0 0 1 startangle endangle arc\
  152.  savematrix setmatrix\
  153.  } def\
  154. "
  155. #define        SPLINE_PS    " \
  156. /DrawSplineSection {\
  157.  /y3 exch def\
  158.  /x3 exch def\
  159.  /y2 exch def\
  160.  /x2 exch def\
  161.  /y1 exch def\
  162.  /x1 exch def\
  163.  /xa x1 x2 add 2 div def\
  164.  /ya y1 y2 add 2 div def\
  165.  /xb x2 x3 add 2 div def\
  166.  /yb y2 y3 add 2 div def\
  167.  /x2 xa xb add 2 div def\
  168.  /y2 ya yb add 2 div def x1 x2 sub abs 2 lt y1 y2 sub abs 2 lt and\
  169.   { x2 y2 lineto }\
  170.   { x2 y2 xb yb x3 y3 x1 y1 xa ya x2 y2 DrawSplineSection\
  171.   /y3 exch def\
  172.   /x3 exch def\
  173.   /yb exch def\
  174.   /xb exch def\
  175.   /y2 exch def\
  176.   /x2 exch def}\
  177.  ifelse\
  178.  x2 x3 sub abs 2 lt y2 y3 sub abs 2 lt and { x3 y3 lineto }\
  179.  { x2 y2 xb yb x3 y3 DrawSplineSection } ifelse\
  180.  } def\
  181. "
  182. #define        END_PROLOG    "\
  183.  end\
  184.  /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def\
  185.  /$F2psEnd {$F2psEnteredState restore end} def\
  186. \n%%EndProlog\
  187. "
  188.  
  189. #define        MAX    32000
  190. #define        MIN    -32000
  191. static int    coord_system;
  192. static int    llx = MAX, lly = MAX, urx = MIN, ury = MIN;
  193.  
  194. prolog(objects)
  195. F_compound    *objects;
  196. {
  197.     char        host[256];
  198.     struct passwd    *who;
  199.     long        when;
  200.     extern char    *ctime(), *strcpy();
  201.     extern long    time();
  202.  
  203.     fprintf(tfp, "%%!\n");    /* PostScript magic strings */
  204.     who = getpwuid(getuid());
  205.     if (-1 == gethostname(host, sizeof(host)))
  206.         (void)strcpy(host, "unknown-host!?!?");
  207.     (void) time(&when);
  208.     fprintf(tfp, "%%%%Title: %s\n", ((from) ? from : "stdin"));
  209.     fprintf(tfp, "%%%%Creator: %s\n", prog);
  210.     fprintf(tfp, "%%%%CreationDate: %s", ctime(&when));
  211.     fprintf(tfp, "%%%%For: %s@%s (%s)\n",
  212.             who->pw_name, host, who->pw_gecos);
  213.     fprintf(tfp, "%%%%Pages: %d\n", show_page);
  214.       fprintf(tfp, "%%%%BoundingBox: %d %d %d %d\n", llx, lly, urx, ury);
  215.     fprintf(tfp, "%%%%EndComments\n");
  216.     fprintf(tfp, "%s\n", BEGIN_PROLOG);
  217.     if (ellipse_exist(objects)) 
  218.         fprintf(tfp, "%s\n", ELLIPSE_PS);
  219.     if (normal_spline_exist(objects)) 
  220.         fprintf(tfp, "%s\n", SPLINE_PS);
  221.     fprintf(tfp, "%s\n", END_PROLOG);
  222.     fprintf(tfp, "$F2psBegin\n");
  223.     }
  224.  
  225. epilog()
  226. {
  227.     if (show_page) fprintf(tfp, "showpage\n");
  228.     fprintf(tfp, "$F2psEnd\n");
  229.     }
  230.  
  231. genps_objects(objects)
  232. F_compound    *objects;
  233. {
  234.       double          scalex, scaley;
  235.       double          origx, origy, dx, dy;
  236.     F_arc        *a;
  237.     F_compound    *c;
  238.     F_ellipse    *e;
  239.     F_line        *l;
  240.     F_spline    *s;
  241.     F_text        *t;
  242.     int        fill;
  243.     int        itmp;
  244.  
  245.     /* Compute bounding box of objects */
  246.     compound_bound(objects, &llx, &lly, &urx, &ury);
  247.     if (llx > urx) {
  248.         fprintf(stderr, "%s: No object",prog);
  249.         return;
  250.         }
  251.       /* calculate reduction:
  252.               convert screen points-per-inch to printer points */
  253.     reduction = POINT_PER_INCH / (float)objects->nwcorner.x;
  254.     scalex = scaley = scale * reduction;
  255.       coord_system = objects->nwcorner.y;
  256.       if (coord_system == 2) {
  257.               scaley = -scaley;
  258.               itmp = lly; lly = ury; ury = itmp;
  259.               }
  260.     /* convert to point unit */
  261.     llx = (int)ceil(llx * scalex);
  262.     lly = (int)ceil(lly * scaley);
  263.     urx = (int)ceil(urx * scalex);
  264.     ury = (int)ceil(ury * scaley);
  265.       /* rotate bounding box if landscape mode */
  266.       if (landscape) {
  267.               itmp = ury; ury = -llx; llx = lly;
  268.               lly = -urx; urx = itmp;
  269.         }
  270.       /* center bounding box in page */
  271.     if (center) {
  272.               origx = -llx;
  273.               origy = -lly;
  274.  
  275.               dx = abs (urx - llx);
  276.               dy = abs (ury - lly);
  277.               llx = (PAGE_WIDTH - dx) / 2.0;
  278.               lly = (PAGE_HEIGHT - dy) / 2.0;
  279.               urx = llx + dx;
  280.               ury = lly + dy;
  281.               origx += llx;
  282.               origy += lly;
  283.               }
  284.     prolog(objects);
  285.  
  286.       /* center image on page */
  287.       if (center)
  288.               fprintf(tfp, "%f %f translate\n", origx, origy);
  289.  
  290.       /* scale image (=> "flip" if origin changing) */
  291.       fprintf(tfp, "%f %f scale\n", scalex, scaley);
  292.       /* rotate image if landscape mode */
  293.       if (landscape)
  294.               fprintf(tfp, "90 rotate\n");
  295.  
  296.     /* make first pass with area-filled objects; second with non-filled */
  297.     for (fill=1; fill>=0; fill--)
  298.         {
  299.         for (a = objects->arcs; a != NULL; a = a->next) 
  300.             genps_arc(a,fill);
  301.         for (c = objects->compounds; c != NULL; c = c->next) 
  302.             genps_compound(c,fill);
  303.         for (e = objects->ellipses; e != NULL; e = e->next) 
  304.             genps_ellipse(e,fill);
  305.         for (l = objects->lines; l != NULL; l = l->next) 
  306.             genps_line(l,fill);
  307.         for (s = objects->splines; s != NULL; s = s->next) 
  308.             genps_spline(s,fill);
  309.         }
  310.     /* do text after everything else */
  311.     for (t = objects->texts; t != NULL; t = t->next) 
  312.         genps_text(t);
  313.     epilog();
  314.     }
  315.  
  316. set_style(s, v)
  317. int    s;
  318. float    v;
  319. {
  320.     if (s == DASH_LINE) {
  321.         if (v > 0.0) fprintf(tfp, "\t[%f] 0 setdash\n", v);
  322.         }
  323.     else if (s == DOTTED_LINE) {
  324.         if (v > 0.0) fprintf(tfp, "\t[1 %f] 0 setdash\n", v);
  325.         }
  326.     }
  327.  
  328. reset_style(s, v)
  329. int    s;
  330. float    v;
  331. {
  332.     if (s == DASH_LINE) {
  333.         if (v > 0.0) fprintf(tfp, "\t[] 0 setdash\n");
  334.         }
  335.     else if (s == DOTTED_LINE) {
  336.         if (v > 0.0) fprintf(tfp, "\t[] 0 setdash\n");
  337.         }
  338.     }
  339.  
  340. set_areafill(a)
  341. int a;
  342. {
  343.     if (cur_areafill != a)
  344.         {
  345.         cur_areafill = a;
  346.         fprintf(tfp, "%.2f setgray\n",1.0-(a-1.0)/(NUMFILLPATS-1.0));
  347.         }
  348.     }
  349.  
  350. set_linewidth(w)
  351. int    w;
  352. {
  353.     extern int    cur_thickness;
  354.  
  355.     if (w != cur_thickness) {
  356.         cur_thickness = w;
  357.         fprintf(tfp, "%.3f setlinewidth\n", /* 0.7 * */ 1.0 * cur_thickness);
  358.         }
  359.     }
  360.  
  361. genps_compound(com,fill)
  362. F_compound    *com;
  363. int fill;
  364. {
  365.     F_arc        *a;
  366.     F_compound    *c;
  367.     F_ellipse    *e;
  368.     F_line        *l;
  369.     F_spline    *s;
  370.     F_text        *t;
  371.  
  372.     for (a = com->arcs; a != NULL; a = a->next) 
  373.         genps_arc(a,fill);
  374.     for (c = com->compounds; c != NULL; c = c->next) 
  375.         genps_compound(c,fill);
  376.     for (e = com->ellipses; e != NULL; e = e->next) 
  377.         genps_ellipse(e,fill);
  378.     for (l = com->lines; l != NULL; l = l->next) 
  379.         genps_line(l,fill);
  380.     for (s = com->splines; s != NULL; s = s->next) 
  381.         genps_spline(s,fill);
  382.     if (fill==0)    /* no filled text, just do text on the non-filled pass */
  383.         for (t = com->texts; t != NULL; t = t->next) 
  384.             genps_text(t);
  385.     }
  386.  
  387. genps_line(l,fill)
  388. F_line    *l;
  389. int fill;
  390. {
  391.     F_point        *p, *q;
  392.     int        radius;
  393.  
  394.     if ((fill && l->area_fill==0) ||
  395.         (fill==0 && l->area_fill))
  396.         return;
  397.  
  398.     set_linewidth(l->thickness);
  399.     radius = l->radius;        /* radius of rounded-corner boxes */
  400.     p = l->points;
  401.     q = p->next;
  402.     if (q == NULL) { /* A single point line */
  403.         if (l->thickness > 0)
  404.         fprintf(tfp, "newpath %d %d moveto %d %d lineto stroke\n",
  405.             p->x, p->y, p->x, p->y);
  406.         else
  407.         fprintf(tfp, "newpath %d %d moveto %d %d lineto\n",
  408.             p->x, p->y, p->x, p->y);
  409.         return;
  410.         }
  411.     if (l->back_arrow)
  412.         draw_arrow_head((float)q->x, (float)q->y, (float)p->x,
  413.             (float)p->y, l->back_arrow->ht, l->back_arrow->wid);
  414.     set_style(l->style, l->style_val);
  415.     fprintf(tfp, "%% Polyline\n");
  416.     if (l->type == T_ARC_BOX)    /* rounded-corner box */
  417.         {
  418.         register int xmin,xmax,ymin,ymax;
  419.  
  420.         xmin = xmax = p->x;
  421.         ymin = ymax = p->y;
  422.         while (p->next != NULL)    /* find lower left and upper right corners */
  423.             {
  424.             p=p->next;
  425.             if (xmin > p->x)
  426.                 xmin = p->x;
  427.             else if (xmax < p->x)
  428.                 xmax = p->x;
  429.             if (ymin > p->y)
  430.                 ymin = p->y;
  431.             else if (ymax < p->y)
  432.                 ymax = p->y;
  433.             }
  434.         fprintf(tfp, "newpath %d %d moveto",xmin+radius, ymin);
  435.         fprintf(tfp, " %d %d %d %d %d arcto 4 {pop} repeat",
  436.                 xmin, ymin, xmin, ymax-radius, radius);
  437.         fprintf(tfp, " %d %d %d %d %d arcto 4 {pop} repeat", /* arc through bl to br */
  438.                 xmin, ymax, xmax-radius, ymax, radius);
  439.         fprintf(tfp, " %d %d %d %d %d arcto 4 {pop} repeat", /* arc through br to tr */
  440.                 xmax, ymax, xmax, ymin+radius, radius);
  441.         fprintf(tfp, " %d %d %d %d %d arcto 4 {pop} repeat", /* arc through tr to tl */
  442.                 xmax, ymin, xmin+radius, ymin, radius);
  443.         }
  444.     else
  445.         {
  446.         fprintf(tfp, "newpath %d %d moveto", p->x, p->y);
  447.         while (q->next != NULL) {
  448.             p = q;
  449.             q = q->next;
  450.             fprintf(tfp, " %d %d lineto", p->x, p->y);
  451.             }
  452.         }
  453.     if (l->type == T_POLYLINE)
  454.         {
  455.         if (l->thickness > 0)
  456.         fprintf(tfp, " %d %d lineto stroke\n", q->x, q->y);
  457.         else
  458.         fprintf(tfp, " %d %d lineto\n", q->x, q->y);
  459.         }
  460.     else
  461.         {
  462.         fprintf(tfp, " closepath ");
  463.         if (l->area_fill)
  464.         {
  465.         set_areafill(l->area_fill);
  466.         fprintf(tfp, " gsave fill grestore ");
  467.         set_areafill(NUMFILLPATS);    /* back to black line */
  468.         }
  469.         if (l->thickness > 0)
  470.         fprintf(tfp, " stroke\n");
  471.         }
  472.  
  473.     reset_style(l->style, l->style_val);
  474.     if (l->for_arrow && l->thickness > 0)
  475.         draw_arrow_head((float)p->x, (float)p->y, (float)q->x,
  476.             (float)q->y, l->for_arrow->ht, l->for_arrow->wid);
  477.     }
  478.  
  479. genps_spline(s,fill)
  480. F_spline    *s;
  481. int fill;
  482. {
  483.     if (int_spline(s))
  484.         genps_itp_spline(s,fill);
  485.     else
  486.         genps_ctl_spline(s,fill);
  487.     }
  488.  
  489. genps_itp_spline(s,fill)
  490. F_spline    *s;
  491. int fill;
  492. {
  493.     F_point        *p, *q;
  494.     F_control    *a, *b;
  495.  
  496.     if ((fill && s->area_fill==0) ||
  497.         (fill==0 && s->area_fill))
  498.         return;
  499.  
  500.     set_linewidth(s->thickness);
  501.     a = s->controls;
  502.     b = a->next;
  503.     p = s->points;
  504.     if (s->back_arrow && s->thickness > 0)
  505.         draw_arrow_head(b->lx, b->ly, (float)p->x,
  506.             (float)p->y, s->back_arrow->ht, s->back_arrow->wid);
  507.  
  508.     set_style(s->style, s->style_val);
  509.     fprintf(tfp, "%% Interpolated spline\n");
  510.     fprintf(tfp, "newpath %d %d moveto\n", p->x, p->y);
  511.     for (q = p->next; q != NULL; p = q, q = q->next) {
  512.         b = a->next;
  513.         fprintf(tfp, "\t%.3f %.3f %.3f %.3f %d %d curveto\n",
  514.             a->rx, a->ry, b->lx, b->ly, q->x, q->y);
  515.         a = b;
  516.         }
  517.     if (closed_spline(s)) 
  518.         {
  519.         fprintf(tfp, " closepath ");
  520.         if (s->area_fill)
  521.             {
  522.             set_areafill(s->area_fill);
  523.             fprintf(tfp, " gsave fill grestore ");
  524.             set_areafill(NUMFILLPATS);    /* back to black for line */
  525.             }
  526.         }
  527.     if (s->thickness > 0)
  528.         fprintf(tfp, " stroke\n");
  529.     reset_style(s->style, s->style_val);
  530.  
  531.     if (s->for_arrow && s->thickness > 0)
  532.         draw_arrow_head(a->lx, a->ly, (float)p->x,
  533.             (float)p->y, s->for_arrow->ht, s->for_arrow->wid);
  534.     }
  535.  
  536. genps_ctl_spline(s,fill)
  537. F_spline    *s;
  538. int fill;
  539. {
  540.     float        a, b, c, d, x1, y1, x2, y2, x3, y3;
  541.     F_point        *p, *q;
  542.  
  543.     /*
  544.     if (first) {
  545.         first = FALSE;
  546.         fprintf(tfp, "%s\n", SPLINE_PS);
  547.         }
  548.     */
  549.  
  550.     if ((fill && s->area_fill==0) ||
  551.         (fill==0 && s->area_fill))
  552.         return;
  553.  
  554.     p = s->points;
  555.     x1 = p->x; y1 = p->y;
  556.     p = p->next;
  557.     c = p->x; d = p->y;
  558.     set_linewidth(s->thickness);
  559.     x3 = a = (x1 + c) / 2;
  560.     y3 = b = (y1 + d) / 2;
  561.     if (s->back_arrow && s->thickness > 0) {
  562.         draw_arrow_head(c, d, x1, y1, s->back_arrow->ht, s->back_arrow->wid);
  563.         }
  564.     set_style(s->style, s->style_val);
  565.     if (! closed_spline(s)) {
  566.         fprintf(tfp, "%% Open spline\n");
  567.         fprintf(tfp, "newpath %.3f %.3f moveto %.3f %.3f lineto\n",
  568.             x1, y1, x3, y3);
  569.         }
  570.     else {
  571.         fprintf(tfp, "%% Closed spline\n");
  572.         fprintf(tfp, "newpath %.3f %.3f moveto\n", a, b);
  573.         }
  574.     for (q = p->next; q != NULL; q = q->next) {
  575.         x1 = x3; y1 = y3;
  576.         x2 = c;  y2 = d;
  577.         c = q->x; d = q->y;
  578.         x3 = (x2 + c) / 2;
  579.         y3 = (y2 + d) / 2;
  580.         fprintf(tfp, "\t%.3f %.3f %.3f %.3f %.3f %.3f DrawSplineSection\n",
  581.             x1, y1, x2, y2, x3, y3);
  582.         }
  583.     /*
  584.     * At this point, (x2,y2) and (c,d) are the position of the 
  585.     * next-to-last and last point respectively, in the point list
  586.     */
  587.     if (closed_spline(s)) {
  588.         fprintf(tfp, "\t%.3f %.3f %.3f %.3f %.3f %.3f DrawSplineSection closepath ",
  589.             x3, y3, c, d, a, b);
  590.         if (s->area_fill)
  591.         {
  592.         set_areafill(s->area_fill);
  593.         fprintf(tfp, " gsave fill grestore\n");
  594.         set_areafill(NUMFILLPATS);    /* back to black for line */
  595.         }
  596.         if (s->thickness > 0)
  597.         fprintf(tfp, " stroke\n");
  598.         }
  599.     else {
  600.         if (s->thickness > 0)
  601.         fprintf(tfp, "\t%.3f %.3f lineto stroke\n", c, d);
  602.         else
  603.         fprintf(tfp, "\t%.3f %.3f lineto\n", c, d);
  604.         }
  605.     reset_style(s->style, s->style_val);
  606.     if (s->for_arrow && s->thickness > 0) 
  607.         {
  608.         draw_arrow_head(x2, y2, c, d, s->for_arrow->ht,
  609.                 s->for_arrow->wid);
  610.         }
  611.     }
  612.  
  613. genps_ellipse(e,fill)
  614. F_ellipse    *e;
  615. int fill;
  616. {
  617.     if ((fill && e->area_fill==0) ||
  618.         (fill==0 && e->area_fill))
  619.         return;
  620.  
  621.     set_linewidth(e->thickness);
  622.     set_style(e->style, e->style_val);
  623.     fprintf(tfp, "%% Ellipse\n");
  624.     fprintf(tfp, "newpath %d %d %d %d 0 360 DrawEllipse\n",
  625.         e->center.x, e->center.y, e->radiuses.x, e->radiuses.y);
  626.     if (e->area_fill)
  627.         {
  628.         set_areafill(e->area_fill);
  629.         fprintf(tfp, " gsave fill grestore\n");
  630.         set_areafill(NUMFILLPATS);    /* back to black for line */
  631.         }
  632.     if (e->thickness > 0)
  633.         fprintf(tfp, " stroke\n");
  634.     reset_style(e->style, e->style_val);
  635.     }
  636.  
  637. #define    TEXT_SET_PS    "\
  638. fn%d.%d setfont\n\
  639. "
  640. #define TEXT_DEF_PS    "\
  641. /fn%d.%d /%s findfont %f scalefont def\n\
  642. "
  643.  
  644. #define MAX_FONT_SIZES 20
  645.  
  646. genps_text(t)
  647. F_text    *t;
  648.     {
  649.     char    *c;
  650.     static    int current_font = -1;
  651.     static    int current_size = -1;
  652.     static    int first[NUMFONTS][MAX_FONT_SIZES];
  653.     int    i,j,found;
  654.  
  655.     if (current_font == -1)
  656.         for (i=0; i<NUMFONTS; i++)
  657.             for (j=0; j<MAX_FONT_SIZES; j++)
  658.             first[i][j] = 0;
  659.  
  660.     /* if different font or different size, choose new */
  661.     if (current_font != t->font || current_size != t->size)
  662.         {
  663.         found = FALSE;
  664.         for (i=0; (first[t->font][i]!=0 && i<MAX_FONT_SIZES); i++)
  665.         if (first[t->font][i] == t->size)    /* look for this size */
  666.             {
  667.             found = TRUE;
  668.             break;
  669.             }
  670.         if (!found)        /* if we haven't already done a 'findfont'... */
  671.         {
  672.         fprintf(tfp, TEXT_DEF_PS, t->font, t->size, fontnames[t->font].psfont, 
  673.                     t->size/reduction);
  674.         if (i < MAX_FONT_SIZES)        /* insert this size in table */
  675.             first[t->font][i] = t->size;
  676.         }
  677.         fprintf(tfp, TEXT_SET_PS, t->font, t->size); /* now select the font */
  678.         }
  679.     current_font = t->font;
  680.     current_size = t->size;
  681.  
  682.     fprintf(tfp,"(");
  683.     for (c = t->cstring; *c; c++)         /* push the string on the stack */
  684.         {
  685.         if (*c == '\\' || *c == '(' || *c == ')') 
  686.         putc('\\', tfp);
  687.         putc(*c, tfp);
  688.         }
  689.  
  690.     if (t->type == T_CENTER_JUSTIFIED || t->type == T_RIGHT_JUSTIFIED)
  691.         {
  692.         /* dup the string and subtract half(all) of the width from the x position */
  693.         fprintf(tfp,") dup stringwidth pop %s %d exch sub ",
  694.                 (t->type == T_CENTER_JUSTIFIED? "2 div": ""),t->base_x);    
  695.         fprintf(tfp,"%d moveto ",t->base_y);
  696.         }
  697.     else
  698.         fprintf(tfp,") %d %d moveto ",t->base_x,t->base_y);
  699.  
  700.     if (coord_system == 2)     /* upper left is 0,0 */
  701.         fprintf(tfp, "1 -1 scale show 1 -1 scale\n");
  702.     else
  703.         fprintf(tfp, "show\n");
  704.     }
  705.  
  706. genps_arc(a,fill)
  707. F_arc    *a;
  708. int fill;
  709. {
  710.     double        angle1, angle2, dx, dy, radius, x, y;
  711.     double        cx, cy, sx, sy, ex, ey;
  712.     int        direction;
  713.  
  714.     if ((fill && a->area_fill==0) ||
  715.         (fill==0 && a->area_fill))
  716.         return;
  717.  
  718.     cx = a->center.x; cy = a->center.y;
  719.     sx = a->point[0].x; sy = a->point[0].y;
  720.     ex = a->point[2].x; ey = a->point[2].y;
  721.  
  722.     if (coord_system == 2)
  723.         direction = !a->direction;
  724.     else
  725.         direction = a->direction;
  726.     set_linewidth(a->thickness);
  727.     if (a->for_arrow && a->thickness > 0) {
  728.         arc_tangent(cx, cy, ex, ey, direction, &x, &y);
  729.         draw_arrow_head(x, y, ex, ey, a->for_arrow->ht, a->for_arrow->wid);
  730.         }
  731.     if (a->back_arrow && a->thickness > 0) {
  732.         arc_tangent(cx, cy, sx, sy, !direction, &x, &y);
  733.         draw_arrow_head(x, y, sx, sy, a->back_arrow->ht, a->back_arrow->wid);
  734.         }
  735.     dx = cx - sx;
  736.     dy = cy - sy;
  737.     radius = sqrt(dx*dx + dy*dy);
  738.     angle1 = atan2(sy-cy, sx-cx) * 180 / M_PI;
  739.     angle2 = atan2(ey-cy, ex-cx) * 180 / M_PI;
  740.     /* direction = 1 -> Counterclockwise */
  741.     set_style(a->style, a->style_val);
  742.     fprintf(tfp, "newpath %.3f %.3f %.3f %.3f %.3f %s\n",
  743.         cx, cy, radius, angle1, angle2,
  744.         ((direction == 1) ? "arc" : "arcn"));
  745.     if (a->area_fill)
  746.         {
  747.         set_areafill(a->area_fill);
  748.         fprintf(tfp, " closepath gsave fill grestore\n");
  749.         set_areafill(NUMFILLPATS);    /* back to black for line */
  750.         }
  751.     if (a->thickness > 0)
  752.         fprintf(tfp," stroke\n");
  753.     reset_style(a->style, a->style_val);
  754.     }
  755.  
  756. arc_tangent(x1, y1, x2, y2, direction, x, y)
  757. double    x1, y1, x2, y2, *x, *y;
  758. int    direction;
  759. {
  760.     if (direction) { /* counter clockwise  */
  761.         *x = x2 + (y2 - y1);
  762.         *y = y2 - (x2 - x1);
  763.         }
  764.     else {
  765.         *x = x2 - (y2 - y1);
  766.         *y = y2 + (x2 - x1);
  767.         }
  768.     }
  769.  
  770. /*    draw arrow heading from (x1, y1) to (x2, y2)    */
  771.  
  772. draw_arrow_head(x1, y1, x2, y2, arrowht, arrowwid)
  773. float    x1, y1, x2, y2, arrowht, arrowwid;
  774. {
  775.     float    x, y, xb, yb, dx, dy, l, sina, cosa;
  776.     float    xc, yc, xd, yd;
  777.  
  778.     dx = x2 - x1;  dy = y1 - y2;
  779.     l = sqrt((double)(dx*dx + dy*dy));    /* length of line */
  780.     sina = dy / l;  cosa = dx / l;
  781.     xb = x2*cosa - y2*sina;
  782.     yb = x2*sina + y2*cosa;
  783.     x = xb - arrowht;
  784.     y = yb - arrowwid / 2;
  785.     xc = x*cosa + y*sina;            /* one tail of arrow */
  786.     yc = -x*sina + y*cosa;
  787.     y = yb + arrowwid / 2;
  788.     xd = x*cosa + y*sina;            /* other tail of arrow */
  789.     yd = -x*sina + y*cosa;
  790.     fprintf(tfp, "newpath %.3f %.3f moveto %.3f %.3f lineto %.3f %.3f lineto stroke\n",
  791.         xc, yc, x2, y2, xd, yd);
  792.     }
  793.  
  794. ellipse_exist(ob)
  795. F_compound    *ob;
  796. {
  797.     F_compound    *c;
  798.  
  799.     if (NULL != ob->ellipses) return(1);
  800.  
  801.     for (c = ob->compounds; c != NULL; c = c->next) {
  802.         if (ellipse_exist(c)) return(1);
  803.         }
  804.  
  805.     return(0);
  806.     }
  807.  
  808. normal_spline_exist(ob)
  809. F_compound    *ob;
  810. {
  811.     F_spline    *s;
  812.     F_compound    *c;
  813.  
  814.     for (s = ob->splines; s != NULL; s = s->next) {
  815.         if (normal_spline(s)) return(1);
  816.         }
  817.  
  818.     for (c = ob->compounds; c != NULL; c = c->next) {
  819.         if (normal_spline_exist(c)) return(1);
  820.         }
  821.  
  822.     return(0);
  823.     }
  824.  
  825. /*VARARGS1*/
  826. put_msg(format, arg1, arg2, arg3, arg4, arg5)
  827.     char    *format;
  828.     int     arg1, arg2, arg3, arg4, arg5;
  829. {
  830.     fprintf(stderr, format, arg1, arg2, arg3, arg4, arg5);
  831. }
  832.