home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / XAP / XFIG / TRANSFIG.2 / TRANSFIG / transfig / fig2dev / dev / genpic.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-10  |  16.0 KB  |  703 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.  *    genpic : PIC driver for fig2dev
  26.  *
  27.  *    Author: Conrad Kwok, UC Davis, 12/88
  28.  *      Modified: Richard Auletta, George Mason Univ., 6/21/89
  29.  *    Added code comments are marked with "rja".
  30.  *      Added: Support for native pic arrowheads.
  31.  *      Added: Support for arrowheads at both ends of lines, arc, splines.
  32.  *
  33.  *      Modified: Stuart Kemp & Dave Bonnell, July, 1991
  34.  *          James Cook University,
  35.  *          Australia
  36.  *      Changes:
  37.  *        Added T_ARC_BOX to genpic_line()
  38.  *        Added 'thickness' attribute all over
  39.  *        Added 'fill' attribute to ellipse
  40.  *        Cleaned up the code
  41.  */
  42.  
  43. #include <stdio.h>
  44. #include <math.h>
  45. #include "object.h"
  46. #include "fig2dev.h"
  47. #include "picfonts.h"
  48. #include "picpsfonts.h"
  49.  
  50. void genpic_ctl_spline(), genpic_itp_spline();
  51. void genpic_open_spline(), genpic_closed_spline();
  52.  
  53. #define            TOP    10.5    /* top of page is 10.5 inch */
  54. static double        ppi;
  55. static int        CONV = 0;
  56. static int LineThickness = 0;
  57. static int OptArcBox = 0;        /* Conditional use */
  58. static int OptLineThick = 0;
  59. static int OptEllipseFill = 0;
  60. static int OptNoUnps = 0;    /* prohibit unpsfont() */
  61.  
  62. void
  63. genpic_option(opt, optarg)
  64. char opt, *optarg;
  65. {
  66.     switch (opt) {
  67.  
  68.     case 'f':        /* set default text font */
  69.             {   int i;
  70.  
  71.             for ( i = 1; i <= MAX_FONT; i++ )
  72.             if ( !strcmp(optarg, picfontnames[i]) ) break;
  73.  
  74.             if ( i > MAX_FONT)
  75.             fprintf(stderr,
  76.             "warning: non-standard font name %s\n", optarg);
  77.         }
  78.         
  79.         picfontnames[0] = picfontnames[1] = optarg;
  80.         break;
  81.  
  82.     case 's':
  83.         if (font_size <= 0 || font_size > MAXFONTSIZE) {
  84.             fprintf(stderr,
  85.                 "warning: font size %d out of bounds\n", font_size);
  86.         }
  87.         break;
  88.  
  89.     case 'm':
  90.     case 'L':
  91.         break;
  92.  
  93.     case 'p':
  94.         if (strcmp(optarg, "all") == 0)
  95.           OptArcBox = OptLineThick = OptEllipseFill = 1;
  96.         else
  97.           if (strcmp(optarg, "arc") == 0)
  98.             OptArcBox = 1;
  99.           else
  100.             if (strcmp(optarg, "line") == 0)
  101.               OptLineThick = 1;
  102.             else
  103.               if (strcmp(optarg, "fill") == 0)
  104.             OptEllipseFill = 1;
  105.               else
  106.             if (strcmp(optarg, "psfont") == 0)
  107.               OptNoUnps = 1;
  108.             else
  109.               if (strcmp(optarg, "allps") == 0)
  110.                 OptArcBox =
  111.                   OptLineThick =
  112.                 OptEllipseFill =
  113.                   OptNoUnps = 1;
  114.               else
  115.                 { fprintf(stderr, "Invalid option: %s\n", optarg);
  116.                   exit(1);
  117.                 }
  118.         break;
  119.           default:
  120.         put_msg(Err_badarg, opt, "pic");
  121.         exit(1);
  122.     }
  123. }
  124.  
  125. static
  126. double convy(a)
  127. double    a;
  128. {
  129.     return((double)(CONV ? TOP-a : a));
  130. }
  131.  
  132. void
  133. genpic_start(objects)
  134. F_compound    *objects;
  135. {
  136.     int        coord_system;
  137.  
  138.     ppi = objects->nwcorner.x/mag;
  139.     coord_system = objects->nwcorner.y;
  140.     if (coord_system == 2) CONV = 1;
  141.  
  142.     fprintf(tfp, ".PS\n.ps %d\n", font_size);    /* PIC preamble */
  143. }
  144.  
  145. void
  146. genpic_end()
  147. {
  148.       fprintf(tfp, ".PE\n");                /* PIC ending */
  149. }
  150.  
  151. /*
  152. The line thickness is, unfortunately, multiple of pixel.
  153. One pixel thickness is a little too thick on the hard copy
  154. so I scale it with 0.7; i.e., it's a kludge.  The best way is
  155. to allow thickness in fraction of pixel.
  156.  
  157. Note that the current version of psdit (a ditroff to postcript filter)
  158. won't take the legitimate line thickness command.
  159. */
  160. static
  161. set_linewidth(w)
  162. int    w;
  163. {
  164.     static int    cur_thickness = -1;
  165.  
  166.     LineThickness = w;
  167.  
  168.     /*
  169.     if (w == 0) return;
  170.     if (w != cur_thickness) {
  171.         cur_thickness = w;
  172.         fprintf(tfp, "\"\\D't %.5fi'\"\n", 0.7 * cur_thickness / ppi);
  173.         }
  174.     */
  175. }
  176.  
  177. static void
  178. AddThickness()
  179. {
  180.   if (OptLineThick && LineThickness)
  181.     fprintf(tfp, " thickness %d", LineThickness);
  182. }
  183.  
  184. static void
  185. set_style(s, v)
  186. int    s;
  187. float    v;
  188. {
  189.     static float    style_val = -1;
  190.  
  191.     if (s == DASH_LINE || s == DOTTED_LINE) {
  192.         if (v == style_val) return;
  193.         if (v == 0.0) return;
  194.         style_val = v;
  195.         fprintf(tfp, "dashwid = %.3fi\n", style_val/ppi);
  196.         }
  197. }
  198.  
  199. /*
  200.  * Makes use of the PIC 'box' command
  201.  *
  202.  * Returns 0 if command failed, else non-zero.
  203.  *
  204.  */
  205.  
  206. static int
  207. genpic_box(l)
  208. F_line *l;
  209. {
  210.   int count, minx, miny, maxx, maxy;
  211.   int Valid;        /* Valid box */
  212.   double width, height;
  213.   F_point *p, *q;
  214.     
  215.   p = l->points;
  216.   q = p->next;
  217.   count = 1;        /* Just a sanity check */
  218.   minx = maxx = p->x;
  219.   miny = maxy = p->y;
  220.  
  221.   /* Find the boundaries */
  222.   while (q != NULL)
  223.   { count++;
  224.     if (q->x < minx) minx = q->x;
  225.     else
  226.       if (q->x > maxx) maxx = q->x;
  227.  
  228.     if (q->y < miny) miny = q->y;
  229.     else
  230.       if (q->y > maxy) maxy = q->y;
  231.  
  232.     q = q->next;
  233.   }
  234.  
  235.   if (Valid = (count == 5))        /* Valid box? */
  236.   { fprintf(tfp, "box");
  237.     if (l->thickness == 0)
  238.       fprintf(tfp, " invis");
  239.     else
  240.       if (l->style_val > 0.0)
  241.       { if (l->style == DASH_LINE)
  242.       fprintf(tfp, " dashed");
  243.     else if (l->style == DOTTED_LINE)
  244.       fprintf(tfp, " dotted");
  245.       }
  246.  
  247.     /* Should have a #define somewhere for the # of fill patterns */
  248.     if (l->area_fill > 0)
  249.       fprintf(tfp, " fill %.2f", ((double) (l->area_fill - 1)) / 20);
  250.  
  251.     fprintf(tfp, " with .sw at (%.2f,%.2f) ",
  252.         minx / ppi, convy(maxy / ppi));
  253.  
  254.     width = (maxx - minx) / ppi;
  255.     if (width < 0.0) width = -width;
  256.     height = convy(maxy / ppi) - convy(miny / ppi);
  257.     if (height < 0.0) height = -height;
  258.  
  259.     fprintf(tfp, "width %.2f height %.2f", width, height);
  260.  
  261.     if (OptArcBox && l->type == T_ARC_BOX)
  262.       fprintf(tfp, " rad %.2f", l->radius/ppi);
  263.  
  264.     AddThickness();
  265.  
  266.     fprintf(tfp, "\n");
  267.   }
  268.  
  269.   return(Valid);
  270. }
  271.  
  272. void
  273. genpic_line(l)
  274. F_line    *l;
  275. {
  276.     F_point        *p, *q;
  277.  
  278.     if (l->type == T_ARC_BOX && !OptArcBox)
  279.     { fprintf(stderr, "Arc box not implemented; substituting box.\n");
  280.       l->type = T_BOX;
  281.     }
  282.  
  283.     set_linewidth(l->thickness);
  284.     set_style(l->style, l->style_val);
  285.     p = l->points;
  286.     q = p->next;
  287.     if (q == NULL)    /* A single point line */
  288.     {   fprintf(tfp, "line from %.3f,%.3f to %.3f,%.3f",
  289.             p->x/ppi, convy(p->y/ppi), p->x/ppi, convy(p->y/ppi));
  290.         AddThickness();
  291.         fprintf(tfp, "\n");
  292.         return;
  293.     }
  294.  
  295.     if (l->type == T_BOX || l->type == T_ARC_BOX)
  296.     { if (genpic_box(l)) return;
  297.       fprintf(stderr, "Invalid T_BOX or T_ARC_BOX in fig file\n");
  298.           fprintf(stderr, "  Using 'line' instead\n");
  299.     }
  300.  
  301.     fprintf(tfp, "line");
  302.  
  303.     if (l->style_val > 0.0)
  304.     { if (l->style == DASH_LINE)
  305.         fprintf(tfp, " dashed");
  306.       else
  307.         if (l->style == DOTTED_LINE)
  308.           fprintf(tfp, " dotted");
  309.     }
  310.  
  311.     /*rja: Place arrowheads or lack there of on the line*/
  312.     if ((l->for_arrow) && (l->back_arrow))
  313.         fprintf(tfp, " <->");
  314.     else if (l->back_arrow)
  315.         fprintf(tfp, " <-");
  316.     else if (l->for_arrow)
  317.         fprintf(tfp, " ->");
  318.  
  319.     fprintf(tfp, " from %.3f,%.3f", p->x/ppi, convy(p->y/ppi));
  320.     do
  321.     { fprintf(tfp, " to %.3f,%.3f", q->x/ppi, convy(q->y/ppi));
  322.       q = q->next;
  323.     } while (q != NULL);
  324.  
  325.     AddThickness();
  326.  
  327.     fprintf(tfp, "\n");
  328. }
  329.  
  330. void
  331. genpic_spline(s)
  332. F_spline    *s;
  333. {
  334.     if (int_spline(s))
  335.         genpic_itp_spline(s);
  336.     else
  337.         genpic_ctl_spline(s);
  338.     }
  339.  
  340. void
  341. genpic_ctl_spline(s)
  342. F_spline    *s;
  343. {
  344.     if (closed_spline(s))
  345.         genpic_closed_spline(s);
  346.     else
  347.         genpic_open_spline(s);
  348.     }
  349.  
  350. void
  351. genpic_open_spline(s)
  352. F_spline    *s;
  353. {
  354.     double        x1, y1, x2, y2;
  355.     F_point        *p, *q;
  356.  
  357.     p = s->points;
  358.     x1 = p->x/ppi; y1 = convy(p->y/ppi);
  359.     p = p->next;
  360.     x2 = p->x/ppi; y2 = convy(p->y/ppi);
  361.  
  362.  
  363.     /* Pic's spline supports only solid line style */
  364.     /* set_linewidth(s->thickness); */
  365.  
  366.     if (p->next == NULL) {
  367.         fprintf(tfp, "line");
  368.  
  369.            /*rja: Attach arrowhead as required */
  370.         if ((s->for_arrow) && (s->back_arrow))
  371.            fprintf(tfp, " <->");
  372.         else if (s->back_arrow)
  373.            fprintf(tfp, " <-");
  374.         else if (s->for_arrow)
  375.            fprintf(tfp, " ->");
  376.  
  377.         fprintf(tfp, " from %.3f,%.3f to %.3f,%.3f", x1, y1, x2, y2);
  378.  
  379.         AddThickness();
  380.  
  381.         fprintf(tfp, "\n");
  382.  
  383.         return;
  384.         }
  385.  
  386.     fprintf(tfp, "spline"); 
  387.  
  388.            /*rja: Attach arrowhead as required */
  389.         if ((s->for_arrow) && (s->back_arrow))
  390.            fprintf(tfp, " <->");
  391.         else if (s->back_arrow)
  392.            fprintf(tfp, " <-");
  393.         else if (s->for_arrow)
  394.            fprintf(tfp, " ->");
  395.  
  396.     fprintf(tfp, " from %.3f,%.3f to %.3f,%.3f", x1, y1, x2, y2);
  397.  
  398.     for (q = p->next; q->next != NULL; p = q, q = q->next)
  399.         fprintf(tfp, " to %.3f,%.3f", q->x/ppi, convy(q->y/ppi));
  400.     fprintf(tfp, " to %.3f,%.3f", q->x/ppi, convy(q->y/ppi));
  401.  
  402.     AddThickness();
  403.  
  404.     fprintf(tfp, "\n");
  405. }
  406.  
  407. void
  408. genpic_ellipse(e)
  409. F_ellipse    *e;
  410. {
  411.     set_linewidth(e->thickness);
  412.     if (e->type == 3 || e->type == 4)
  413.       fprintf(tfp, "circle at %.3f,%.3f rad %.3f",
  414.         e->center.x/ppi, convy(e->center.y/ppi),
  415.         e->radiuses.x/ppi);
  416.     else
  417.       fprintf(tfp, "ellipse at %.3f,%.3f wid %.3f ht %.3f",
  418.         e->center.x/ppi, convy(e->center.y/ppi),
  419.         2 * e->radiuses.x/ppi, 2 * e->radiuses.y/ppi);
  420.  
  421.     if ( OptEllipseFill && e->area_fill > 0)
  422.       fprintf(tfp, " fill %.2f", ((double)(e->area_fill - 1)) / 20);
  423.  
  424.     AddThickness();
  425.  
  426.     fprintf(tfp, "\n");
  427. }
  428.  
  429. /*
  430. Text is display on the screen with the base line starting at
  431. (base_x, base_y); some characters extend below this line.
  432. Pic displays the center of the height of text at the given
  433. coordinate. HT_OFFSET is use to compensate all the above factors
  434. so text position in fig 1.4 should be at the same position on
  435. the screen as on the hard copy.
  436. */
  437. #define            HT_OFFSET    (0.2 / 72.0)
  438.  
  439. void
  440. genpic_text(t)
  441. F_text    *t;
  442. {
  443.     float    y;
  444.         char *tpos;
  445.  
  446.     if (!OptNoUnps) {
  447.       unpsfont(t);
  448.       fprintf(tfp, "\"\\s%d\\f%s", PICFONTMAG(t) ,
  449.           PICFONT(t->font) );
  450.     } else {
  451.       fprintf(tfp, ".ps\n.ps %d\n", PICFONTMAG(t) );
  452.       fprintf(tfp, ".ft\n.ft %s\n", PICPSFONT(t) );
  453.     }
  454.  
  455.         switch (t->type) {
  456.         case T_LEFT_JUSTIFIED:
  457.         case DEFAULT:
  458.             tpos = "ljust";
  459.             break;
  460.         case T_CENTER_JUSTIFIED:
  461.             tpos = "";
  462.             break;
  463.         case T_RIGHT_JUSTIFIED:
  464.             tpos = "rjust";
  465.             break;
  466.         default:
  467.             fprintf(stderr, "unknown text position type\n");
  468.             exit(1);
  469.         }    
  470.      y = convy(t->base_y/ppi) +
  471.          PICFONTMAG(t) *
  472.              HT_OFFSET;
  473.      if (!OptNoUnps)
  474.          fprintf(tfp, "%s\\fP\" at %.3f,%.3f %s\n",
  475.              t->cstring, t->base_x/ppi, y, tpos);
  476.      else
  477.          fprintf(tfp, "\"%s\" at %.3f,%.3f %s\n.ft \n.ps \n",
  478.             t->cstring, t->base_x/ppi, y, tpos);
  479.     }
  480.  
  481. void
  482. genpic_arc(a)
  483. F_arc    *a;
  484. {
  485.     double        x, y;
  486.     double        cx, cy, sx, sy, ex, ey;
  487.  
  488.     cx = a->center.x/ppi; cy = convy(a->center.y/ppi);
  489.     sx = a->point[0].x/ppi; sy = convy(a->point[0].y/ppi);
  490.     ex = a->point[2].x/ppi; ey = convy(a->point[2].y/ppi);
  491.  
  492.     set_linewidth(a->thickness);
  493.  
  494.     fprintf(tfp, "arc ");
  495.  
  496.     /*rja: Attach arrowhead as required */
  497.     if ((a->for_arrow) && (a->back_arrow))
  498.       fprintf(tfp, " <->");
  499.     else if (a->back_arrow)
  500.       fprintf(tfp, " <-");
  501.     else if (a->for_arrow)
  502.       fprintf(tfp, " ->");
  503.  
  504.  
  505.     fprintf(tfp, " at %.3f,%.3f from %.3f,%.3f to %.3f,%.3f",
  506.         cx, cy, sx, sy, ex, ey);
  507.  
  508.     if (!a->direction)
  509.       fprintf(tfp, " cw");
  510.  
  511.     if (a->area_fill > 0.0)
  512.       fprintf(stderr, "PIC does not support filled arcs ... ignoring 'fill' directive\n");
  513.  
  514.     AddThickness();
  515.     fprintf(tfp, "\n");
  516. }
  517.  
  518. void
  519. arc_tangent(x1, y1, x2, y2, direction, x, y)
  520. double    x1, y1, x2, y2, *x, *y;
  521. int    direction;
  522. {
  523.     if (direction)    /* counter clockwise  */
  524.     {   *x = x2 + (y2 - y1);
  525.         *y = y2 - (x2 - x1);
  526.     }
  527.     else
  528.     {   *x = x2 - (y2 - y1);
  529.         *y = y2 + (x2 - x1);
  530.     }
  531. }
  532.  
  533. /*    draw arrow heading from (x1, y1) to (x2, y2)    */
  534.  
  535. draw_arrow_head(x1, y1, x2, y2, arrowht, arrowwid)
  536. double    x1, y1, x2, y2, arrowht, arrowwid;
  537. {
  538.     double    x, y, xb, yb, dx, dy, l, sina, cosa;
  539.     double    xc, yc, xd, yd;
  540.  
  541.     dx = x2 - x1;  dy = y1 - y2;
  542.     l = sqrt((dx*dx + dy*dy));
  543.     if (l == 0) {
  544.          return;
  545.     }
  546.     else {
  547.          sina = dy / l;  cosa = dx / l;
  548.     }
  549.     xb = x2*cosa - y2*sina;
  550.     yb = x2*sina + y2*cosa;
  551.     x = xb - arrowht;
  552.     y = yb - arrowwid / 2;
  553.     xc = x*cosa + y*sina;
  554.     yc = -x*sina + y*cosa;
  555.     y = yb + arrowwid / 2;
  556.     xd = x*cosa + y*sina;
  557.     yd = -x*sina + y*cosa;
  558.     fprintf(tfp, "line from %.3f,%.3f to %.3f,%.3f to %.3f,%.3f\n",
  559.         xc, yc, x2, y2, xd, yd);
  560.     }
  561.  
  562. #define        THRESHOLD    .05    /* inch */
  563.  
  564. quadratic_spline(a1, b1, a2, b2, a3, b3, a4, b4)
  565. double    a1, b1, a2, b2, a3, b3, a4, b4;
  566. {
  567.     double    x1, y1, x4, y4;
  568.     double    xmid, ymid;
  569.  
  570.     x1 = a1; y1 = b1;
  571.     x4 = a4; y4 = b4;
  572.  
  573.     xmid = (a2 + a3) / 2;
  574.     ymid = (b2 + b3) / 2;
  575.     if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD)
  576.     { fprintf(tfp, " to %.3f,%.3f", xmid, ymid);
  577.     }
  578.     else {
  579.         quadratic_spline(x1, y1, ((x1+a2)/2), ((y1+b2)/2),
  580.             ((3*a2+a3)/4), ((3*b2+b3)/4), xmid, ymid);
  581.         }
  582.  
  583.     if (fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD)
  584.     { fprintf(tfp, " to %.3f,%.3f", x4, y4);
  585.     }
  586.     else {
  587.         quadratic_spline(xmid, ymid, ((a2+3*a3)/4), ((b2+3*b3)/4),
  588.             ((a3+x4)/2), ((b3+y4)/2), x4, y4);
  589.         }
  590.     }
  591.  
  592. void
  593. genpic_closed_spline(s)
  594. F_spline    *s;
  595. {
  596.     F_point    *p;
  597.     double    cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
  598.     double    x1, y1, x2, y2;
  599.  
  600.     p = s->points;
  601.     x1 = p->x/ppi;  y1 = convy(p->y/ppi);
  602.     p = p->next;
  603.     x2 = p->x/ppi;  y2 = convy(p->y/ppi);
  604.     cx1 = (x1 + x2) / 2;      cy1 = (y1 + y2) / 2;
  605.     cx2 = (x1 + 3 * x2) / 4;  cy2 = (y1 + 3 * y2) / 4;
  606.  
  607.     for (p = p->next; p != NULL; p = p->next) {
  608.         fprintf(tfp, "line from %.3f,%.3f ", cx1, cy1);
  609.         x1 = x2;  y1 = y2;
  610.         x2 = p->x/ppi;  y2 = convy(p->y/ppi);
  611.         cx3 = (3 * x1 + x2) / 4;  cy3 = (3 * y1 + y2) / 4;
  612.         cx4 = (x1 + x2) / 2;      cy4 = (y1 + y2) / 2;
  613.         quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
  614.         AddThickness();
  615.         fprintf(tfp, "\n");
  616.         cx1 = cx4;  cy1 = cy4;
  617.         cx2 = (x1 + 3 * x2) / 4;  cy2 = (y1 + 3 * y2) / 4;
  618.         }
  619.     x1 = x2;  y1 = y2;
  620.     p = s->points->next;
  621.     x2 = p->x/ppi;  y2 = convy(p->y/ppi);
  622.     cx3 = (3 * x1 + x2) / 4;  cy3 = (3 * y1 + y2) / 4;
  623.     cx4 = (x1 + x2) / 2;      cy4 = (y1 + y2) / 2;
  624.     fprintf(tfp, "line from %.3f,%.3f ", cx1, cy1);
  625.     quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
  626.     AddThickness();
  627.     fprintf(tfp, "\n");
  628. }
  629.  
  630. void
  631. genpic_itp_spline(s)
  632. F_spline    *s;
  633. {
  634.     F_point        *p1, *p2, *pfirst;
  635.     F_control    *cp1, *cp2;
  636.     double        x1, x2, y1, y2;
  637.  
  638.     p1 = s->points;
  639.     cp1 = s->controls;
  640.     cp2 = cp1->next;
  641.     x2 = p1->x/ppi; y2 = convy(p1->y/ppi);
  642.  
  643.          pfirst = p1->next;/*save first to test in loop*/
  644.     for (p2 = p1->next, cp2 = cp1->next; p2 != NULL;
  645.         p1 = p2, cp1 = cp2, p2 = p2->next, cp2 = cp2->next) {
  646.  
  647.         fprintf(tfp, "line ");
  648.  
  649.            /*rja: Attach arrowhead as required */
  650.  
  651.         if ((s->back_arrow) && (p2 == pfirst))
  652.            fprintf(tfp, " <- ");
  653.         else if ((s->for_arrow) && (p2->next == NULL))
  654.            fprintf(tfp, " -> ");
  655.  
  656.         fprintf(tfp, " from %.3f,%.3f", x2, y2);
  657.  
  658.         x1 = x2; y1 = y2;
  659.         x2 = p2->x/ppi; y2 = convy(p2->y/ppi);
  660.         bezier_spline(x1, y1, (double)cp1->rx/ppi, convy(cp1->ry/ppi),
  661.         (double)cp2->lx/ppi, convy(cp2->ly/ppi), x2, y2);
  662.         AddThickness();
  663.         fprintf(tfp, "\n");
  664.         }
  665.  
  666.     }
  667.  
  668. bezier_spline(a0, b0, a1, b1, a2, b2, a3, b3)
  669. double    a0, b0, a1, b1, a2, b2, a3, b3;
  670. {
  671.     double    x0, y0, x3, y3;
  672.     double    sx1, sy1, sx2, sy2, tx, ty, tx1, ty1, tx2, ty2, xmid, ymid;
  673.  
  674.     x0 = a0; y0 = b0;
  675.     x3 = a3; y3 = b3;
  676.     if (fabs(x0 - x3) < THRESHOLD && fabs(y0 - y3) < THRESHOLD)
  677.     { fprintf(tfp, " to %.3f,%.3f", x3, y3);
  678.     }
  679.     else {
  680.         tx = (a1 + a2) / 2;        ty = (b1 + b2) / 2;
  681.         sx1 = (x0 + a1) / 2;    sy1 = (y0 + b1) / 2;
  682.         sx2 = (sx1 + tx) / 2;    sy2 = (sy1 + ty) / 2;
  683.         tx2 = (a2 + x3) / 2;    ty2 = (b2 + y3) / 2;
  684.         tx1 = (tx2 + tx) / 2;    ty1 = (ty2 + ty) / 2;
  685.         xmid = (sx2 + tx1) / 2;    ymid = (sy2 + ty1) / 2;
  686.  
  687.         bezier_spline(x0, y0, sx1, sy1, sx2, sy2, xmid, ymid);
  688.         bezier_spline(xmid, ymid, tx1, ty1, tx2, ty2, x3, y3);
  689.         }
  690.     }
  691.  
  692. struct driver dev_pic = {
  693.          genpic_option,
  694.     genpic_start,
  695.     genpic_arc,
  696.     genpic_ellipse,
  697.     genpic_line,
  698.     genpic_spline,
  699.     genpic_text,
  700.     genpic_end,
  701.     INCLUDE_TEXT
  702. };
  703.