home *** CD-ROM | disk | FTP | other *** search
/ Graphics 16,000 / graphics-16000.iso / msdos / viewers / showgl19 / hpgl1.c < prev    next >
C/C++ Source or Header  |  1992-08-18  |  35KB  |  1,232 lines

  1. #pragma linesize(132)    /* listing linewidth = 132 */
  2.  
  3. /* hpgl1.c */
  4. /* This code Copyright 1991, 1992, Robert C. Becker, Lantern Systems */
  5.  
  6.  
  7. /* rev. E 8/16/92
  8.  
  9. Added solid line fill type to filled rectangles.  Also added new window 
  10. window clipper.  It was needed for solid fill type because we do direct
  11. access to pw_wrt_line () in the graphix library.  This routine also cleaned
  12. up some of the clipping code in showhpgl.c and fixed a few bugs related to
  13. drawing outside the P1/P2 hard clip if IW was defined larger than the
  14. hard clip border
  15. */
  16.  
  17. /* rev. D 8/13/92
  18.  
  19.     Relocated some code from hpgl1.c to hpgl2.c to make file sizes more
  20. equal and reduce compile time of hpgl1.c . */
  21.  
  22. /* Rev. C.  8/8/92
  23.  
  24. Found and fixed bugs in tick mark calculation and filled rectangles.  The tick
  25. mark bug manifested itself as not resizing tick sizes when P1/P2 changed.  Part
  26. of the fix is in showhpgl.c .  Added recalc_ticksize ().
  27.  
  28. Found and fixed bug in filled rectangle drawing routines.  Fixed logic errors 
  29. in fill_type () which assigned the wrong units when default spacing was in
  30. effect.  fill_rect () attempted to draw in plotter units even if user unit
  31. scaling was in effect. 
  32. */
  33.  
  34. /* Rev. B.  8/2/92  
  35.  
  36. Found a bug in tick mark drawing routines.  In order to simplify the need
  37. to draw in a consistent size unit based on the P1/P2 spacings, the tick size
  38. was calculated in GDU's and the drawing mode was changed from UDU's to GDU's.
  39. This, unfortunately, reset the clip border to the hardclip limit, instead of
  40. the UDU border and allowed ticks to be drawn outside the soft clip border.
  41. calc_ticksize () has been changed to calculate tick sizes in plotter units,
  42. and two other variables (uu_2_pux, uu_2_puy) which are calculated every time
  43. set_scale () is called convert from user units to ploter units depending on
  44. scaling = ON/OFF.
  45. */
  46.  
  47. /* Rev. A.  */
  48.  
  49. /* This file contains the following functions:
  50.  
  51.     arc_3pt ()
  52.     calc_ticksize ()
  53.     chord_t ()
  54.     circle ()
  55.     cot ()
  56.     draw_xtick ()
  57.     draw_ytick ()
  58.     draw_rect ()
  59.     fill_rect ()
  60.     fill_type ()
  61.     fix_hatch ()
  62.     init_fills ()
  63.     new_plot ()
  64.     plotted_on ()
  65.     print_error ()
  66.     recalc_ticksize ()
  67.     tick_length ()
  68.     velocity_sel ()
  69.  
  70. */
  71.  
  72. #include <stdio.h>
  73. #include <stdlib.h>
  74. #include <math.h>
  75. #include <float.h>
  76. #include "graph.h"    /* this must preceed hpgl.h */
  77. #include "mscio.h"    /* header for pc_wrt_line () */
  78. #include "gstructs.h"    /* header file for library structures */
  79. #include "hpgl.h"
  80.  
  81. extern struct hp_misc __gr_msc__;    /* library struct */
  82.  
  83. extern struct clip_border hpgl_clip;
  84. extern int my_pen;
  85. extern int scaling;
  86. extern double p1x, p1y, p2x, p2y;
  87. extern int chord_type, p_status, symbol_mode;
  88. extern double uu_2_pux, uu_2_puy;
  89. extern char symbol;
  90. extern int debugging;
  91.  
  92. static void fill_rect (double, double, double, double, double, double);
  93. static double cot ( double );
  94. static void solid_rect ( double, double, double, double );
  95. static int code ( int, int);
  96.  
  97. static char copyright[] = "Copyright 1991, 1992, Robert C. Becker, Lantern Systems";
  98.  
  99. struct poly_fills
  100.     {
  101.     int mode;
  102.     double opt1, opt2;
  103.     double alt_opt1;
  104.     };
  105.  
  106. static struct poly_fills fill_code [6];    /* hold values for types 1, 2, 3, 4, 10, 11 */
  107.                     /* values for these type stored in this order in struct array */
  108.  
  109. struct tick
  110.     {
  111.     double tnx, tny, tpx, tpy, tn, tp;
  112.     /* x, y tick negative & positive lengths in plotter units; tx, ty in % */
  113.     };
  114.  
  115. static struct tick ticksize;
  116.  
  117. static int select_fill;            /* last fill type selected */
  118. static double anchor_x, anchor_y;    /* corner anchors for fill types */
  119. static int dirty_plot;            /* flag to mark if plot has been plotted on yet */
  120.  
  121. /*--------------------------------------*/
  122.  
  123. void velocity_sel (FILE *infile)
  124.     {
  125.     double x;
  126.  
  127.     DB (printf ("VS\n");)
  128.     if (get_val (infile, &x))    /* optional speed argument: not used */
  129.         {
  130.         get_val (infile, &x);    /* optional pen # argument: not used */
  131.         }
  132.     return;
  133.     }
  134.  
  135. /*--------------------------------------*/
  136.  
  137. void tick_length (FILE *infile)
  138.     {
  139.     double tp, tn;
  140.  
  141.     tp = DEF_TICK;
  142.     tn = DEF_TICK;        /* default tick lengths */
  143.     if ( get_val (infile, &tp))    /* got one value: try for two */
  144.         {
  145.         if (!get_val (infile, &tn)) tn = 0.0;    /* if only have one value, tn = 0 */
  146.         }
  147.     calc_ticksize (tp, tn);
  148.  
  149.     return;
  150.     }
  151.  
  152. /*--------------------------------------*/
  153.  
  154. void recalc_ticksize ( void )
  155.     {
  156.  
  157.     /* force recalculation of ticksize when P1/P2 change */
  158.     calc_ticksize (ticksize.tp, ticksize.tn);
  159.  
  160.     return;
  161.     }
  162.  
  163. /*--------------------------------------*/
  164.  
  165. void calc_ticksize (double tp, double tn)
  166.     {
  167.  
  168.     tp = MAX (-100.0, (MIN (100.0, tp)));
  169.     tn = MAX (-100.0, (MIN (100.0, tn)));    /* limit tick size to +/- 100% */
  170.  
  171.     ticksize.tp = tp;
  172.     ticksize.tn = tn;    /* save tick lengths */
  173.  
  174.     /* calculate tick lengths (plotter units) for x- and y-axes */
  175.  
  176.     ticksize.tpx = tp * fabs (p2x - p1x) / 100.0;
  177.     ticksize.tpy = tp * fabs (p2y - p1y) / 100.0;
  178.     ticksize.tnx = tn * fabs (p2x - p1x) / 100.0;
  179.     ticksize.tny = tn * fabs (p2y - p1y) / 100.0;
  180.     /* P1, P2 are in mils (plotter units) */ 
  181.  
  182.     DB (printf ("calc_ticksize: tpx = %lf, tnx = %lf, tpy = %lf, tny = %lf\n", \
  183.         ticksize.tpx, ticksize.tnx, ticksize.tpy, ticksize.tny);)
  184.  
  185.     return;
  186.     }
  187.  
  188. /*--------------------------------------*/
  189.  
  190. void draw_xtick (void)
  191.     {
  192.     double x_1, y_1;
  193.     double ystart, ystop;    /* local variables */
  194.  
  195.     /* move relative to current position.  Convert plotter units to user
  196.     units if required */
  197.  
  198.     ystart = -ticksize.tny;
  199.     ystop = ticksize.tpy;    /* start & stop points in plotter units */
  200.  
  201.     if (scaling == ON)    /* start & stop points in user units */
  202.         {
  203.         ystart = -ticksize.tny * uu_2_puy;
  204.         ystop = ticksize.tpy * uu_2_puy;
  205.         }
  206.  
  207.     where (&x_1, &y_1);        /* get starting position */
  208.  
  209.     DB (printf ("draw_xtick: scaling = %d, ystart = %lf, ystop = %lf\n", \
  210.         scaling, ystart, ystop);)
  211.  
  212.     rmove (0.0, ystart);    /* move relative to current position */
  213.     rdraw (0.0, ystop);    /* draw vertical tick mark */
  214.     move (x_1, y_1);    /* re-establish original position */
  215.     plotted_on (1);        /* we drew something on this plot */
  216.  
  217.     return;
  218.     }
  219.  
  220. /*--------------------------------------*/
  221.  
  222. void draw_ytick (void)
  223.     {
  224.     double x_1, y_1;
  225.     double xstart, xstop;    /* local variables */
  226.  
  227.     /* move relative to current position.  Convert plotter units to user
  228.     units if required */
  229.  
  230.     xstart = -ticksize.tnx;
  231.     xstop = ticksize.tpx;    /* start & stop points in plotter units */
  232.  
  233.     if (scaling == ON)    /* start & stop points in user units */
  234.         {
  235.         xstart = -ticksize.tnx * uu_2_pux;
  236.         xstop = ticksize.tpx * uu_2_pux;
  237.         }
  238.  
  239.     where (&x_1, &y_1);
  240.  
  241.     DB (printf ("draw_ytick: scaling = %d, xstart = %lf, xstop = %lf\n", \
  242.         scaling, xstart, xstop);)
  243.  
  244.     rmove (xstart, 0.0);
  245.     rdraw (xstop, 0.0);    /* draw horizontal tick mark */
  246.     move (x_1, y_1);    /* re-establish original position */
  247.     plotted_on (1);        /* we drew something on this plot */
  248.  
  249.     return;
  250.     }
  251.  
  252. /*--------------------------------------*/
  253.  
  254. void print_error (char *instr, int type)
  255.     {
  256.  
  257.     if (!debugging) return;    /* no output if not asked for */
  258.  
  259.     if (type)
  260.         fprintf (stdout, "%s", instr);
  261.     else
  262.         fprintf (stdout, "%s instruction not implimented\n", instr);
  263.     return;
  264.     }
  265.  
  266. /*--------------------------------------*/
  267.  
  268. void new_plot ( void )
  269.     {
  270.  
  271.     dirty_plot = 0;    /* plot is clean (not plotted on) */
  272.     return;
  273.     }
  274.  
  275. /*--------------------------------------*/
  276.  
  277. int plotted_on (int plot_flag)
  278.     {
  279.  
  280.     if (plot_flag > 0)
  281.         dirty_plot = 1;    /* mark plot as plotted on */
  282.     return (dirty_plot);
  283.     }
  284.  
  285. /*--------------------------------------*/
  286.  
  287. void circle (FILE * infile)
  288.     {
  289.     double ang, ang2, radius, val2, x_1, y_1;
  290.     unsigned char c2;
  291.     int segs;
  292.  
  293.     DB(printf ("CI\n");)
  294.  
  295.     if (!get_val (infile, &radius))
  296.         {
  297.         print_string ("CI: radius not specified\n");
  298.         return;    /* error: no param's */
  299.         }
  300.  
  301.     ang2 = val2 = DEF_CHORD;    /* default chord angle or deviation for circle/arc */
  302.     if ( get_val (infile, &val2))
  303.         {
  304.         val2 = fabs (val2);    /* only positive values allowed */
  305.         if (chord_type == ANG || val2 == 0.0)        /* using angles, not deviations */
  306.             {
  307.             if (val2 == 0.0) val2 = DEF_CHORD;    /* set default chord angle or deviation */
  308.             ang2 = MIN (MAX_CHORD, (MAX (val2, MIN_CHORD)));
  309.             }
  310.         else        /* chord angle determined by deviation of segments from circle radius */
  311.             {    /* at this point, val2 is length in current units, not angle in degrees */
  312.             if (val2 > 2.0 * radius) val2 = 2.0 * radius;    /* limit deviation: resulting chord angle < 180 deg. */
  313.             ang2 = acos ( (radius - val2) / radius) * RAD_2_DEG;
  314.             }
  315.         }
  316.     segs = (int) (360.0 / ang2 + 0.5);    /* # segments in 360 deg. */
  317.         /* sign of 'segs' changes direction of arc () */
  318.     DB (printf ("CI: radius = %lf, chord = %lf, # segments = %d\n", radius, ang2, segs);)
  319.     where (&x_1, &y_1);
  320.     arc (radius, segs, 0.0, 360.0);    /* circle with l segments */
  321.     if (symbol_mode)
  322.         {
  323.         move (x_1, y_1);
  324.         symbol_mark (symbol);
  325.         }
  326.     plotted_on (1);        /* we drew something on this plot */
  327.     return;
  328.     }
  329.  
  330. /*--------------------------------------*/
  331.  
  332. void arc_3pt (FILE * infile, int type)
  333.     {    /* type 0 = absolute arc, type 1 = relative arc */
  334.     double ma, mb, ba, bb, x_1, y_1, xi, yi, xe, ye;
  335.     double dax, day, dbx, dby, xc, yc, ang_e, ang_i;
  336.     double start_ang, stop_ang, radius, ang2, val5;
  337.     int segs, cw;
  338.  
  339.     DB (if (type == RELATIVE) printf ("AR\n"); else printf ("AT\n");)
  340.     if (!get_xy (infile, &xi, &yi))
  341.         {
  342.         if (type == RELATIVE)
  343.             print_string ("AR: missing Xi or Yi value\n");
  344.         else
  345.             print_string ("AT: missing Xi or Yi value\n");
  346.         return;
  347.         }
  348.     if (!get_xy (infile, &xe, &ye))
  349.         {
  350.         if (type == RELATIVE)
  351.             print_string ("AR: missing Xe or Ye value\n");
  352.         else
  353.             print_string ("AT: missing Xe or Ye value\n");
  354.         return;
  355.         }
  356.  
  357.     where (&x_1, &y_1);        /* current position */
  358.     if (type == RELATIVE)        /* relative arc in 3 pts */
  359.         {
  360.         xe += x_1;
  361.         ye += y_1;
  362.         xi += x_1;
  363.         yi += y_1;    /* convert from offsets to abs coordinates */
  364.         }
  365.  
  366.     dax = xe - x_1;
  367.     day = ye - y_1;        /* delta-x, -y from ref. to end pt. */
  368.     dbx = xi - xe;
  369.     dby = yi - ye;        /* delta-x, -y from end pt. to intermediate pt. */
  370.  
  371.     DB (printf ("P1: (%lf, %lf) Pi: (%lf, %lf), Pe: (%lf, %lf)\n", x_1, y_1, xi, yi, xe, ye);)
  372.     DB (printf ("fabs (day) = %lf, fabs(dby) = %lf\n", fabs(day), fabs(dby));)
  373.  
  374.     if ( fabs (day) < FLT_EPSILON)    /* P1, Pe horizontal or same */
  375.         {        /* FLT, not DBL: more conservative */
  376.         DB (printf ("fabs (day) < FLT_EPSILON\n");)
  377.         xc = x_1 + dax / 2;        /* equation of vertical line */
  378.         if (fabs (dby) < FLT_EPSILON || fabs (dax) < FLT_EPSILON)
  379.             {            /* all pts horizontal */
  380.             DB (printf ("vertical or straight line curve\n");)
  381.             if (symbol_mode)
  382.                 {
  383.                 move (x_1, y_1);
  384.                 symbol_mark (symbol);
  385.                 }
  386.             draw (xi, yi);        /* draw intermediate pt in case end & start same */
  387.             draw (xe, ye);        /* this is the curve */
  388.  
  389.             plotted_on (1);        /* we drew something on this plot */
  390.             return;
  391.             }
  392.         mb = -dbx / dby;        /* slope of line normal to PePi */
  393.         bb = (ye + dby / 2) - mb * (xe + dbx / 2);    /* now have b-part of line equations */
  394.         yc = mb * xc + bb;
  395.         }
  396.     else
  397.         {    /* FLT, not DBL: more conservative */
  398.         if (fabs (dby) < FLT_EPSILON)    /* Pe, Pi horizontal or same */
  399.             {
  400.             DB (printf ("fabs (dby) < FLT_EPSILON\n");)
  401.             xc = xe + dbx / 2;        /* equation of vertical line */
  402.             if (fabs (day) < FLT_EPSILON || fabs (dbx) < FLT_EPSILON)
  403.                 {            /* all pts horizontal or Pe == Pi */
  404.                 DB (printf ("horizontal or straight line curve\n");)
  405.                 if (symbol_mode)
  406.                     {
  407.                     move (x_1, y_1);
  408.                     symbol_mark (symbol);
  409.                     }
  410.                 draw (xi, yi);        /* draw intermediate pt in case end & start same */
  411.                 draw (xe, ye);        /* this is the curve */
  412.                 plotted_on (1);        /* we drew something on this plot */
  413.                 return;
  414.                 }
  415.             ma = -dax / day;    /* slope of line normal to PiPe */
  416.             ba = (y_1 + day / 2) - ma * (x_1 + dax / 2);
  417.             yc = ma * xc + ba;
  418.             }
  419.         else
  420.             {
  421.  
  422.             /* general case:  can't handle dby = 0 or day = 0 */
  423.             ma = -dax / day;        /* slope of line normal to P1Pe */
  424.             mb = -dbx / dby;        /* slope of line normal to PePi */
  425.  
  426.                 /* y_1 + day = y-value midway between y_1 and ye */
  427.                 /* x_1 + dax = x-value midway between x_1 and xe */
  428.                 /* ye + dby = y-value midway between ye and yi */
  429.                 /* xe + dbx = x-value midway between xe and yi */
  430.             ba = (y_1 + day / 2) - ma * (x_1 + dax / 2);
  431.             bb = (ye + dby / 2) - mb * (xe + dbx / 2);    /* now have b-part of line equations */
  432.  
  433.             if (fabs (ma - mb) < FLT_EPSILON)    /* that's right FLT, not DBL */
  434.                 {                /* too small to prevent floating point overflow */
  435.                 DB (printf ("straight line curve\n");)
  436.                 if (symbol_mode)
  437.                     {
  438.                     move (x_1, y_1);
  439.                     symbol_mark (symbol);
  440.                     }
  441.                 draw (xi, yi);        /* draw intermediate pt in case end & start same */
  442.                 draw (xe, ye);        /* this is the curve */
  443.                 return;
  444.                 }
  445.             xc = (bb - ba) / (ma - mb);        /* now have x-center */
  446.             yc = mb * xc + bb;            /* can find yc using either line eqn. */
  447.             }
  448.         }
  449.  
  450.     DB (printf ("3-pt. arc:  center at (%lf, %lf)\n", xc, yc);)
  451.  
  452.     radius = sqrt ((xc - x_1) * (xc - x_1) + (yc - y_1) * (yc - y_1));
  453.  
  454.     val5 = ang2 = DEF_CHORD;
  455.  
  456.     if (get_val (infile, &val5))
  457.         {
  458.         val5 = fabs (val5);    /* only positive values allowed */
  459.  
  460.         /* note: if no tolerance is specified, the default is a
  461.         chord ANGLE of 5 DEGREES, regardless of chord_type */
  462.  
  463.         if (chord_type == ANG || val5 == 0.0)    /* using angles, not deviations */
  464.             {
  465.             if (val5 == 0.0) val5 = DEF_CHORD;    /* set default chord angle */
  466.             ang2 = MIN (MAX_CHORD, (MAX (val5, MIN_CHORD)));
  467.             }
  468.         else        /* chord angle determined by deviation of segments from circle radius */
  469.             {    /* at this point, val5 is length in current units, not angle in degrees */
  470.  
  471.             if (val5 > 2.0 * radius) val5 = 2.0 * radius;    /* limit deviation: resulting chord angle < 180 deg. */
  472.             ang2 = acos ( (radius - val5) / radius) * RAD_2_DEG;
  473.  
  474.             /* note that this value is being left in radians (for now) */
  475.             }
  476.  
  477.         }
  478.  
  479.     DB (printf ("P1: (%lf, %lf), Pc: (%lf, %lf), Pe: (%lf, %lf)\n", x_1, y_1, xc, yc, xe, ye);)
  480.  
  481.     start_ang = RAD_2_DEG * atan2 (y_1 - yc, x_1 - xc);    /* angle from center to starting pt */
  482.     stop_ang = RAD_2_DEG * atan2 (ye - yc, xe - xc);    /* angle from center to stopping pt */
  483.  
  484.     DB (printf ("initial: start_ang = %lf, stop_ang = %lf\n", start_ang, stop_ang);)
  485.  
  486.     ang_e = RAD_2_DEG * atan2 (day, dax);
  487.     ang_i = RAD_2_DEG * atan2 ( yi - y_1, xi - x_1);    /* determine direction of arc */
  488.  
  489.     cw = 1;    /* direction defaults to clockwise rotation */
  490.  
  491.     if (ang_e >= 0.0 && ang_i >= 0.0)    /* resolve direction of arc by */
  492.         cw = (ang_e < ang_i) ? 1 : 0;    /* angle between ref. pt and other 2 pts */
  493.     else
  494.         {
  495.         if (ang_e <= 0.0 && ang_i <= 0.0)
  496.             cw = (ang_e < ang_i) ? 1 : 0;
  497.         else
  498.             {
  499.             if (ang_e <= 0.0 && ang_i >= 0.0)    /* first conflict */
  500.                 cw = (ang_i - ang_e <= 180.0) ? 1 : 0;
  501.             else
  502.                 if (ang_e >= 0.0 && ang_i <= 0.0)
  503.                     cw = (ang_e - ang_i >= 180.0) ? 1 : 0;
  504.             }
  505.         }
  506.     /* now we have determined which direction the arc is drawn (either cw or ccw) */
  507.  
  508.     switch (cw)
  509.         {
  510.         case 0:    /* counter clockwise rotation */
  511.             DB (printf ("counter-clockwise rotation\n");)
  512.             if (start_ang >= 0.0 && stop_ang >= 0.0)
  513.                 {
  514.                 stop_ang += (start_ang > stop_ang) ? 360.0 : 0.0;  /* 1 */
  515.                 }
  516.             else
  517.                 {
  518.                 if (start_ang <= 0.0 && stop_ang <= 0.0)
  519.                     {
  520.                     stop_ang += (start_ang > stop_ang) ? 360.0 : 0.0; /* 2 */
  521.                     }
  522.                 else
  523.                     if (start_ang >= 0.0 && stop_ang <= 0.0) /* 4 */
  524.                         {
  525.                         stop_ang += 360.0;
  526.                         }
  527.                 }
  528.             break;
  529.         case 1:    /* clockwise rotation */
  530.             DB (printf ("clockwise rotation\n");)
  531.             if (stop_ang >= 0.0 && stop_ang >= 0.0)
  532.                 {
  533.                 stop_ang -= (start_ang < stop_ang) ? 360.0 : 0.0; /* 1a */
  534.                 }
  535.             else
  536.                 {
  537.                 if (start_ang <= 0.0 && stop_ang <= 0.0)
  538.                     {
  539.                     stop_ang -= (start_ang < stop_ang) ? 360.0 : 0.0; /* 2a */
  540.                     }
  541.                 else
  542.                     if (start_ang <= 0.0 && stop_ang >= 0.0) /* 4a */
  543.                         {
  544.                         stop_ang -= 360.0;
  545.                         }
  546.                 }
  547.             break;
  548.         default: break;
  549.         }
  550.  
  551.     segs = (int) (fabs (start_ang - stop_ang) / ang2 + 0.5);    /* # segments in "ang1" deg. */
  552.         /* sign of 'segs' changes direction of arc () */
  553.  
  554.     DB (printf ("final: start_ang = %lf, stop_ang = %lf\n", start_ang, stop_ang);)
  555.     DB (printf ("chord angle = %lf, # segments = %d\n", ang2, segs);)
  556.  
  557.     move (xc, yc);    /* move to center of arc */
  558.     arc (radius, segs ,start_ang, stop_ang);
  559.  
  560.     plotted_on (1);        /* we drew something on this plot */
  561.     return;
  562.     }
  563.  
  564. /*--------------------------------------*/
  565.  
  566. void init_fills (void)
  567.     {    /* only need to initialize hatched & x-hatched fills */
  568.  
  569.     /* values for hatched fill and cross-hatched fill */
  570.     /* for DEFAULTUNITS, spacing must be determined at the same time 
  571.     the fill is used for drawing since P1 & P2 could have changed */
  572.  
  573.     fill_code [HATCH].mode = fill_code [XHATCH].mode = DEFAULTUNITS;
  574.  
  575.     /* don't care about either opt1 or alt_opt1 since default unit sizes
  576.     are calculated when they are drawn */
  577.  
  578.     fill_code [HATCH].opt1 = fill_code [XHATCH].opt1 = 0.0;
  579.     fill_code [HATCH].alt_opt1 = fill_code [XHATCH].alt_opt1 = 0.0;
  580.  
  581.     fill_code [HATCH].opt2  = fill_code [XHATCH].opt2 = 0.0;    /* angle = 0 */
  582.  
  583.     select_fill = DEFAULT_FILL;    /* select default fill */
  584.  
  585.     return;
  586.     }
  587.  
  588. /*--------------------------------------*/
  589.  
  590. void fix_hatch ( void )
  591.     {
  592.     /* don't care if scaling is on or off.  This only affects hatch sizes
  593.     when they are in user units and the scale changes */
  594.  
  595.     /* fill_code [].opt1 is in user units; fill_code [].alt_opt1 is in plotter units */
  596.  
  597.     if (fill_code [HATCH].mode == USERUNITS)
  598.         fill_code [HATCH].alt_opt1 = fill_code [HATCH].opt1 / uu_2_pux;
  599.     if (fill_code [XHATCH].mode == USERUNITS)
  600.         fill_code [XHATCH].alt_opt1 = fill_code [XHATCH].opt1 / uu_2_pux;
  601.     return;
  602.     }
  603.  
  604. /*--------------------------------------*/
  605.  
  606. void fill_type (FILE *infile, int scaling )
  607.     {
  608.     double ftype, opt1, opt2;
  609.     int f1, f2, type;
  610.  
  611.     f1 = f2 = 0;    /* no arguments */
  612.     opt1 = opt2 = 0.0;
  613.     if (get_val (infile, &ftype))
  614.         {
  615.         /* test for invalid type */
  616.         if (ftype < 1.0 || ftype > 11.0 || (ftype > 4.0 && ftype < 10.0))
  617.             {
  618.             while (get_val (infile, &opt1));    /* dump trailing arguments */
  619.             return;
  620.             }
  621.         /* have one value argument */
  622.         if (get_val (infile, &opt1))
  623.             {
  624.             f1 = 1;    /* mark option #1 present */
  625.             if (get_val (infile, &opt2))
  626.                 f2 = 1;    /* mark option #2 present */
  627.             }
  628.         type = (int) ftype;
  629.         type = (type > 4) ? (type - 6) : type - 1;    /* shift range to 0 - 5 */
  630.         }
  631.     else
  632.         {
  633.         select_fill = type = DEFAULT_FILL;    /* no fill-type -> default */
  634.         /* save current fill-type in select_fill */
  635.         fill_code [type].mode = DEFAULTUNITS;
  636.         /* calculate size of units when fill is drawn */
  637.         return;
  638.         }
  639.  
  640.     switch (type)
  641.         {
  642.         case SOLID:    /* solid fill: bidirectional */
  643.         case SOLID1:    /* solid_fill: unidirectional */
  644.  
  645.             select_fill = type;    /* save current fill-type */
  646.             /* no other information required */
  647.             break;
  648.  
  649.         case HATCH:    /* hatched fill */
  650.         case XHATCH:    /* crosshatched fill */
  651.  
  652.             select_fill = type;    /* save current fill-type */
  653.  
  654.             if (f1)        /* option #1 is present */
  655.                 {
  656.                 if (opt1 == 0.0)    /* use default spacing */
  657.                     {
  658.                     fill_code [type].mode = DEFAULTUNITS;
  659.                     /* calculate size of units when fill is drawn */
  660.                     }
  661.                 else
  662.                     {
  663.                     fill_code [type].mode = PLOTTERUNITS;    /* assume plotter units */
  664.                     /* save hatch x-spacing in plotter units */
  665.                     fill_code [type].alt_opt1 = opt1;
  666.  
  667.                     /* don't care about size in user units */
  668.                     if (scaling == ON)
  669.                         {
  670.                         fill_code [type].mode = USERUNITS;    /* correct assumption about units */
  671.                         fill_code [type].opt1 = opt1;    /* user units value */
  672.                         fill_code [type].alt_opt1 = opt1 / uu_2_pux;
  673.                         /* save value of option #1 in plotter units */
  674.  
  675.                         /* we do this because HPGL/2 demands that use units
  676.                         be frozen in equivalent plotter units if scaling is
  677.                         turned off */
  678.                         }
  679.                     }
  680.  
  681.                 /* update angle value only if user supplied */
  682.  
  683.                 if (f2) fill_code [type].opt2 = opt2;
  684.                 }
  685.  
  686.             break;
  687.         case 4: select_fill = type;    /* save current fill-type */
  688.             /* shaded fill:  not yet implimented */
  689.             break;
  690.         case 5: select_fill = type;    /* save current fill-type */
  691.             /* user defined fill: not yet implimented */
  692.             break;
  693.         default: print_string ("FT: Invalid fill type\n"); 
  694.             break;
  695.         }
  696.  
  697.     return;
  698.     }
  699. /*--------------------------------------*/
  700.  
  701. void draw_rect (FILE * infile, int type)
  702.     {    /* type 0 = absolute, type 1 = relative, 0x10 = absolute, filled,
  703.             0x11 = relative, filled */
  704.     double xp, yp, xc, yc, x_sp, theta;
  705.  
  706.     DB ({if (type & FILLED_ABS) printf ("%s\n", (type & 1) ? "RR" : "RA");})
  707.     DB ({if (!(type & FILLED_ABS)) printf ("%s\n", (type & 1) ? "ER" : "EA");})
  708.     where (&xp, &yp);    /* get current position */
  709.     if (get_xy (infile, &xc, &yc))
  710.         {
  711.         /* calculate width and height for rectangle () function */
  712.         if (type & 1)    /* relative rect */
  713.             {
  714.             xc += xp;
  715.             yc += yp;    /* calculate opposite corner pos */
  716.             }
  717.         DB (printf ("Rectangle from (%lf, %lf) to  (%lf, %lf)\n", xp, yp, xc, yc);)
  718.         rectangle (xp, yp, xc, yc);
  719.  
  720.         plotted_on (1);    /* mark plot as dirty */
  721.         if (type & 0x10)
  722.             {
  723.             DB (printf ("filled rectangle: select_fill = %d\n", select_fill);)
  724.             if (select_fill != HATCH && select_fill != XHATCH)
  725.                 {
  726.                 if (select_fill == SOLID || select_fill == SOLID1)
  727.                     {
  728.                     solid_rect ( xp, yp, xc, yc);
  729.                     return;
  730.                     }
  731.                 else
  732.                     return;    /* unsupported fill type */
  733.                 }
  734.             theta = fill_code [select_fill].opt2;    /* theta */
  735.  
  736.             /* get current hatch spacing in plotter units */
  737.             /* for default units, calculate size now */
  738.  
  739.             DB (printf ("rectangle: theta = %lf, fill_code[select_fill].mode = %d\n", \
  740.                 theta, fill_code [select_fill].mode);)
  741.             switch (fill_code [select_fill].mode)
  742.                 {
  743.                 case DEFAULTUNITS:
  744.                     x_sp = 0.01 * sqrt ( (p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
  745.                     break;
  746.                 case PLOTTERUNITS:
  747.                 case USERUNITS:
  748.                     x_sp = fill_code [select_fill].alt_opt1;
  749.                     /* x-spacing is in plotter units */
  750.                     break;
  751.                 default: break;
  752.                 }
  753.  
  754.             if (scaling == ON)    /* convert to plotter units */
  755.                 {
  756.                 plotter_units (&xp, &yp);
  757.                 plotter_units (&xc, &yc);    /* corner coordinates in plotter units */
  758.                 }
  759.             DB (printf ("draw_rect: filled rect: (xp, yp) = (%lf, %lf), (xc, yx) = (%lf, %lf)\n",\
  760.                 xp, yp, xc, yc);)
  761.             fill_rect (xp, yp, xc, yc, x_sp, theta);
  762.             if (select_fill == XHATCH)    /* if cross-hatch, draw crossing hatch at theta + 90 */
  763.                 fill_rect (xp, yp, xc, yc, x_sp, theta + 90.0);
  764.             }
  765.         return;
  766.         }
  767.  
  768.     if (type & 0x10)    /* filled */
  769.         {
  770.         if (type & 1)
  771.             print_string ("ER: missing argument\n");
  772.         else
  773.             print_string ("EA: missing argument\n");
  774.         }
  775.     else
  776.         {
  777.         if (type & 1)
  778.             print_string ("RR: missing argument\n");
  779.         else
  780.             print_string ("RA: missing argument\n");
  781.         }
  782.  
  783.     return;
  784.     }
  785.  
  786. /*--------------------------------------*/
  787.  
  788. static void fill_rect (double x_1, double y_1, double x_2, double y_2, double x_sp, double theta)
  789.     {    /* x_sp, x_1, x_2, y_1, y_2  all in plotter units */
  790.     double ymin, ymax, xmin, xmax;
  791.     double xd1, yd1, xd2, yd2, ac_x, ac_y, x_off, xh;
  792.     double yh, yi, xi, y_off, xlast, ylast, etan, ecot, theta_r;
  793.     int n, sector;
  794.  
  795.     get_anchor (&ac_x, &ac_y);    /* get anchor corner in plotter units */
  796.  
  797.     xmin = x_1;
  798.     ymin = y_1;
  799.     xmax = x_2;
  800.     ymax = y_2;
  801.  
  802.     DB (printf ("hatch_fill: x_sp = %lf, theta = %lf\n", x_sp, theta);)
  803.  
  804.     theta = fmod (theta, 180.0);
  805.     theta_r = theta / RAD_2_DEG;
  806.  
  807.     if (theta < 90.0)
  808.         {        /* sectors 1,5 */
  809.         if (theta < 45.0)
  810.             {
  811.             sector = 1;
  812.             yi = (x_1 - ac_x) * tan (theta_r) + ac_y;
  813.             yh = x_sp / cos (theta_r);    /* this fails at theta = 90 */
  814.  
  815.             y_off = fmod (y_2 - yi, yh);    /* get distance below top edge for starting point */
  816.  
  817.             y_1 = ymax - y_off;
  818.  
  819.             if (y_1 > ymax) y_1 -= yh;    /* check case of yi > y_1 */
  820.             if (y_1 < ymin) y_1 += yh;    /* check case of yi < y_1 */
  821.             y_2 = y_1 + (xmax - xmin) * tan (theta_r);
  822.             }
  823.         else
  824.             {    /* sectors 2, 6 */
  825.             sector = 2;
  826.             xi = (y_1 - ac_y) * cot (theta_r) + ac_x;
  827.             xh = x_sp / sin (theta_r);    /* this fails at theta = 0 */
  828.  
  829.             x_off = fmod (x_2 - xi, xh);    /* get distance inside of right edge for starting point */
  830.  
  831.             x_1 = xmax - x_off;
  832.             if (x_1 > xmax) x_1 -= xh;    /* check case of xi > x_1 */
  833.             if (x_1 < xmin) x_1 += xh;    /* check case of xi < x_1 */
  834.             x_2 = x_1 + (ymax - ymin) * cot (theta_r);
  835.             }
  836.  
  837.         }
  838.     else        /* sectors 4,8 */
  839.         {
  840.         if (theta > 135.0)
  841.             {
  842.             sector = 4;
  843.             yi = (x_2 - ac_x) * tan (theta_r) + ac_y;
  844.             yh = - x_sp / cos (theta_r);    /* this fails at theta = 90 */
  845.  
  846.             /* get distance above bottom edge for starting point */
  847.             y_off = fmod (y_2 - yi, yh);
  848.  
  849.             y_1 = ymax - y_off;
  850.             if (y_1 > ymax) y_1 -= yh;    /* check case of yi > y_1 */
  851.             if (y_1 < ymin) y_1 += yh;    /* check case of yi < y_1 */
  852.             y_2 = y_1 - (xmax - xmin) * tan (theta_r);
  853.             /* tan (theta) < 0 for 90 <= theta < 180 */
  854.  
  855.             xmin = x_2;
  856.             xmax = x_1;
  857.             }
  858.         else
  859.             {    /* sectors 3,7 */
  860.             sector = 3;
  861.             xi = (y_2 - ac_y) * cot (theta_r) + ac_x;
  862.             xh = x_sp / sin (theta_r);    /* this fails at theta = 0 */
  863.  
  864.             x_off = fmod (x_2 - xi, xh);    /* get distance inside of right edge for starting point */
  865.  
  866.             x_1 = xmax - x_off;
  867.  
  868.             if (x_1 > xmax) x_1 -= xh;    /* check case of xi > x_1 */
  869.             if (x_1 < xmin) x_1 += xh;    /* check case of xi < x_1 */
  870.             x_2 = x_1 - (ymax - ymin) * cot (theta_r);
  871.  
  872.             ymax = y_1;
  873.             ymin = y_2;
  874.             }
  875.  
  876.         }
  877.  
  878.  
  879.     if (x_sp == 0.0) return;    /* no point in wasting time */
  880.  
  881.     where (&xlast, &ylast);        /* get current position in current units */
  882.  
  883.     n = 0;        /* emergency break-out counter */
  884.  
  885.     if (sector == 1 || sector == 4)
  886.         {
  887.         etan = tan (theta_r);
  888.         while (y_2 > ymin && n < 2048)    /* this loop only works for 0 <= theta < 90 */
  889.             {
  890.             ++n;
  891.             xd1 = xmin;
  892.             yd1 = y_1;
  893.             xd2 = xmax;
  894.             yd2 = y_2;
  895.  
  896.             if (yd2 > ymax) 
  897.                 {
  898.                 yd2 = ymax;
  899.                 xd2 = xmin + (yd2 - y_1) / etan;
  900.                 }    /* never reach this case if theta == 0 since */
  901.                     /* y_1 == y_2 and y_1 < ymax */
  902.  
  903.             if (yd1 < ymin)
  904.                 {
  905.                 yd1 = ymin;
  906.                 xd1 = xmin + (ymin - y_1) / etan;
  907.                 }    /* never reach this case if theta == 0 since y_2 == y_1 */
  908.                     /* and loop begins with y_1 >= ymin */
  909.  
  910.             if (scaling == ON)    /* convert to user units */
  911.                 {
  912.                 user_units (&xd1, &yd1);
  913.                 user_units (&xd2, &yd2);
  914.                 }
  915.  
  916.             move (xd1, yd1);
  917.             draw (xd2, yd2);
  918.             y_1 -= yh;
  919.             y_2 -= yh;
  920.             }
  921.         }
  922.     else        /* sectors 2, 3 */
  923.         {
  924.         ecot = cot (theta_r);
  925.         while (x_2 > xmin && n < 2048)    /* this loop decrements x sizes */
  926.             {
  927.             ++n;
  928.             xd1 = x_1;
  929.             yd1 = ymin;
  930.             xd2 = x_2;
  931.             yd2 = ymax;
  932.  
  933.             if (xd2 > xmax) 
  934.                 {
  935.                 xd2 = xmax;
  936.                 yd2 = ymin + (xd2 - x_1) / ecot;
  937.                 }    /* never reach this case if theta == 0 since */
  938.                     /* x_1 == x_2 and x_1 < xmax */
  939.  
  940.             if (xd1 < xmin)
  941.                 {
  942.                 xd1 = xmin;
  943.                 yd1 = ymin + (xmin - x_1) / ecot;
  944.                 }    /* never reach this case if theta == 0 since y_2 == y_1 */
  945.                     /* and loop begins with x_1 >= xmin */
  946.  
  947.             if (scaling == ON)    /* revert to user units for drawing */
  948.                 {
  949.                 user_units (&xd1, &yd1);
  950.                 user_units (&xd2, &yd2);
  951.                 }
  952.  
  953.             move (xd1, yd1);
  954.             draw (xd2, yd2);
  955.             x_1 -= xh;
  956.             x_2 -= xh;
  957.             }
  958.         }
  959.  
  960.     move (xlast, ylast);    /* return to original position */
  961.     }
  962.  
  963. /*-------------------------------------*/
  964.  
  965. static void solid_rect (double x_1, double y_1, double x_2, double y_2)
  966.     {    /* draw solid filled rectangles w/o rotation */
  967.     /* passed parameters are in current units */
  968.     int x, y, page, c1, c2;
  969.     struct scrn_pixel__ pix1, pix2;
  970.  
  971.     DB (printf ("solid_fill: from  (%lf,%lf) to (%lf,%lf)\n", x_1, y_1, x_2, y_2);)
  972.  
  973.     /* because there is no filled rectangle in the graphix library, we are
  974.     force to make our own here, and call the line drawing portion of the
  975.     graphix library directly.  That gives the best drawing speed and makes 
  976.     it possible to prevent line overlap at the pixel level.  To do 
  977.     this, we need to know the clip borders in the current units.  We can
  978.     use pmap () to retrieve the pixel coordinates of the rectangle corners.
  979.     The clipping code used here is a modified Cohen-Sutherland coded clipper.
  980.     It returns the clip end-points of a horizontal and a vertical line.  If
  981.     the x or y end-points are both outside the clip border, then the 
  982.     entire rectangle must be outside the clip border, and there is nothing
  983.     to draw. */
  984.  
  985.     page = 0;        /* used by pc_wrt_line (): current graphix page */
  986.  
  987.  
  988.     /* get pixel coordinates */
  989.     pmap (x_1, y_1, (struct scrn_pixel__ _far *) &pix1);
  990.     pmap (x_2, y_2, (struct scrn_pixel__ _far *) &pix2);
  991.  
  992.     pix1.yp = __gr_msc__.max_y_dot - pix1.yp;    /* pmap () returns true pixel coordinates */
  993.     pix2.yp = __gr_msc__.max_y_dot - pix2.yp;    /* map to origin in lower left corner */
  994.  
  995.     DB (printf ("solid_fill: from (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
  996.  
  997.     c1 = code (pix1.xp, pix1.yp);
  998.     c2 = code (pix2.xp, pix1.yp);
  999.  
  1000.     DB (printf ("c1 = %d, c2 = %d\n", c1, c2);)
  1001.  
  1002.     if ( c1 & (4 | 8) )            /* test x-coordinates */
  1003.         {
  1004.         if ( c1 & 0x8 )        /* x_1 < clip_xmin */
  1005.             {
  1006.             if (c2 & 0x8)    /* x_2 < clip_xmin */
  1007.                 return;    /* both x-coords outside clip border */
  1008.             pix1.xp = hpgl_clip.xmin;
  1009.             }
  1010.         else if ( c1 & 0x4 )    /* x_1 > clip_xmax */
  1011.             {
  1012.             if (c2 & 0x04)    /* x_2 > clip_xmax */
  1013.                 return;    /* both x-coords outside clip border */
  1014.             pix1.xp = hpgl_clip.xmax;
  1015.             }
  1016.         }
  1017.  
  1018.     if ( c2 )            /* test 2nd x-coordinate */
  1019.         {
  1020.         if ( c2 & 0x8 )        /* x_2 < clip_xmin */
  1021.             {        /* already tested x_1 */
  1022.             pix2.xp = hpgl_clip.xmin;
  1023.             }
  1024.         else if ( c2 & 0x4 )    /* x_2 > clip_xmax */
  1025.             {        /* already tested x_1 */
  1026.             pix2.xp = hpgl_clip.xmax;
  1027.             }
  1028.         }
  1029.  
  1030.     c1 = code (pix1.xp, pix1.yp);
  1031.     c2 = code (pix1.xp, pix2.yp);
  1032.     DB (printf ("c1 = %d, c2 = %d\n", c1, c2);)
  1033.  
  1034.     if ( c1 & (1 | 2) )
  1035.         {
  1036.         if ( c1 & 0x2 )        /* y_1 < clip_ymin */
  1037.             {
  1038.             if (c2 & 0x2)     /* y_2 < clip_ymin */
  1039.                 return;
  1040.             pix1.yp = hpgl_clip.ymin;
  1041.             }
  1042.         else if ( c1 & 0x1 )    /* y_1 > clip_ymax */
  1043.             {
  1044.             if (c2 & 0x1)    /* y_2 > clip_ymax */
  1045.                 return;
  1046.             pix1.yp = hpgl_clip.ymax;
  1047.             }
  1048.         }
  1049.  
  1050.     if ( c2 )            /* test 2nd y-coordinate */
  1051.         {
  1052.         if ( c2 & 0x2 )        /* y_2 < clip_ymin */
  1053.             {        /* already tested y_1 */
  1054.             pix2.yp = hpgl_clip.ymin;
  1055.             }
  1056.         else if ( c2 & 0x1 )    /* y_2 > clip_ymax */
  1057.             {        /* already tested y_1 */
  1058.             pix2.yp = hpgl_clip.ymax;
  1059.             }
  1060.         }
  1061.  
  1062.     DB (printf ("solid_fill: from (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
  1063.  
  1064.     /* now limit pixel value to screen size */
  1065.     pix1.xp = MIN (__gr_msc__.max_x_dot, ( MAX (0, pix1.xp)));
  1066.     pix1.yp = MIN (__gr_msc__.max_y_dot, ( MAX (0, pix1.yp)));
  1067.     pix2.xp = MIN (__gr_msc__.max_x_dot, ( MAX (0, pix2.xp)));
  1068.     pix2.yp = MIN (__gr_msc__.max_y_dot, ( MAX (0, pix2.yp)));
  1069.  
  1070.     DB (printf ("solid_fill: limited (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
  1071.  
  1072.     if (pix1.yp > pix2.yp)
  1073.         {
  1074.         y = pix1.yp;
  1075.         pix1.yp = pix2.yp;
  1076.         pix2.yp = y;
  1077.         }
  1078.  
  1079.     for (y = pix1.yp; y <= pix2.yp; ++y)    /* draw the solid rectangle */
  1080.         {
  1081.         pc_wrt_line (page, pix1.xp, y, pix2.xp, y, my_pen);
  1082.         }        /* my_pen = internal pen color */
  1083.  
  1084.     return;
  1085.     }
  1086.  
  1087.  
  1088. /*-------------------------------------*/
  1089.  
  1090. /*
  1091.             |      1      |
  1092.             |             |
  1093.     --------+-------------+---------
  1094.             |             |
  1095.        8    |     OK      |    4
  1096.             |             |
  1097.     --------+-------------+---------
  1098.             |             |
  1099.             |      2      |
  1100.  
  1101. */
  1102.  
  1103. static int code (int x, int y)    /* return clipping code */
  1104.     {
  1105.     int clip_code;
  1106.  
  1107.     clip_code = 0;
  1108.  
  1109.     if (x < hpgl_clip.xmin) clip_code = 8;
  1110.     else if (x > hpgl_clip.xmax) clip_code = 4;
  1111.  
  1112.     if (y < hpgl_clip.ymin) clip_code |= 2;
  1113.     else if (y > hpgl_clip.ymax) clip_code |= 1;
  1114.  
  1115.     return (clip_code);
  1116.     }    /* returned code: (x < xmin:x > xmax:y < ymin:y > ymax) */
  1117.  
  1118. /*-------------------------------------*/
  1119.  
  1120. static double cot ( double theta )
  1121.     {    /* valid from 0 to 180 degrees */
  1122.     double a;
  1123.  
  1124.     a = cos (theta);
  1125.     return ( a * sqrt ( 1.0 - a * a));
  1126.     }
  1127.  
  1128. /*--------------------------------------*/
  1129.  
  1130. void chord_t (FILE * infile)
  1131.     {
  1132.     double x;
  1133.  
  1134.     if (get_val (infile, &x))
  1135.         {
  1136.         if (x == 1.0)
  1137.             {
  1138.             chord_type = LENGTH;
  1139.             return;
  1140.             }
  1141.         if (x != 0.0)
  1142.             {
  1143.             print_string ("CT: invalid argument\n");
  1144.             return;
  1145.             }
  1146.         }
  1147.     chord_type = ANG;    /* chord type in degree's */
  1148.     return;
  1149.     }
  1150.  
  1151. /*--------------------------------------*/
  1152.  
  1153. void set_clip (double x_1, double x_2, double y_1, double y_2)
  1154.     {
  1155.     struct scrn_pixel__ pix1, pix2;
  1156.     double px1, px2, py1, py2, tmp;
  1157.  
  1158.     px1 = p1x;
  1159.     px2 = p2x;
  1160.     py1 = p1y;
  1161.     py2 = p2y;
  1162.  
  1163.     DB (printf ("set_clip: clip from (%18.11lf,%18.11lf) to (%18.11lf,%18.11lf)\n", x_1, y_1, x_2, y_2);)
  1164.     DB (printf ("set_clip: hard clip: (p1x, p1y) = (%lf,%lf) to (p2x, p2y) = (%lf,%lf)\n", p1x, p1y, p2x, p2y);)
  1165.  
  1166.     /* check against P1/P2 window */
  1167.     if (scaling == ON)
  1168.         {    /* get user units for "hard clip" border */
  1169.         user_units (&px1, &py1);
  1170.         user_units (&px2, &py2);
  1171.         }
  1172.  
  1173.     /* limit clipping border to P1/P2 border */
  1174.     /* this will prevent drawing outside the P1/P2 border when */
  1175.     /* P1/P2 < paper size and clipping window > P1/P2 border */
  1176.     /* exchange x_1, x_2 and y_1, y_2 if P1/P2 exchanged */
  1177.  
  1178.     if (p1x < p2x)
  1179.         {
  1180.         x_1 = MAX (px1, x_1);
  1181.         x_2 = MIN (px2, x_2);
  1182.         }
  1183.     else    /* P1/P2 exchanged */
  1184.         {
  1185.         tmp = MAX (px2, x_2);
  1186.         x_2 = MIN (px1, x_1);
  1187.         x_1 = tmp;
  1188.         }
  1189.  
  1190.     if (p1y < p2y)
  1191.         {
  1192.         y_1 = MAX (py1, y_1);
  1193.         y_2 = MIN (py2, y_2);
  1194.         }
  1195.     else    /* P1/P2 exchanged */
  1196.         {
  1197.         tmp = MAX (py2, y_2);
  1198.         y_2 = MIN (py1, y_1);
  1199.         y_1 = tmp;
  1200.         }
  1201.  
  1202.     DB (printf ("set_clip: clip from (%lf,%lf) to (%lf,%lf)\n", x_1, y_1, x_2, y_2);)
  1203.     clip (x_1, x_2, y_1, y_2);    /* clipping limited to P1/P2 window */
  1204.  
  1205.     /* get pixel coordinates */
  1206.     pmap (x_1, y_1, (struct scrn_pixel__ _far *) &pix1);
  1207.     pmap (x_2, y_2, (struct scrn_pixel__ _far *) &pix2);
  1208.  
  1209.     DB (printf ("set_clip: from (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
  1210.  
  1211.     /* now limit pixel value to screen size */
  1212.     pix1.xp = MIN (__gr_msc__.max_x_dot, ( MAX (0, pix1.xp)));
  1213.     pix1.yp = MIN (__gr_msc__.max_y_dot, ( MAX (0, pix1.yp)));
  1214.     pix2.xp = MIN (__gr_msc__.max_x_dot, ( MAX (0, pix2.xp)));
  1215.     pix2.yp = MIN (__gr_msc__.max_y_dot, ( MAX (0, pix2.yp)));
  1216.  
  1217.     DB (printf ("set_clip: from (pixel) (%d,%d) to (%d,%d)\n", pix1.xp, pix1.yp, pix2.xp, pix2.yp);)
  1218.  
  1219.     hpgl_clip.xmin = pix1.xp;
  1220.     hpgl_clip.xmax = pix2.xp;
  1221.  
  1222.     hpgl_clip.ymin = __gr_msc__.max_y_dot - pix1.yp;
  1223.     hpgl_clip.ymax = __gr_msc__.max_y_dot - pix2.yp;    /* compensate for origin in LL corner */
  1224.     /* save clip border in pixels for solid_fill () */
  1225.  
  1226.     DB (printf ("set_clip: hardclip (pixel) (%d,%d) to (%d,%d)\n", hpgl_clip.xmin, hpgl_clip.ymin, hpgl_clip.xmax, hpgl_clip.ymax);)
  1227.  
  1228.     return;
  1229.     }
  1230.  
  1231. /*--------------------------------------*/
  1232.