home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / GRAPHICS / SHOWGL10.ZIP / HPGL1.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-29  |  28.9 KB  |  1,037 lines

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