home *** CD-ROM | disk | FTP | other *** search
/ Der Mediaplex Sampler - Die 6 von Plex / 6_v_plex.zip / 6_v_plex / DISK2 / MULTI_04 / SHOWGL15.ZIP / HPGL1.C < prev    next >
C/C++ Source or Header  |  1991-12-27  |  30KB  |  1,056 lines

  1. #pragma linesize(132)    /* listing linewidth = 132 */
  2.  
  3. /* hpgl1.c    Rev. A.  This file contains the following functions:
  4.  
  5.     arc_3pt ()
  6.     calc_ticksize ()
  7.     chord_t ()
  8.     circle ()
  9.     cot ()
  10.     draw_arc ()
  11.     draw_xtick ()
  12.     draw_ytick ()
  13.     draw_wedge ()
  14.     draw_rect ()
  15.     fill_rect ()
  16.     fill_type ()
  17.     fix_hatch ()
  18.     get_xy ()
  19.     get_val ()
  20.     init_fills ()
  21.     new_plot ()
  22.     plotted_on ()
  23.     print_error ()
  24.     tick_length ()
  25.     velocity_sel ()
  26.  
  27. */
  28.  
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <math.h>
  32. #include <float.h>
  33. #include "graph.h"    /* this must preceed hpgl.h */
  34. #include "hpgl.h"
  35.  
  36. extern double gdu_cm, p1x, p1y, p2x, p2y;
  37. extern int chord_type, p_status, symbol_mode;
  38. extern double uu_2_pux, uu_2_puy;
  39. extern char symbol;
  40. extern int debugging;
  41.  
  42. static void fill_rect (double, double, double, double, double, double);
  43. static double cot ( double );
  44.  
  45. static char copyright[] = "Copyright 1991, Robert C. Becker, Lantern Systems";
  46.  
  47. struct poly_fills
  48.     {
  49.     int mode;
  50.     double opt1, opt2;
  51.     double alt_opt1;
  52.     };
  53.  
  54. static struct poly_fills fill_code [6];    /* hold values for types 1, 2, 3, 4, 10, 11 */
  55.                     /* values for these type stored in this order in struct array */
  56.  
  57. static int select_fill;            /* last fill type selected */
  58. static double tnx, tny, tpx, tpy;    /* x, y tick negative & positive lengths in GDU's */
  59. static double anchor_x, anchor_y;    /* corner anchors for fill types */
  60. static int dirty_plot;            /* flag to mark if plot has been plotted on yet */
  61. static char bfr[256];            /* scratch char buffer for get_val */
  62.  
  63. /*--------------------------------------*/
  64.  
  65. void velocity_sel (FILE *infile)
  66.     {
  67.     double x;
  68.  
  69.     DB (printf ("VS\n");)
  70.     if (get_val (infile, &x))    /* optional speed argument: not used */
  71.         {
  72.         get_val (infile, &x);    /* optional pen # argument: not used */
  73.         }
  74.     return;
  75.     }
  76.  
  77. /*--------------------------------------*/
  78.  
  79. void tick_length (FILE *infile)
  80.     {
  81.     double tp, tn;
  82.  
  83.     tp = DEF_TICK;
  84.     tn = DEF_TICK;        /* default tick lengths */
  85.     if ( get_val (infile, &tp))    /* got one value: try for two */
  86.         {
  87.         if (!get_val (infile, &tn)) tn = 0.0;    /* if only have one value, tn = 0 */
  88.         }
  89.     calc_ticksize (tp, tn);
  90.     return;
  91.     }
  92. /*--------------------------------------*/
  93.  
  94. void calc_ticksize (double tp, double tn)
  95.     {
  96.  
  97.     tp = MAX (-128.00, (MIN (127.9999, tp)));
  98.     tn = MAX (-128.00, (MIN (127.9999, tn)));
  99.  
  100.     tpx = (tp * (p2x - p1x) * 0.00254 / 100.0) * gdu_cm;
  101.     tpy = (tp * (p2y - p1y) * 0.00254 / 100.0) * gdu_cm;
  102.     tnx = (tn * (p2x - p1x) * 0.00254 / 100.0) * gdu_cm;
  103.     tny = (tn * (p2y - p1y) * 0.00254 / 100.0) * gdu_cm;
  104.     /* P1, P2 are in mils.  0.00254 cm/mil */
  105.  
  106.     return;
  107.     }
  108.  
  109. /*--------------------------------------*/
  110.  
  111. void draw_xtick (void)
  112.     {
  113.     double x_1, y_1;    /* local variables */
  114.  
  115.     setgu();
  116.     where (&x_1, &y_1);
  117.     rmove (0.0, -tny);
  118.     rdraw (0.0, tpy);    /* draw vertical tick mark */
  119.     move (x_1, y_1);    /* NOP: establish new position for subsequent rmove/draw ()'s */
  120.     setuu ();
  121.     plotted_on (1);        /* we drew something on this plot */
  122.     return;
  123.     }
  124.  
  125. /*--------------------------------------*/
  126.  
  127. void draw_ytick (void)
  128.     {
  129.     double x_1, y_1;    /* local variables */
  130.  
  131.     setgu ();
  132.     where (&x_1, &y_1);
  133.     rmove (-tnx, 0.0);
  134.     rdraw (tpx, 0.0);    /* draw horizontal tick mark */
  135.     move (x_1, y_1);    /* NOP: establish new position for subsequent rmove/draw ()'s */
  136.     setuu ();
  137.     plotted_on (1);        /* we drew something on this plot */
  138.     return;
  139.     }
  140.  
  141. /*--------------------------------------*/
  142.  
  143. void print_error (char *instr, int type)
  144.     {
  145.  
  146.     if (!debugging) return;    /* no output if not asked for */
  147.  
  148.     if (type)
  149.         fprintf (stderr, "%s", instr);
  150.     else
  151.         fprintf (stderr, "%s instruction not implimented\n", instr);
  152.     return;
  153.     }
  154.  
  155. /*--------------------------------------*/
  156.  
  157. int get_xy (FILE *infile, double *xv, double *yv)
  158.     {
  159.  
  160.     if (get_val (infile, xv))    /* get x values */
  161.          {
  162.         if ( !get_val (infile, yv))    /* get y value */
  163.             {
  164.             print_string ("get_xy():  missing y-value\n");
  165.             return (0);
  166.             }
  167.         return (1);    /* have 2 values */
  168.         }
  169.     return (0);    /* no values */
  170.     }
  171.  
  172. /*--------------------------------------*/
  173.  
  174. void new_plot ( void )
  175.     {
  176.  
  177.     dirty_plot = 0;    /* plot is clean (not plotted on) */
  178.     return;
  179.     }
  180.  
  181. /*--------------------------------------*/
  182.  
  183. int plotted_on (int plot_flag)
  184.     {
  185.  
  186.     if (plot_flag > 0)
  187.         dirty_plot = 1;    /* mark plot as plotted on */
  188.     return (dirty_plot);
  189.     }
  190.  
  191. /*--------------------------------------*/
  192.  
  193. int get_val (FILE *infile, double *rval)
  194.     {
  195.     int j;
  196.     char c;
  197.  
  198.     c = getc (infile);
  199.     while ( c  && c != (char) EOF && isspace (c) ) c = getc (infile);
  200.     /* remove leading white-space */
  201.  
  202.     if ( c == TERMCHAR || c == (char) EOF) return (0);    /* terminated: return # params read */
  203.     if ( ! (isdigit (c) || c == ',' || c == '-' || c == '+' || c == '.'))
  204.         {
  205.         ungetc (c, infile);    /* put back what we grabbed */
  206.         return (0);        /* next char not a number */
  207.         }
  208.     if (c == ',') c = getc (infile);
  209.  
  210.     j = 0;
  211.     while ( isdigit ( c ) || c == '-' || c == '+' || c == '.' )
  212.         {
  213.         bfr[j] = c;
  214.         c = getc (infile);
  215.         ++j;
  216.         }
  217.     bfr[j] = '\0';    /* terminate string */
  218.     if (c != ',' && !isspace (c) ) ungetc (c, infile);    /* DO NOT INCLUDE termchar IN THIS TEST!! */
  219.  
  220.     /* including termchar in the test to unget a char will cause a failure if termchar was read 
  221.     by this routine and it is called again immediately thereafter (will return 1 argument of zero value [error]) */
  222.  
  223.     if (j == 0)    /* trap zero length arguments */
  224.         {
  225.         print_string ("? Null argument in get_val ()\n");
  226.         return (0);
  227.         }
  228.  
  229.     DB (printf ("get_val: instring = %s\n", bfr);)
  230.     *rval = atof (bfr);
  231.     return (1);
  232.     }
  233.  
  234. /*--------------------------------------*/
  235.  
  236. void draw_arc (FILE * infile, int type )
  237.     {    /* type: 0 -> absolute, 1 -> relative */
  238.     double radius, x, y, x_1, y_1, x_2, y_2, val4, ang1, ang2, ang3;
  239.     unsigned char c2;
  240.     int segs;
  241.  
  242.     DB (if (type) printf ("AR\n"); else printf ("AA\n");)
  243.     if (!get_xy (infile, &x, &y))
  244.         {
  245.         if (type)
  246.             print_string ("AR: missing x- or y-value\n");
  247.         else
  248.             print_string ("AA: missing x- or y-value\n");
  249.         return;    /* illegal instr */
  250.         }
  251.     if (!get_val (infile, &ang1))    /* arc angle */
  252.         {
  253.         if (type)
  254.             print_string ("AR: missing arc angle\n");
  255.         else
  256.             print_string ("AA: missing arc angle\n");
  257.         return;    /* illegal instr */
  258.         }
  259.     DB (printf ("input value: x = %lf, y = %lf, ang1 = %lf\n", x, y, ang1);)
  260.     where (&x_1, &y_1);    /* get starting point */
  261.     if (type)
  262.         {        /* relative */
  263.         DB (printf ("current location: (x,y) = (%lf, %lf)\n", x_1, y_1);)
  264.         x_2 = x_1 + x;
  265.         y_2 = y_1 + y;
  266.         x_1 = -x;
  267.         y_1 = -y;
  268.         }
  269.     else
  270.         {        /* absolute */
  271.         x_2 = x;
  272.         y_2 = y;    /* save center position */
  273.         x_1 -= x;
  274.         y_1 -= y;    /* delta-x, -y */
  275.         }
  276.     DB (printf ("arc center: (x,y) = (%lf, %lf), angle = %lf\n", x_2, y_2, ang1);)
  277.     move (x_2, y_2);    /* move to center of arc */
  278.     radius = sqrt (x_1*x_1 + y_1*y_1);
  279.  
  280.     ang2 = val4 = DEF_CHORD;
  281.     if (get_val (infile, &val4))
  282.         {
  283.         val4 = fabs (val4);    /* only positive values allowed */
  284.         if (chord_type == ANG || val4 == 0.0)        /* using angles, not deviations */
  285.             {
  286.             if (val4 == 0.0) val4 = DEF_CHORD;    /* set default chord angle or deviation */
  287.             ang2 = MIN (MAX_CHORD, (MAX (val4, MIN_CHORD)));
  288.             }
  289.         else        /* chord angle determined by deviation of segments from circle radius */
  290.             {    /* at this point, val4 is length in current units, not angle in degrees */
  291.             if (val4 > 2.0 * radius) val4 = 2.0 * radius;    /* limit deviation: resulting chord angle < 180 deg. */
  292.             ang2 = acos ( (radius - val4) / radius) * RAD_2_DEG;
  293.             }
  294.         }
  295.  
  296.     segs = (int) (fabs (ang1) / ang2 + 0.5);    /* # segments in "ang1" deg. */
  297.         /* sign of 'segs' changes direction of arc () */
  298.     DB (printf ("chord = %lf, # segments = %d\n", ang2, segs);)
  299.     ang3 = RAD_2_DEG * atan2 (y_1, x_1);
  300.     if (p_status == PENDOWN)    /* draw the arc only if pen is down */
  301.         {
  302.         DB (printf ("radius = %lf, start angle = %lf, stop angle = %lf\n", radius, ang3, ang1 + ang3);)
  303.         arc ( radius, segs, ang3, ang1 + ang3);
  304.         }
  305.     if (symbol_mode)
  306.         {
  307.         move (x_2, y_2);
  308.         symbol_mark (symbol);
  309.         }
  310.     plotted_on (1);        /* we drew something on this plot */
  311.     return;
  312.     }
  313.  
  314. /*--------------------------------------*/
  315.  
  316. void circle (FILE * infile)
  317.     {
  318.     double ang, ang2, radius, val2, x_1, y_1;
  319.     unsigned char c2;
  320.     int segs;
  321.  
  322.     DB(printf ("CI\n");)
  323.  
  324.     if (!get_val (infile, &radius))
  325.         {
  326.         print_string ("CI: radius not specified\n");
  327.         return;    /* error: no param's */
  328.         }
  329.  
  330.     ang2 = val2 = DEF_CHORD;    /* default chord angle or deviation for circle/arc */
  331.     if ( get_val (infile, &val2))
  332.         {
  333.         val2 = fabs (val2);    /* only positive values allowed */
  334.         if (chord_type == ANG || val2 == 0.0)        /* using angles, not deviations */
  335.             {
  336.             if (val2 == 0.0) val2 = DEF_CHORD;    /* set default chord angle or deviation */
  337.             ang2 = MIN (MAX_CHORD, (MAX (val2, MIN_CHORD)));
  338.             }
  339.         else        /* chord angle determined by deviation of segments from circle radius */
  340.             {    /* at this point, val2 is length in current units, not angle in degrees */
  341.             if (val2 > 2.0 * radius) val2 = 2.0 * radius;    /* limit deviation: resulting chord angle < 180 deg. */
  342.             ang2 = acos ( (radius - val2) / radius) * RAD_2_DEG;
  343.             }
  344.         }
  345.     segs = (int) (360.0 / ang2 + 0.5);    /* # segments in 360 deg. */
  346.         /* sign of 'segs' changes direction of arc () */
  347.     DB (printf ("CI: radius = %lf, chord = %lf, # segments = %d\n", radius, ang2, segs);)
  348.     where (&x_1, &y_1);
  349.     arc (radius, segs, 0.0, 360.0);    /* circle with l segments */
  350.     if (symbol_mode)
  351.         {
  352.         move (x_1, y_1);
  353.         symbol_mark (symbol);
  354.         }
  355.     plotted_on (1);        /* we drew something on this plot */
  356.     return;
  357.     }
  358.  
  359. /*--------------------------------------*/
  360.  
  361. void arc_3pt (FILE * infile, int type)
  362.     {    /* type 0 = absolute arc, type 1 = relative arc */
  363.     double ma, mb, ba, bb, x_1, y_1, xi, yi, xe, ye;
  364.     double dax, day, dbx, dby, xc, yc, ang_e, ang_i;
  365.     double start_ang, stop_ang, radius, ang2, val5;
  366.     int segs, cw;
  367.  
  368.     DB (if (type) printf ("AR\n"); else printf ("AT\n");)
  369.     if (!get_xy (infile, &xi, &yi))
  370.         {
  371.         if (type)
  372.             print_string ("AR: missing Xi or Yi value\n");
  373.         else
  374.             print_string ("AT: missing Xi or Yi value\n");
  375.         return;
  376.         }
  377.     if (!get_xy (infile, &xe, &ye))
  378.         {
  379.         if (type)
  380.             print_string ("AR: missing Xe or Ye value\n");
  381.         else
  382.             print_string ("AT: missing Xe or Ye value\n");
  383.         return;
  384.         }
  385.  
  386.     where (&x_1, &y_1);    /* current position */
  387.     if (type)        /* relative arc in 3 pts */
  388.         {
  389.         xe += x_1;
  390.         ye += y_1;
  391.         xi += x_1;
  392.         yi += y_1;    /* convert from offsets to abs coordinates */
  393.         }
  394.  
  395.     dax = xe - x_1;
  396.     day = ye - y_1;        /* delta-x, -y from ref. to end pt. */
  397.     dbx = xi - xe;
  398.     dby = yi - ye;        /* delta-x, -y from end pt. to intermediate pt. */
  399.  
  400.     DB (printf ("P1: (%lf, %lf) Pi: (%lf, %lf), Pe: (%lf, %lf)\n", x_1, y_1, xi, yi, xe, ye);)
  401.     DB (printf ("fabs (day) = %lf, fabs(dby) = %lf\n", fabs(day), fabs(dby));)
  402.  
  403.     if ( fabs (day) < FLT_EPSILON)    /* P1, Pe horizontal or same */
  404.         {        /* FLT, not DBL: more conservative */
  405.         DB (printf ("fabs (day) < FLT_EPSILON\n");)
  406.         xc = x_1 + dax / 2;        /* equation of vertical line */
  407.         if (fabs (dby) < FLT_EPSILON || fabs (dax) < FLT_EPSILON)
  408.             {            /* all pts horizontal */
  409.             DB (printf ("vertical or straight line curve\n");)
  410.             if (symbol_mode)
  411.                 {
  412.                 move (x_1, y_1);
  413.                 symbol_mark (symbol);
  414.                 }
  415.             draw (xi, yi);        /* draw intermediate pt in case end & start same */
  416.             draw (xe, ye);        /* this is the curve */
  417.  
  418.             plotted_on (1);        /* we drew something on this plot */
  419.             return;
  420.             }
  421.         mb = -dbx / dby;        /* slope of line normal to PePi */
  422.         bb = (ye + dby / 2) - mb * (xe + dbx / 2);    /* now have b-part of line equations */
  423.         yc = mb * xc + bb;
  424.         }
  425.     else
  426.         {    /* FLT, not DBL: more conservative */
  427.         if (fabs (dby) < FLT_EPSILON)    /* Pe, Pi horizontal or same */
  428.             {
  429.             DB (printf ("fabs (dby) < FLT_EPSILON\n");)
  430.             xc = xe + dbx / 2;        /* equation of vertical line */
  431.             if (fabs (day) < FLT_EPSILON || fabs (dbx) < FLT_EPSILON)
  432.                 {            /* all pts horizontal or Pe == Pi */
  433.                 DB (printf ("horizontal or straight line curve\n");)
  434.                 if (symbol_mode)
  435.                     {
  436.                     move (x_1, y_1);
  437.                     symbol_mark (symbol);
  438.                     }
  439.                 draw (xi, yi);        /* draw intermediate pt in case end & start same */
  440.                 draw (xe, ye);        /* this is the curve */
  441.                 plotted_on (1);        /* we drew something on this plot */
  442.                 return;
  443.                 }
  444.             ma = -dax / day;    /* slope of line normal to PiPe */
  445.             ba = (y_1 + day / 2) - ma * (x_1 + dax / 2);
  446.             yc = ma * xc + ba;
  447.             }
  448.         else
  449.             {
  450.  
  451.             /* general case:  can't handle dby = 0 or day = 0 */
  452.             ma = -dax / day;        /* slope of line normal to P1Pe */
  453.             mb = -dbx / dby;        /* slope of line normal to PePi */
  454.  
  455.                 /* y_1 + day = y-value midway between y_1 and ye */
  456.                 /* x_1 + dax = x-value midway between x_1 and xe */
  457.                 /* ye + dby = y-value midway between ye and yi */
  458.                 /* xe + dbx = x-value midway between xe and yi */
  459.             ba = (y_1 + day / 2) - ma * (x_1 + dax / 2);
  460.             bb = (ye + dby / 2) - mb * (xe + dbx / 2);    /* now have b-part of line equations */
  461.  
  462.             if (fabs (ma - mb) < FLT_EPSILON)    /* that's right FLT, not DBL */
  463.                 {                /* too small to prevent floating point overflow */
  464.                 DB (printf ("straight line curve\n");)
  465.                 if (symbol_mode)
  466.                     {
  467.                     move (x_1, y_1);
  468.                     symbol_mark (symbol);
  469.                     }
  470.                 draw (xi, yi);        /* draw intermediate pt in case end & start same */
  471.                 draw (xe, ye);        /* this is the curve */
  472.                 return;
  473.                 }
  474.             xc = (bb - ba) / (ma - mb);        /* now have x-center */
  475.             yc = mb * xc + bb;            /* can find yc using either line eqn. */
  476.             }
  477.         }
  478.  
  479.     DB (printf ("3-pt. arc:  center at (%lf, %lf)\n", xc, yc);)
  480.  
  481.     radius = sqrt ((xc - x_1) * (xc - x_1) + (yc - y_1) * (yc - y_1));
  482.  
  483.     val5 = ang2 = DEF_CHORD;
  484.  
  485.     if (get_val (infile, &val5))
  486.         {
  487.         val5 = fabs (val5);    /* only positive values allowed */
  488.  
  489.         /* note: if no tolerance is specified, the default is a
  490.         chord ANGLE of 5 DEGREES, regardless of chord_type */
  491.  
  492.         if (chord_type == ANG || val5 == 0.0)    /* using angles, not deviations */
  493.             {
  494.             if (val5 == 0.0) val5 = DEF_CHORD;    /* set default chord angle */
  495.             ang2 = MIN (MAX_CHORD, (MAX (val5, MIN_CHORD)));
  496.             }
  497.         else        /* chord angle determined by deviation of segments from circle radius */
  498.             {    /* at this point, val5 is length in current units, not angle in degrees */
  499.  
  500.             if (val5 > 2.0 * radius) val5 = 2.0 * radius;    /* limit deviation: resulting chord angle < 180 deg. */
  501.             ang2 = acos ( (radius - val5) / radius) * RAD_2_DEG;
  502.  
  503.             /* note that this value is being left in radians (for now) */
  504.             }
  505.  
  506.         }
  507.  
  508.     DB (printf ("P1: (%lf, %lf), Pc: (%lf, %lf), Pe: (%lf, %lf)\n", x_1, y_1, xc, yc, xe, ye);)
  509.  
  510.     start_ang = RAD_2_DEG * atan2 (y_1 - yc, x_1 - xc);    /* angle from center to starting pt */
  511.     stop_ang = RAD_2_DEG * atan2 (ye - yc, xe - xc);    /* angle from center to stopping pt */
  512.  
  513.     DB (printf ("initial: start_ang = %lf, stop_ang = %lf\n", start_ang, stop_ang);)
  514.  
  515.     ang_e = RAD_2_DEG * atan2 (day, dax);
  516.     ang_i = RAD_2_DEG * atan2 ( yi - y_1, xi - x_1);    /* determine direction of arc */
  517.  
  518.     cw = 1;    /* direction defaults to clockwise rotation */
  519.  
  520.     if (ang_e >= 0.0 && ang_i >= 0.0)    /* resolve direction of arc by */
  521.         cw = (ang_e < ang_i) ? 1 : 0;    /* angle between ref. pt and other 2 pts */
  522.     else
  523.         {
  524.         if (ang_e <= 0.0 && ang_i <= 0.0)
  525.             cw = (ang_e < ang_i) ? 1 : 0;
  526.         else
  527.             {
  528.             if (ang_e <= 0.0 && ang_i >= 0.0)    /* first conflict */
  529.                 cw = (ang_i - ang_e <= 180.0) ? 1 : 0;
  530.             else
  531.                 if (ang_e >= 0.0 && ang_i <= 0.0)
  532.                     cw = (ang_e - ang_i >= 180.0) ? 1 : 0;
  533.             }
  534.         }
  535.     /* now we have determined which direction the arc is drawn (either cw or ccw) */
  536.  
  537.     switch (cw)
  538.         {
  539.         case 0:    /* counter clockwise rotation */
  540.             DB (printf ("counter-clockwise rotation\n");)
  541.             if (start_ang >= 0.0 && stop_ang >= 0.0)
  542.                 {
  543.                 stop_ang += (start_ang > stop_ang) ? 360.0 : 0.0;  /* 1 */
  544.                 }
  545.             else
  546.                 {
  547.                 if (start_ang <= 0.0 && stop_ang <= 0.0)
  548.                     {
  549.                     stop_ang += (start_ang > stop_ang) ? 360.0 : 0.0; /* 2 */
  550.                     }
  551.                 else
  552.                     if (start_ang >= 0.0 && stop_ang <= 0.0) /* 4 */
  553.                         {
  554.                         stop_ang += 360.0;
  555.                         }
  556.                 }
  557.             break;
  558.         case 1:    /* clockwise rotation */
  559.             DB (printf ("clockwise rotation\n");)
  560.             if (stop_ang >= 0.0 && stop_ang >= 0.0)
  561.                 {
  562.                 stop_ang -= (start_ang < stop_ang) ? 360.0 : 0.0; /* 1a */
  563.                 }
  564.             else
  565.                 {
  566.                 if (start_ang <= 0.0 && stop_ang <= 0.0)
  567.                     {
  568.                     stop_ang -= (start_ang < stop_ang) ? 360.0 : 0.0; /* 2a */
  569.                     }
  570.                 else
  571.                     if (start_ang <= 0.0 && stop_ang >= 0.0) /* 4a */
  572.                         {
  573.                         stop_ang -= 360.0;
  574.                         }
  575.                 }
  576.             break;
  577.         default: break;
  578.         }
  579.  
  580.     segs = (int) (fabs (start_ang - stop_ang) / ang2 + 0.5);    /* # segments in "ang1" deg. */
  581.         /* sign of 'segs' changes direction of arc () */
  582.  
  583.     DB (printf ("final: start_ang = %lf, stop_ang = %lf\n", start_ang, stop_ang);)
  584.     DB (printf ("chord angle = %lf, # segments = %d\n", ang2, segs);)
  585.  
  586.     move (xc, yc);    /* move to center of arc */
  587.     arc (radius, segs ,start_ang, stop_ang);
  588.  
  589.     plotted_on (1);        /* we drew something on this plot */
  590.     return;
  591.     }
  592.  
  593. /*--------------------------------------*/
  594.  
  595. void init_fills (void)
  596.     {    /* since only hatched fill defined, only need to initialize it */
  597.  
  598.     /* values for hatched fill and cross-hatched fill */
  599.     /* for DEFAULTUNITS, spacing must be determined at the same time 
  600.     the fill is used for drawing since P1 & P2 could have changed */
  601.  
  602.     fill_code [HATCH].mode = fill_code [XHATCH].mode = DEFAULTUNITS;
  603.  
  604.     /* don't care about either opt1 or alt_opt1 since default unit sizes
  605.     are calculated when they are drawn */
  606.  
  607.     fill_code [HATCH].opt1 = fill_code [XHATCH].opt1 = 0.0;
  608.     fill_code [HATCH].alt_opt1 = fill_code [XHATCH].alt_opt1 = 0.0;
  609.  
  610.     fill_code [HATCH].opt2  = fill_code [XHATCH].opt2 = 0.0;    /* angle = 0 */
  611.  
  612.     select_fill = DEFAULT_FILL;    /* select default fill */
  613.  
  614.     return;
  615.     }
  616.  
  617. /*--------------------------------------*/
  618.  
  619. void fix_hatch ( void )
  620.     {
  621.     /* don't care if scaling is on or off.  This only affects hatch sizes
  622.     when they are in user units and the scale changes */
  623.  
  624.     /* fill_code [].opt1 is in user units; fill_code [].alt_opt1 is in plotter units */
  625.  
  626.     if (fill_code [HATCH].mode == USERUNITS)
  627.         fill_code [HATCH].alt_opt1 = fill_code [HATCH].opt1 / uu_2_pux;
  628.     if (fill_code [XHATCH].mode == USERUNITS)
  629.         fill_code [XHATCH].alt_opt1 = fill_code [XHATCH].opt1 / uu_2_pux;
  630.     return;
  631.     }
  632.  
  633. /*--------------------------------------*/
  634.  
  635. void fill_type (FILE *infile, int scaling )
  636.     {
  637.     double ftype, opt1, opt2;
  638.     int f1, f2, type;
  639.  
  640.     f1 = f2 = 0;    /* no arguments */
  641.     opt1 = opt2 = 0.0;
  642.     if (get_val (infile, &ftype))
  643.         {
  644.         /* test for invalid type */
  645.         if (ftype < 1.0 || ftype > 11.0 || (ftype > 4.0 && ftype < 10.0))
  646.             {
  647.             while (get_val (infile, &opt1));    /* dump trailing arguments */
  648.             return;
  649.             }
  650.         /* have one value argument */
  651.         if (get_val (infile, &opt1))
  652.             {
  653.             f1 = 1;    /* mark option #1 present */
  654.             if (get_val (infile, &opt2))
  655.                 f2 = 1;    /* mark option #2 present */
  656.             }
  657.         type = (int) ftype;
  658.         type = (type > 4) ? (type - 6) : type - 1;    /* shift range to 0 - 5 */
  659.         }
  660.     else
  661.         {
  662.         type = DEFAULT_FILL;    /* no fill-type -> default */
  663.         select_fill = type;    /* save current fill-type */
  664.         fill_code [type].mode = DEFAULTUNITS;
  665.         /* calculate size of units when fill is drawn */
  666.         return;
  667.         }
  668.  
  669.     switch (type)
  670.         {
  671.         case 0: select_fill = type;    /* save current fill-type */
  672.             return;    /* solid fill:  not yet implimented */
  673.             break;
  674.         case 1: select_fill = type;    /* save current fill-type */
  675.             return;    /* solid_fill:  not yet implimented */
  676.             break;
  677.         case HATCH:    /* hatched fill */
  678.         case XHATCH:    /* crosshatched fill */
  679.  
  680.             select_fill = type;    /* save current fill-type */
  681.  
  682.             if (f1 && opt1 == 0.0)    /* use default spacing */
  683.                 fill_code [type].mode = DEFAULTUNITS;
  684.                 /* calculate size of units when fill is drawn */
  685.  
  686.             if (f1)
  687.                 {
  688.                 fill_code [type].mode = PLOTTERUNITS;    /* assume plotter units */
  689.                 fill_code [type].alt_opt1 = opt1;    /* save hatch x-spacing in plotter units */
  690.                     /* don't care about size in user units */
  691.                 if (scaling == ON)
  692.                     {
  693.                     fill_code [type].mode = USERUNITS;    /* correct assumption about units */
  694.                     fill_code [type].opt1 = opt1;    /* user units value */
  695.                     fill_code [type].alt_opt1 = opt1 / uu_2_pux;
  696.                     /* save value of option #1 in plotter units */
  697.  
  698.                     /* we do this because HPGL/2 demands that use units
  699.                     be frozen in equivalent plotter units if scaling is
  700.                     turned off */
  701.                     }
  702.                 }
  703.  
  704.             /* update angle value only if user supplied */
  705.  
  706.             if (f2) fill_code [type].opt2 = opt2;
  707.  
  708.             break;
  709.         case 4: select_fill = type;    /* save current fill-type */
  710.             return;    /* shaded fill:  not yet implimented */
  711.             break;
  712.         case 5: select_fill = type;    /* save current fill-type */
  713.             return;    /* user defined fill: not yet implimented */
  714.             break;
  715.         default: break;
  716.         }
  717.  
  718.     return;
  719.     }
  720. /*--------------------------------------*/
  721.  
  722. void draw_rect (FILE * infile, int type)
  723.     {    /* type 0 = absolute, type 1 = relative, 0x10 = absolute, filled,
  724.             0x11 = relative, filled */
  725.     double xp, yp, xc, yc, x_sp, theta;
  726.  
  727.     DB ({if (type & 0x10) printf ("%s\n", (type & 1) ? "RR" : "RA");})
  728.     DB ({if (!(type &0x10)) printf ("%s\n", (type & 1) ? "ER" : "EA");})
  729.     where (&xp, &yp);    /* get current position */
  730.     if (get_xy (infile, &xc, &yc))
  731.         {
  732.         /* calculate width and height for rectangle () function */
  733.         if (type & 1)    /* relative rect */
  734.             {
  735.             xc += xp;
  736.             yc += yp;    /* calculate opposite corner pos */
  737.             }
  738.         DB (printf ("Rectangle from (%lf, %lf) to  (%lf, %lf)\n", xp, yp, xc, yc);)
  739.         rectangle (xp, yp, xc, yc);
  740.         if (type & 0x10)
  741.             {
  742.             DB (printf ("filled rectangle: select_fill = %d\n", select_fill);)
  743.             if (select_fill != HATCH && select_fill != XHATCH)
  744.                 {
  745.                 plotted_on (1);    /* mark plot as dirty */
  746.                 return;    /* for now, only hatched or cross-hatched fill */
  747.                 }
  748.             theta = fill_code [select_fill].opt2;    /* theta */
  749.  
  750.             /* get current hatch spacing in plotter units */
  751.             /* for default units, calculate size now */
  752.             switch (fill_code [select_fill].mode)
  753.                 {
  754.                 case DEFAULTUNITS:
  755.                     x_sp = 0.01 * sqrt ( (p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
  756.                     break;
  757.                 case PLOTTERUNITS:
  758.                 case USERUNITS:
  759.                     x_sp = fill_code [select_fill].alt_opt1;
  760.                     /* x-spacing is in plotter units */
  761.                     break;
  762.                 default: break;
  763.                 }
  764.  
  765.             plotter_units (&xp, &yp);
  766.             plotter_units (&xc, &yc);    /* corner coordinates in plotter units */
  767.             fill_rect (xp, yp, xc, yc, x_sp, theta);
  768.             if (select_fill == XHATCH)    /* if cross-hatch, draw crossing hatch at theta + 90 */
  769.                 fill_rect (xp, yp, xc, yc, x_sp, theta + 90.0);
  770.             }
  771.         plotted_on (1);        /* we drew something on this plot */
  772.         return;
  773.         }
  774.  
  775.     if (type & 0x10)
  776.         {
  777.         if (type & 1)
  778.             print_string ("ER: missing argument\n");
  779.         else
  780.             print_string ("EA: missing argument\n");
  781.         }
  782.     else
  783.         {
  784.         if (type & 1)
  785.             print_string ("RR: missing argument\n");
  786.         else
  787.             print_string ("RA: missing argument\n");
  788.         }
  789.  
  790.     return;
  791.     }
  792.  
  793. /*--------------------------------------*/
  794.  
  795. static void fill_rect (double x_1, double y_1, double x_2, double y_2, double x_sp, double theta)
  796.     {
  797.     double ymin, ymax, xmin, xmax;
  798.     double xd1, yd1, xd2, yd2, ac_x, ac_y, x_off, xh;
  799.     double yh, yi, xi, y_off, xlast, ylast, etan, ecot, theta_r;
  800.     int n, sector;
  801.  
  802.     get_anchor (&ac_x, &ac_y);    /* get anchor corner in plotter units */
  803.                     /* x_sp, x_1, x_2, y_1, y_2  all in plotter units */
  804.  
  805.     xmin = x_1;
  806.     ymin = y_1;
  807.     xmax = x_2;
  808.     ymax = y_2;
  809.  
  810.     DB (printf ("hatch_fill: x_sp = %lf, theta = %lf\n", x_sp, theta);)
  811.  
  812.     theta = fmod (theta, 180.0);
  813.     theta_r = theta / RAD_2_DEG;
  814.  
  815.     if (theta < 90.0)
  816.         {        /* sectors 1,5 */
  817.         if (theta < 45.0)
  818.             {
  819.             sector = 1;
  820.             yi = (x_1 - ac_x) * tan (theta_r) + ac_y;
  821.             yh = x_sp / cos (theta_r);    /* this fails at theta = 90 */
  822.  
  823.             y_off = fmod (y_2 - yi, yh);    /* get distance below top edge for starting point */
  824.  
  825.             y_1 = ymax - y_off;
  826.  
  827.             if (y_1 > ymax) y_1 -= yh;    /* check case of yi > y_1 */
  828.             if (y_1 < ymin) y_1 += yh;    /* check case of yi < y_1 */
  829.             y_2 = y_1 + (xmax - xmin) * tan (theta_r);
  830.             }
  831.         else
  832.             {    /* sectors 2, 6 */
  833.             sector = 2;
  834.             xi = (y_1 - ac_y) * cot (theta_r) + ac_x;
  835.             xh = x_sp / sin (theta_r);    /* this fails at theta = 0 */
  836.  
  837.             x_off = fmod (x_2 - xi, xh);    /* get distance inside of right edge for starting point */
  838.  
  839.             x_1 = xmax - x_off;
  840.             if (x_1 > xmax) x_1 -= xh;    /* check case of xi > x_1 */
  841.             if (x_1 < xmin) x_1 += xh;    /* check case of xi < x_1 */
  842.             x_2 = x_1 + (ymax - ymin) * cot (theta_r);
  843.             }
  844.  
  845.         }
  846.     else        /* sectors 4,8 */
  847.         {
  848.         if (theta > 135.0)
  849.             {
  850.             sector = 4;
  851.             yi = (x_2 - ac_x) * tan (theta_r) + ac_y;
  852.             yh = - x_sp / cos (theta_r);    /* this fails at theta = 90 */
  853.  
  854.             /* get distance above bottom edge for starting point */
  855.             y_off = fmod (y_2 - yi, yh);
  856.  
  857.             y_1 = ymax - y_off;
  858.             if (y_1 > ymax) y_1 -= yh;    /* check case of yi > y_1 */
  859.             if (y_1 < ymin) y_1 += yh;    /* check case of yi < y_1 */
  860.             y_2 = y_1 - (xmax - xmin) * tan (theta_r);
  861.             /* tan (theta) < 0 for 90 <= theta < 180 */
  862.  
  863.             xmin = x_2;
  864.             xmax = x_1;
  865.             }
  866.         else
  867.             {    /* sectors 3,7 */
  868.             sector = 3;
  869.             xi = (y_2 - ac_y) * cot (theta_r) + ac_x;
  870.             xh = x_sp / sin (theta_r);    /* this fails at theta = 0 */
  871.  
  872.             x_off = fmod (x_2 - xi, xh);    /* get distance inside of right edge for starting point */
  873.  
  874.             x_1 = xmax - x_off;
  875.  
  876.             if (x_1 > xmax) x_1 -= xh;    /* check case of xi > x_1 */
  877.             if (x_1 < xmin) x_1 += xh;    /* check case of xi < x_1 */
  878.             x_2 = x_1 - (ymax - ymin) * cot (theta_r);
  879.  
  880.             ymax = y_1;
  881.             ymin = y_2;
  882.             }
  883.  
  884.         }
  885.  
  886.  
  887.     if (x_sp == 0.0) return;    /* no point in wasting time */
  888.  
  889.     where (&xlast, &ylast);        /* get current position */
  890.  
  891.     n = 0;        /* emergency break-out counter */
  892.  
  893.     if (sector == 1 || sector == 4)
  894.         {
  895.         etan = tan (theta_r);
  896.         while (y_2 > ymin && n < 2048)    /* this loop only works for 0 <= theta < 90 */
  897.             {
  898.             ++n;
  899.             xd1 = xmin;
  900.             yd1 = y_1;
  901.             xd2 = xmax;
  902.             yd2 = y_2;
  903.  
  904.             if (yd2 > ymax) 
  905.                 {
  906.                 yd2 = ymax;
  907.                 xd2 = xmin + (yd2 - y_1) / etan;
  908.                 }    /* never reach this case if theta == 0 since */
  909.                     /* y_1 == y_2 and y_1 < ymax */
  910.  
  911.             if (yd1 < ymin)
  912.                 {
  913.                 yd1 = ymin;
  914.                 xd1 = xmin + (ymin - y_1) / etan;
  915.                 }    /* never reach this case if theta == 0 since y_2 == y_1 */
  916.                     /* and loop begins with y_1 >= ymin */
  917.  
  918.             move (xd1, yd1);
  919.             draw (xd2, yd2);
  920.             y_1 -= yh;
  921.             y_2 -= yh;
  922.             }
  923.         }
  924.     else        /* sectors 2, 3 */
  925.         {
  926.         ecot = cot (theta_r);
  927.         while (x_2 > xmin && n < 2048)    /* this loop decrements x sizes */
  928.             {
  929.             ++n;
  930.             xd1 = x_1;
  931.             yd1 = ymin;
  932.             xd2 = x_2;
  933.             yd2 = ymax;
  934.  
  935.             if (xd2 > xmax) 
  936.                 {
  937.                 xd2 = xmax;
  938.                 yd2 = ymin + (xd2 - x_1) / ecot;
  939.                 }    /* never reach this case if theta == 0 since */
  940.                     /* x_1 == x_2 and x_1 < xmax */
  941.  
  942.             if (xd1 < xmin)
  943.                 {
  944.                 xd1 = xmin;
  945.                 yd1 = ymin + (xmin - x_1) / ecot;
  946.                 }    /* never reach this case if theta == 0 since y_2 == y_1 */
  947.                     /* and loop begins with x_1 >= xmin */
  948.  
  949.             move (xd1, yd1);
  950.             draw (xd2, yd2);
  951.             x_1 -= xh;
  952.             x_2 -= xh;
  953.             }
  954.         }
  955.  
  956.     move (xlast, ylast);    /* return to original position */
  957.     }
  958.  
  959. /*-------------------------------------*/
  960.  
  961. static double cot ( double theta )
  962.     {    /* valid from 0 to 180 degrees */
  963.     double a;
  964.  
  965.     a = cos (theta);
  966.     return ( a * sqrt ( 1.0 - a * a));
  967.     }
  968.  
  969. /*--------------------------------------*/
  970.  
  971. void draw_wedge (FILE * infile)
  972.     {
  973.     double radius, xc, yc, x_1, y_1, val4, ang1, ang2, ang3;
  974.     int segs;
  975.  
  976.     DB (printf ("EW\n");)
  977.     if (!get_val (infile, &radius))
  978.         {
  979.         print_string ("EW: missing radius\n");
  980.         return;    /* illegal instr */
  981.         }
  982.     if (!get_val (infile, &ang1))
  983.         {
  984.         print_string ("EW: missing start_ang\n");
  985.         return;    /* illegal instr */
  986.         }
  987.     if (!get_val (infile, &ang2))    /* arc angle */
  988.         {
  989.         print_string ("EW: missing sweep angle\n");
  990.         return;    /* illegal instr */
  991.         }
  992.     where (&xc, &yc);    /* get starting point */
  993.     DB (printf ("center: (x,y) = (%lf, %lf), start angle = %lf\n", xc, yc, ang1);)
  994.  
  995.     val4 = ang3 = DEF_CHORD;
  996.     if (get_val (infile, &val4))
  997.         {
  998.         val4 = fabs (val4);    /* only positive values allowed */
  999.         if (chord_type == ANG || val4 == 0.0)        /* using angles, not deviations */
  1000.             {
  1001.             if (val4 == 0.0) val4 = DEF_CHORD;    /* set default chord angle or deviation */
  1002.             ang3 = MIN (MAX_CHORD, (MAX (val4, MIN_CHORD)));
  1003.             }
  1004.         else        /* chord angle determined by deviation of segments from circle radius */
  1005.             {    /* at this point, val4 is length in current units, not angle in degrees */
  1006.             if (val4 > 2.0 * radius) val4 = 2.0 * radius;    /* limit deviation: resulting chord angle < 180 deg. */
  1007.             ang3 = acos ( (radius - val4) / radius) * RAD_2_DEG;
  1008.             }
  1009.         }
  1010.     segs = (int) (fabs (ang2) / ang3 + 0.5);    /* # segments in "ang1" deg. */
  1011.         /* sign of 'segs' changes direction of arc () */
  1012.  
  1013.     DB (printf ("chord = %lf, # segments = %d\n", ang3, segs);)
  1014.     DB (printf ("radius = %lf, start angle = %lf, stop angle = %lf\n", radius, ang1, ang1 + ang2);)
  1015.     x_1 = xc + radius * cos (ang1 / RAD_2_DEG);
  1016.     y_1 = yc + radius * sin (ang1 / RAD_2_DEG);    /* position of start of arc */
  1017.  
  1018.     draw (x_1, y_1);            /* draw line from center to start of arc */
  1019.     move (xc, yc);
  1020.     arc ( radius, segs, ang1, ang1 + ang2);    /* draw arc: leaves pen at end of arc */
  1021.     draw (xc, yc);                /* draw line from end of arc to center */
  1022.  
  1023.     if (symbol_mode)
  1024.         {
  1025.         symbol_mark (symbol);
  1026.         }
  1027.  
  1028.     plotted_on (1);        /* we drew something on this plot */
  1029.     return;
  1030.     }
  1031.  
  1032. /*--------------------------------------*/
  1033.  
  1034. void chord_t (FILE * infile)
  1035.     {
  1036.     double x;
  1037.  
  1038.     if (get_val (infile, &x))
  1039.         {
  1040.         if (x == 1.0)
  1041.             {
  1042.             chord_type = LENGTH;
  1043.             return;
  1044.             }
  1045.         if (x != 0.0)
  1046.             {
  1047.             print_string ("CT: invalid argument\n");
  1048.             return;
  1049.             }
  1050.         }
  1051.     chord_type = ANG;    /* chord type in degree's */
  1052.     return;
  1053.     }
  1054.  
  1055. /*--------------------------------------*/
  1056.