home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / progm / pcgraphc.zip / GRAPHX.C < prev    next >
C/C++ Source or Header  |  1988-12-26  |  46KB  |  1,540 lines

  1.  
  2. /* graphics library for the C language:
  3. This set of routines is designed to replicate the Hewlett-Packard 
  4. 9845 BASIC graphics routine.  The current implimentation uses naming
  5. conventions from the HP9845 series computers (i.e., LOCATE and SCALE),
  6. but incorporates some of the features of HP Technical BASIC 5.0 (such as
  7. PIVOT, RMOVE, RPLOT, RDRAW).  This is not a complete implimentation, as
  8. several functions (such as CURSOR, DIGITIZE, POINTER, PLOTTER IS, AXES,
  9. LINETYPE, and GRID are either not completely implimented for hardware
  10. reasons, or are not implimented at all. */
  11.  
  12. /*
  13. Copyright 1988, Lantern Systems
  14. */
  15.  
  16. /* to start debugging, enter this line:  #define debug 1   */
  17.  
  18. /* headers and definitions for this code */
  19. #include "gr_lib.h"
  20. #include <stdarg.h>
  21. #include <stdio.h>
  22. #include <math.h>
  23. #include <dos.h>
  24.  
  25. #define        MAX(x,y)    (((x) < (y)) ? (y) : (x))
  26. #define        MIN(x,y)    (((x) < (y)) ? (x) : (y))
  27. #define        isprint(x)    ((*char_$_p[x]) == -1) ? 0 : 1
  28.  
  29.  
  30. union REGS regs;    /* register definitions for DOS interrupts */
  31.  
  32.  
  33. static char copyright[] =  "copyright 1988, Lantern Systems";
  34.  
  35.  
  36. extern int *char_$_v[];
  37. extern char *char_$_p[];
  38.  
  39. static int xpos, ypos, max_x_dot, max_y_dot, clp[4][2], locat[4],
  40.     units, clip_type, clip_store, pivot_x, pivot_y;
  41.  
  42. int degree, pendown;
  43.  
  44. static int x_inc, y_inc, l_org, l_type, rpos_x, rpos_y;
  45. static unsigned char video_mode;
  46.  
  47. double X_mm, Y_mm;
  48.  
  49. static double tilt, a_ratio, c_size, l_cos, l_sin, x_gdu, y_gdu,
  50.     p_cos, p_sin, x_factor, y_factor, x_offset, y_offset, ratio_,
  51.     c_scale, ar_scale, def_csize, pivot_sin, pivot_cos;
  52.  
  53. static double gdu_limit_mms, x_ppm, y_ppm, limit_xmin, limit_ymin;
  54.  
  55. static double pix_p_gdu_x, pix_p_gdu_y, gdu_inc, l_rpt;
  56.  
  57. static double l_1[] = { 0 };        /* solid line */
  58. static int    l_1p[] = { 0 };
  59. static double l_2[] = { 0 };        /* dot at end points, only */
  60. static int    l_2p[] = { 0 };
  61. static double l_3[] = { 0, 0, 5.0 };    /* dot every 5 gdu's */
  62. static int    l_3p[] = { 1, -1, 0 };
  63. static double l_4[] = { 0, 0, 2 };    /* dot every 2 gdu's */
  64. static int    l_4p[] = { 1, -1, 0 };
  65. static double l_5[] = {  3, 5 };
  66. static int    l_5p[] = { 1, 0 };        /* 3 gdu dash, 2 gdu space */
  67. static double l_6[] = { 3.4, 4.1, 4.3, 5 };
  68. static int    l_6p[] = { 1, 0, 1, 0 };    /* 3.4 gdu dash, .7 gdu space, .2 gdu dash, .7 gdu space */
  69. static double l_7[] = { 2.9, 3.6, 4.3, 5 };
  70. static int    l_7p[] = { 1, 0, 1, 0 };    /* 2.9 gdu dash, .7 gdu space, .7 gdu dash, .7 gdu space */
  71. static double l_8[] = { 0.5, 1.0, 1.5, 2, 4.5, 5.0 };
  72. static int    l_8p[] = { 1, 0, 1, 0, 1, 0 };
  73. static double l_9[] = { 5 };    /* solid w/ 1 gdu tick at end of segment */
  74. static int    l_9p[] = { 1 };
  75. static double l_10[] = { 5 };    /* solid w/ 2 gdu tick at end of segment */
  76. static int    l_10p[] = { 1 };
  77.  
  78. static double *line_types[] = { l_1, l_2, l_3, l_4, l_5, l_6, l_7, l_8,
  79.     l_9, l_10 };
  80.  
  81. static int *line_penc[] = { l_1p, l_2p, l_3p, l_4p, l_5p, l_6p, l_7p, l_8p,
  82.     l_9p, l_10p };
  83.  
  84. static int line_pat[] = { 0, 0, 3, 3, 2, 4, 4, 6, 1, 1 };
  85. static int pat_ptr, pix_cnt, pen_c[10], pen_px[10], pen_py[10], pat_length;
  86. static int pix_max, pen_stat, Pen;
  87.  
  88. va_list arg_ptr;
  89.  
  90. /*__________________________________________________*/
  91.  
  92. /* variable usage:
  93.  
  94. pendown: Used to record the current pen status (up or down). 1 => pen is down
  95.  
  96. xpos, ypos:  Current x & y position on screen (pixel coordinates)
  97.  
  98. max_x_dot, max_y_dot:  maximum pixel position for selected video mode
  99.  
  100. locat[0]:  xmin \
  101. locat[1]:  xmax  | define a viewport within the hardclip limits (in mm's)
  102. locat[2]:  ymin  |
  103. locat[3]:  ymax /
  104.  
  105. Ordinarily, the locate size would be kept in pixels.  However, because of
  106. the unequal pixel density in the x- and y-directions of the PC screens, it
  107. is necessary to keep the locate area size in mm's so that the aspect ratio
  108. of the viewing area is preserved and isotropic scaling (show) functions
  109. correctly.
  110.  
  111. clp[0][0]: xmin \
  112. clp[1][0]: xmax  | define the hard clip boundary (in pixel coordinates).
  113. clp[2][0]: ymin  | default is the physical screen size in pixels.
  114. clp[3][0]: ymax /
  115.  
  116. clp[0][1]: xmin \
  117. clp[1][1]: xmax  | define the soft clip boundary (in pixel coordinates).
  118. clp[2][1]: ymin  | default is the locate viewport size in pixels whenever
  119. clp[3][1]: ymax /  locate () is issued.  Same as hard clip at g_init ().
  120.  
  121. degree: select degree or radian mode.  degree = 1 => degree mode.
  122.  
  123. Pen:  Select the pen # (various colors on a color crt or plotter)
  124.  
  125. x_inc, y_inc: x & y basic sizes of stroke characters (in gdu's)
  126.  
  127. l_org:  label origin (0 - 9)
  128.  
  129. l_type: line type (1 - 10)
  130.  
  131. l_rpt:  repeat length (in gdu's) for non-solid line patterns
  132.  
  133. rpos_x, rpos_y: reference x, y position (in pixel coordinates) for relative
  134.     motion plotting, moving, and drawing.
  135.  
  136. X_mm, Y_mm: CRT plotting area in mm.  User must set these in gpr.h for his
  137.     particular screen size.
  138.  
  139. tilt: tan(tilt) used to tilt stroke characters (in current angle units)
  140.  
  141. a_ratio: aspect ratio of label characters.
  142.  
  143. c_size: scale factor for label char's.
  144.  
  145. l_cos, l_sin: cosine and sine of label direction (for rotation of labels)
  146.  
  147. p_cos, p_sin: cosine and sine of plotting direction (for relative and
  148.     incremental motion)
  149.  
  150. x_factor, y_factor: scale factors for x-axis and y-axis plotting (in
  151.     pixels/user_unit).  Set by scale (), show (), and mscale ().
  152.  
  153. x_offset, y_offset:  x-value and y-value for left edge and bottom edge,
  154.     respectively, of locate viewport.  Set by scale (), show (), and
  155.     mscale ().
  156.  
  157. ratio_: aspect ratio of hardclip area (pixels/pixel)
  158.  
  159. c_scale: scale factor for external csize () to internal c_size.
  160.  
  161. ar_scale: scale factor for external char aspect ratio to internal
  162.     character a_ratio.
  163.  
  164. def_csize: default c_size if externally specified value is 0.
  165.  
  166. clip_type: current clipping limits (0 = hardclip, 1 = softclip)
  167.  
  168. clip_store: storage for current clipping type (used when drawing
  169.     characters which only obey the hardclip limits)
  170.  
  171. x_ppm, y_ppm: # pixels/mm of the selected screen mode 
  172.  
  173. gdu_limit_mms: # mm's along the longest axis of the limit area
  174.  
  175. limit_xmin, limit_ymin: the lower left corner coordinates of the limit
  176.     area in mm's.  This location is required in order to calculate
  177.     the locat[] coordinates in mm's from the user supplied input
  178.     which is in gdu's
  179.  
  180. */
  181.  
  182.  
  183. /*__________________________________________________*/
  184.  
  185. void labelf (fmt) char *fmt;
  186.     {
  187.     /* this routine accepts strings and formatted output for labeling.  It
  188.     controls centering and positioning of the string exactly as does the
  189.     HP labeling software on the 9845 and series 200 and 300 computers.
  190.     Due to the embedding of control characters (i.e., <cr><lf> pairs in
  191.     the text, labelf() will have to scan for and capture them to get the
  192.     correct string length for centering and justifying.
  193.  
  194.     tan(slant), aspect ratio, character size, cos(label_dir), sin(label_dir),
  195.     x_pos, y_pos mark the starting point for the string
  196.     x_inc, y_inc are the x-step between characters and the
  197.     y-step between lines. They are scaled by c_size and a_ratio.
  198.  
  199.     labelf() and draw_c() routines.
  200.     labelf() functions exactly as printf except for drawing onto the graphics
  201.     screen with graphic characters.
  202.  
  203.     draw_c() is the routine which calls drawline() and actually draws the
  204.     graphic characters.
  205.  
  206.     draw_c() calls drawline(); drawline() calls putdot(). */
  207.  
  208.  
  209.     int save_clip, p_char, t_char, xp, yp;
  210.     char *start, *idx, pr_str[512], cur_char;
  211.  
  212.     save_clip = clip_type;    /* save current clipping type */
  213.     clip_type = 0;        /* turn off soft clipping */
  214.  
  215.     va_start (arg_ptr, fmt);
  216.     t_char = vsprintf ( pr_str, fmt, arg_ptr ); /* print to string */
  217.     if ((t_char > 512) || (t_char < 0))    /* check for overflow or error */
  218.         {
  219.         fprintf (stderr,"?(label) - string length violation\n");
  220.         exit(1);
  221.         }
  222.     va_end (arg_ptr);
  223.  
  224. #ifdef debug
  225.  
  226. printf ("(labelf): pr_str = %s\n", pr_str);
  227.  
  228. #endif
  229.  
  230.     start = idx = pr_str;    /* initialize string pointers */
  231.     t_char = p_char = 0;    /* t_char = total # chars, p_char = # printing chars */
  232.     xp = xpos;        /* save starting position for after a <cr> if any */
  233.     yp = ypos;
  234.  
  235.     pendown = 1;    /* drop pen to draw */
  236.     while ((cur_char = *idx) != '\0')    /* scan string for <cr>'s */
  237.         {
  238.         ++t_char;
  239.         if (isprint (cur_char)) ++p_char;
  240.         ++idx;            /* point to next char */
  241.         if (cur_char == '\n')
  242.             {
  243. #ifdef debug
  244. printf ("(labelf): # char = %d, # printing chars = %d\n", t_char, p_char);
  245. #endif
  246.             write_char (start, t_char, p_char);    /* label substring */
  247.             start = idx;        /* skip '\n' for next line (if any) */
  248.             p_char = 0;        /* reset printing char count */
  249.             t_char = 0;        /* reset total # of chars in substring */
  250.             /* return to start of label */
  251.             xpos = xp += (int) ((double) y_inc * c_size * x_gdu * l_sin * x_ppm);
  252.             ypos = yp -= (int) ((double) y_inc * c_size * x_gdu * l_cos * y_ppm);
  253.             /* new pen position after \n with l_dir rotation */
  254.             }
  255.         }
  256.         /* catch strings which don't end with a <cr> */
  257.     if (p_char > 0) write_char (start, t_char, p_char);
  258.  
  259.     clip_type = save_clip; /* resume previous clipping after labeling */
  260.  
  261.     pendown = 0;    /* lift pen at end of label */
  262.  
  263.     return;
  264.     }
  265.  
  266. /*____________________________________________________*/
  267. /* routine for labeling strings */
  268.  
  269. void write_char (start, t_char, p_char) char *start; int t_char, p_char;
  270.     {
  271.     int i;
  272.     double l_str;
  273.  
  274.     l_str = p_char * ((double) (x_inc) * x_gdu * c_size * a_ratio);
  275.     /* length of char string in pixels */
  276.  
  277.     /* left justified requires no action */
  278.     if ((l_org < 7) && (l_org > 3))
  279.         {
  280.         xpos = xpos - (int) (l_str * x_ppm * l_cos / 2);    /* centered */
  281.         ypos = ypos - (int) (l_str * y_ppm * l_sin / 2);
  282.         }
  283.     else if (l_org>=7)
  284.         {
  285.         xpos = xpos - (int) (l_str * x_ppm * l_cos);         /* right justified */
  286.         ypos = ypos - (int) (l_str * y_ppm * l_sin);
  287.         }
  288.     switch ( l_org )
  289.         {
  290.         case 0:
  291.         case 1: 
  292.         case 4:
  293.         case 7:break;    /* bottom justified */
  294.         case 2:
  295.         case 5:
  296.         case 8: ypos = ypos - (int) ((double)(y_inc) * c_size * y_gdu * y_ppm * l_cos / 2); /* centered */
  297.             xpos = xpos + (int) ((double)(y_inc) * c_size * x_gdu * x_ppm * l_sin / 2);
  298.             break;
  299.         case 3:
  300.         case 6:
  301.         case 9: ypos = ypos - (int) ((double)(y_inc) * c_size * y_gdu * y_ppm * l_cos);   /* top justified */
  302.             xpos = xpos + (int) ((double)(y_inc) * c_size * y_gdu * x_ppm * l_sin);
  303.         default:break;
  304.         }
  305.     for (i = 0; i < t_char; ++i)
  306.         {
  307.         if (isprint (*start)) draw_c (*start);
  308.         ++start;
  309.         }
  310.     return;
  311.     }
  312.  
  313. /*____________________________________________________*/
  314.  
  315.  
  316. void draw_c (c) char c;
  317.     {
  318.  
  319.     /* graphics_tbl[] is a table of pointers the the (x,y) pairs which
  320.     make up the characters.  pen_tbl[] is a table of pointer to the
  321.     pen control character.  0xff is the end of the table for a particular
  322.     character. */
  323.  
  324.     /* xpos,ypos are screen pixel coordinates (integer). */
  325.  
  326.     int *start_char, x1, y1, x3, y3, x4, y4;
  327.     double x2, y2, ival_x, ival_y;
  328.     char pen_c, *start_pen;
  329.  
  330.     double x_f, y_f;
  331.  
  332. #ifdef debug
  333. printf ("(draw_c):char code: %xh, char = %c\n",c,c);
  334. #endif
  335.  
  336.     start_char = char_$_v[c];    /* pointer to first (x,y) (in pixels) */
  337.     start_pen = char_$_p[c];    /* pointer to first pen control */
  338.  
  339.         x_f = c_size * a_ratio * gdu_limit_mms / 100;    /* units are mm's/gdu */
  340.         y_f = c_size * gdu_limit_mms / 100;
  341.  
  342.     /* # mm's / gdu:100 gdu's = y-size of limit area */
  343.  
  344.             /* (x,y) are origin of character */
  345.     x3 = xpos;
  346.     y3 = ypos;    /* all characters start at relative origin (0,0) */
  347.  
  348.     do
  349.         {
  350.  
  351.         /* rotate starting coordinates to ldir() angle */
  352.  
  353.         x1 = x3;
  354.         y1 = y3;    /* start (x,y) for line */
  355.  
  356. #ifdef debug
  357. printf ("(draw_c): x1 = %d y1 = %d\n", x1, y1);
  358. #endif
  359.         pen_c = *(start_pen++);
  360.  
  361.         /* scale size  of char and aspect ratio to gdu's */
  362.         /* the order of these statements is important!!! */
  363.  
  364.         x2 = ((double) (*(start_char ++))) * x_f;
  365.  
  366. #ifdef debug
  367. printf ("(draw_c): char_y_pos = %d\n", *start_char);
  368. #endif
  369.  
  370.         y2 = ((double) (*(start_char++))) * y_f;
  371.         x2 = x2 +  y2 * tilt;    /* add tilt to characters */
  372.  
  373.         /* stop (x,y) for character after rotation: scale for different
  374.         X and Y pixel densities */
  375.         ival_x = (x2 * l_cos - y2 * l_sin) * x_ppm;
  376.         ival_y = (y2 * l_cos + x2 * l_sin) * y_ppm;
  377.          /* rotation of coordinates for ldir() */
  378.         x4 = (ival_x > 0) ? (int) (ival_x + 0.5) : (int) (ival_x -0.5);
  379.         y4 = (ival_y > 0) ? (int) (ival_y + 0.5) : (int) (ival_y -0.5);
  380.         x3 = x4 + xpos;
  381.         y3 = y4 + ypos;
  382.  
  383. #ifdef debug
  384. printf ("(draw_c): x3: %d, y3: %d\n", x3, y3 );
  385. #endif
  386.  
  387.         if ((pen_c & 1) != 0) drawline ( x1, y1, x3, y3 );
  388.         }
  389.     while (pen_c >= 0);
  390.     /* calculate new pen position based upon c_size, a_ratio, and ldir */
  391.     /* new position for lateral x-motion only */
  392.     xpos = xpos + (int) ((double) (x_inc) * a_ratio * l_cos * y_f * x_ppm);
  393.     ypos = ypos + (int) ((double) (x_inc) * a_ratio * l_sin * y_f * y_ppm);
  394.     return;
  395.     }
  396.  
  397. /*---------------------------------------------------*/
  398.  
  399. void csize (height, a_r, slant) double height, a_r, slant;
  400.     {
  401.     /* csize (size (default = 4), aspect ratio (default = 0.6), slant (default = 0)) */
  402.  
  403.     a_ratio = ((a_r != 0.0) ? fabs (a_r * ar_scale) : 0.6 * ar_scale );
  404.     tilt = tan ( ((degree != 0) ? slant / 57.2958 : slant) );
  405.     c_size = ((height != 0) ? fabs (height / c_scale) : def_csize );
  406.  
  407.     /* units are GDU's: default is 4.0   c_scale changes the height
  408.     to reflect higher res screens. */
  409.     return;
  410.     }
  411.  
  412. /*---------------------------------------------------*/
  413.  
  414. void lorg (x) int x;
  415.     {
  416.     /* select label origin (0 - 9) */
  417.     l_org = MAX (MIN(9,abs(x)), 1);
  418.     return;
  419.     }
  420.  
  421. /*---------------------------------------------------*/
  422.  
  423. double ratio()
  424.     {
  425.     /* get hardclip aspect ratio */
  426.     return ((double) (clp[1][0] - clp[0][0]) / (double) (clp[3][0] - clp[2][0]));
  427.     }
  428.  
  429. /*---------------------------------------------------*/
  430. void ldir (angle) double angle;
  431.     {
  432.     if (degree == 1) angle = angle / 57.2958;    /* convert to radians */
  433.     l_cos = cos (angle);
  434.     l_sin = sin (angle);    /* rotation of labels */
  435.     return;
  436.     }
  437.  
  438. /*---------------------------------------------------*/
  439.  
  440. void line_type (type, repeat) int type; double repeat;
  441.     {
  442.     /* line_type (type, repeat (default = 5 GDU's)) */
  443.  
  444.     int i;
  445.  
  446.     l_type = MIN (MAX (abs (type), 1),10);
  447.     l_rpt = MAX ( (fabs ( repeat ) / 5),1);
  448.     pat_ptr = 0;    /* reset pattern pointer */
  449.     pix_cnt = 0;    /* reset pixel counter */
  450.     pen_c[0] = 1;    /* pen control for zero length patterns */
  451.     pen_px[0] = 32767; /* make pattern length arbritrarily long for solid lines */
  452.     pen_py[0] = 32767;
  453.     pat_length = line_pat [ l_type -1 ];
  454.  
  455. #ifdef debug
  456. printf ("(line_type): pat_length = %d\n",pat_length);
  457. #endif
  458.  
  459.     for (i = 0; i < pat_length; ++i)
  460.         {
  461.         switch ( line_penc[ l_type - 1 ][i])
  462.             {
  463.             case -1: /* dot at pattern count */
  464.             pen_c[i] = 1;    /* pen down */
  465.             pen_px[i] = pen_px[i - 1] + 1;
  466.             pen_py[i] = pen_py[i - 1] + 1;
  467.             break;
  468.  
  469.             case 0: /* pen up */
  470.             pen_c[i] = 0;
  471.             pen_px[i] = (int) line_types[ l_type - 1][ i ] * x_gdu * x_ppm * l_rpt;
  472.             pen_py[i] = (int) line_types[ l_type - 1][ i ] * x_gdu * y_ppm * l_rpt;
  473.             break;
  474.  
  475.             case 1: /* pen down */
  476.             pen_c[i] = 1;
  477.             pen_px[i] = (int) line_types[ l_type - 1][ i ] * x_gdu * x_ppm * l_rpt;
  478.             pen_py[i] = (int) line_types[ l_type - 1][ i ] * x_gdu * y_ppm * l_rpt;
  479.             break;
  480.             }
  481.  
  482. #ifdef debug
  483. printf ("(line_type): line_penc[ l_type - 1 ][i] = %d\n", line_penc[l_type - 1][i]);
  484. printf ("(line_type): i = %d, pen_c[i] = %d, pen_py[i] = %d\n",i, pen_c[i], pen_py[i]);
  485. #endif
  486.  
  487.         }
  488.  
  489.     return;
  490.     }
  491.  
  492. /*---------------------------------------------------*/
  493.  
  494. void pen (p) int p;
  495.     {
  496.     Pen = p;
  497.     return;
  498.     }
  499.  
  500. /*---------------------------------------------------*/
  501.  
  502. void penup ()
  503.     {
  504.     pendown = 0;    /* mark pen as up */
  505.     return;
  506.     }
  507.  
  508. /*---------------------------------------------------*/
  509.  
  510. void deg ()
  511.     {
  512.     degree = 1;
  513.     return;
  514.     }
  515.  
  516. /*---------------------------------------------------*/
  517.  
  518. void rad ()
  519.     {
  520.     degree = 0;
  521.     return;
  522.     }
  523.  
  524. /*---------------------------------------------------*/
  525.  
  526. /* only graphics_off () is implimented.  Switching from alpha to graphics
  527. screens clears the graphics screen */
  528.  
  529. void graphics_off ()
  530.     {
  531.     regs.h.ah = SET_MODE;
  532.     regs.h.al = video_mode;        /* return to original video mode */
  533.     int86 (VIDEO, ®s, ®s);
  534.     }
  535.  
  536. /*---------------------------------------------------*/
  537.  
  538. void g_init (mode) int mode;
  539.     {
  540.     /* select graphics mode for drawing.
  541.     modes are
  542.     1: 320x200 CGA 4 color; 2: 640x200 CGA 2 color; 3: 640x400 AT&T 2 color; 
  543.     4: 320x200 EGA 16 color; 5: 640x200 EGA 16 color;
  544.     6: 640x350 EGA 16 color; 7: 640x480 VGA 16 color;
  545.     8: 320x200 VGS 256 color */
  546.  
  547.     clp[0][0] = 0;    /* set hard clip lower limits */
  548.     clp[2][0] = 0;    /* to the same boundary */
  549.  
  550.     def_csize = c_size = 0.5;    /* scale & size char's for */
  551.     c_scale = 8.0;        /* Initial internal c_size. Default external csize = 4 */
  552.     a_ratio = 1.0;        /* initial internal aspect ratio for characters is 1.0 */
  553.     ar_scale = 1.666;    /* aspect ratio scaling for char's */
  554.  
  555.     regs.h.ah = VIDEO_STATE;    /* Read current video mode */
  556.     int86 (VIDEO, ®s, ®s);
  557.     video_mode = regs.h.al;        /* current video mode */
  558.  
  559.     switch (mode)
  560.         {
  561.         case 1:
  562.             clp[1][0] = 319;    /* low res screen */
  563.             clp[3][0] = 199;
  564.             regs.h.ah = SET_MODE;
  565.             regs.h.al = CGA_MED;
  566.             int86 (VIDEO, ®s, ®s);
  567.             break;
  568.         case 2:
  569.             clp[1][0] = 639;    /* med res screen */
  570.             clp[3][0] = 199;
  571.             regs.h.ah = SET_MODE;
  572.             regs.h.al = CGA_HIGH;
  573.             int86 (VIDEO, ®s, ®s);
  574.             break;
  575.         case 3:
  576.             clp[1][0] = 639;    /* high res screen */
  577.             clp[3][0] = 399;
  578.             regs.h.ah = SET_MODE;
  579.             regs.h.al = ATT_HIRES;
  580.             int86 (VIDEO, ®s, ®s);
  581.             /* mode 72 also available (tiny text) */
  582.             break;
  583.         case 4:
  584.             clp[1][0] = 319;    /* 16 color EGA screen */
  585.             clp[3][0] = 199;
  586.             regs.h.ah = SET_MODE;
  587.             regs.h.al = EGA_LORES;
  588.             int86 (VIDEO, ®s, ®s);
  589.             break;
  590.         case 5:
  591.             clp[1][0] = 639;    /* 16 color EGA screen */
  592.             clp[3][0] = 199;
  593.             regs.h.ah = SET_MODE;
  594.             regs.h.al = EGA_MEDRES;
  595.             int86 (VIDEO, ®s, ®s);
  596.             break;
  597.         case 6:
  598.             clp[1][0] = 639;    /* 16 color EGA screen */
  599.             clp[3][0] = 349;
  600.             regs.h.ah = SET_MODE;
  601.             regs.h.al = EGA_HIRES;
  602.             int86 (VIDEO, ®s, ®s);
  603.             break;
  604.         case 7:
  605.             clp[1][0] = 639;    /* 16 color VGA screen */
  606.             clp[3][0] = 479;
  607.             regs.h.ah = SET_MODE;
  608.             regs.h.al = VGA_HIRES;
  609.             int86 (VIDEO, ®s, ®s);
  610.             break;
  611.         case 8:
  612.             clp[1][0] = 319;    /* 256 color VGA screen */
  613.             clp[3][0] = 199;
  614.             regs.h.ah = SET_MODE;
  615.             regs.h.al = VGA_LORES;
  616.             int86 (VIDEO, ®s, ®s);
  617.             break;
  618.         default:
  619.             printf ("\nIllegal graphics mode\n");
  620.             exit(1);
  621.         }
  622.  
  623.     deg ();        /* set mode to degrees */
  624.     clip_store = 0;    /* set clipping save buffer to hard clipping */
  625.     clip_type = 0;    /* hard clipping on */
  626.     units = 0;    /* select GDU's */
  627.     x_inc = 9;    /* basic char. x-size is 9 gdu's */
  628.     y_inc = 15;    /* basic char. y-size is 15 gdu's */
  629.     l_org = 1;    /* label origin is 1 */
  630.     line_type (1,0);/* set initial line type to 1 */
  631.     l_cos = 1.0;    /* label direction rotation */
  632.     l_sin = 0;
  633.     tilt = 0.0;    /* tilt of characters */
  634.     rpos_x = xpos = 0;    /* initial x,y position on screen */
  635.     rpos_y = ypos = 0;    /* (in pixels) */
  636.     p_cos = 1.0;    /* plotting direction rotation */
  637.     p_sin = 0.0;
  638.     Pen = 1;    /* select pen #1 as the default pen. */
  639.     pendown = 0;    /* mark pen as up */
  640.     limit_xmin = 0;
  641.     limit_ymin = 0;    /* hardclip limit lower left corner (in pixels) */
  642.  
  643.     /* set soft clip limits to hard clip limits and default locate limits
  644.     to hard clip limits.  Adjust max_dot to reflect current mode. 
  645.     max_x_dot and max_y_dot are max screen size in pixels. */
  646.  
  647.     locat[0] = limit_xmin;
  648.     locat[2] = limit_ymin;
  649.     locat[1] = X_mm;
  650.     locat[3] = Y_mm;    /* set locate limits to screen limits */
  651.     clp[0][1] = clp[0][0];
  652.     max_x_dot = clp[1][1] = clp[1][0];
  653.     clp[2][1] = clp[2][0];
  654.     max_y_dot = clp[3][1] = clp[3][0];
  655.  
  656.     x_ppm = max_x_dot / X_mm;
  657.     y_ppm = max_y_dot / Y_mm;    /* pixels / mm */
  658.  
  659.     ratio_ = X_mm / Y_mm;
  660.  
  661.     if (ratio_ >= 1.0)    /* y gdu's = 100 */
  662.         gdu_limit_mms = Y_mm;
  663.     else            /* x gdu's = 100 */
  664.         gdu_limit_mms = X_mm;
  665.  
  666.     /* set the startup x_gdu and y_gdu values.  These change when the hard
  667.     clip limits are changed.  Normally, the screen aspect ratio is defined
  668.     as (max_x - min_x) / (max_y - min_y). */
  669.  
  670.     x_gdu = y_gdu = gdu_limit_mms / 100;    /* mm's / gdu */
  671.  
  672.     x_factor = x_gdu * x_ppm;
  673.     y_factor = y_gdu * y_ppm;    /* default scaling (needed by clip() */
  674.     x_offset = y_offset = 0;    /* mscale, scale, and show change these */
  675.  
  676. #ifdef debug
  677. printf ("x_gdu = %lf, y_gdu = %lf\nx_factor = %lf, x_offset = %lf\n", x_gdu, y_gdu, x_factor, x_offset );
  678. #endif
  679.  
  680.     return;
  681.     }
  682.  
  683. /*----------------------------------------------------*/
  684.  
  685. void limit (xmin, xmax, ymin, ymax) double xmin, xmax, ymin, ymax;
  686.     {
  687.  
  688.     /* The limits are defined to be in mm from the origin of the plotting
  689.     device.  These are hard clip limits which are used to redefine the
  690.     size of the screen. */
  691.  
  692.     /* units are in mm's from the lower left corner of the crt */
  693.  
  694.     if (xmin < 0 || xmax < 0 || ymin < 0 || ymax < 0)
  695.         {
  696.         fprintf (stderr, "? (limit) - parameter out of range.");
  697.         exit (1);
  698.         }
  699.  
  700.     locat[0] = limit_xmin = xmin;
  701.     locat[1] = xmax;
  702.     locat[2] = limit_ymin = ymin;    /* new lower left corner in mm's */
  703.     locat[3] = ymax;
  704.  
  705.     pivot_x = locat[0];
  706.     pivot_y = locat[2];
  707.     pivot_cos = 1.0;
  708.     pivot_sin = 0.0;    /* clear existing pivot (if any) */
  709.  
  710.     clp[0][1] = clp[0][0] = MIN (((int) (xmin * (double) (max_x_dot) / X_mm)), max_x_dot);
  711.     clp[1][1] = clp[1][0] = MIN (((int) (xmax * (double) (max_x_dot) / X_mm)), max_x_dot);
  712.     clp[2][1] = clp[2][0] = MIN (((int) (ymin * (double) (max_y_dot) / Y_mm)), max_y_dot);
  713.     clp[3][1] = clp[3][0] = MIN (((int) (ymax * (double) (max_y_dot) / Y_mm)), max_y_dot);
  714.  
  715.     /* set the screen aspect ratio for the new hard clip limits 
  716.     and set the soft clip limits to the new hard clip limits */
  717.  
  718. #ifdef debug
  719. printf ("(limit): screen size X_mm = %lf, Y_mm = %lf\n", X_mm, Y_mm);
  720. printf ("(limit): clip (min) (X,Y) = (%d, %d), (max) (X,Y) = (%d, %d)\n", clp[0][0], clp[2][0], clp[1][0], clp[3][0] );
  721. #endif
  722.  
  723.     ratio_ = (xmax - xmin) / (ymax - ymin);    /* set ratio by screen size */
  724.  
  725.     if (ratio_ >= 1.0)    /* y gdu's = 100 */
  726.         gdu_limit_mms = ymax - ymin;
  727.     else            /* x gdu's = 100 */
  728.         gdu_limit_mms = xmax - xmin;
  729.  
  730.     x_gdu = y_gdu = gdu_limit_mms / 100;    /* mm's / gdu */
  731.  
  732. #ifdef debug
  733. printf ("(limit): ratio = %lf, x_gdu = %lf mm/gdu, y_gdu = %lf mm/gdu\n", ratio_, x_gdu, y_gdu);
  734. #endif
  735.  
  736.     return;
  737.     }
  738.  
  739. /*------------------------------------------------------*/
  740.  
  741. void locate (xmin, xmax, ymin, ymax) double xmin, xmax, ymin, ymax;
  742.     {
  743.  
  744.     /* units are in gdu's; locate is defined in terms of offsets from
  745.     the lower right limit coordinate.  clip[][] is in screen coordinates
  746.     (pixels), and locate is in mm's. locate() sets the softclip limits
  747.     to the locate parameters when called. The locate coordinates are
  748.     kept in mm's because of the varying anisotropic pixel density of
  749.     the various screen modes of the PC */
  750.  
  751.     locat[0] = limit_xmin + xmin * x_gdu;
  752.     locat[1] = limit_xmin + xmax * x_gdu;
  753.     locat[2] = limit_ymin + ymin * y_gdu;
  754.     locat[3] = limit_ymin + ymax * y_gdu;    /* new locate window in mm's */
  755.  
  756.     pivot_x = locat[0];
  757.     pivot_y = locat[2];
  758.     pivot_cos = 1.0;
  759.     pivot_sin = 0.0;    /* clear existing pivot (if any) */
  760.  
  761.     clp[0][1] = clp[0][0] + (int) (xmin * x_gdu * x_ppm);    /* xmin */
  762.     clp[1][1] = clp[0][0] + (int) (xmax * x_gdu * x_ppm);    /* xmax */
  763.     clp[2][1] = clp[2][0] + (int) (ymin * y_gdu * y_ppm);    /* ymin */
  764.     clp[3][1] = clp[2][0] + (int) (ymax * y_gdu * y_ppm);    /* ymax */
  765.  
  766. #ifdef debug
  767. printf ("(locate): (x,y) min = (%d,%d), (x,y) max = (%d,%d)\n", locat[0], locat[2], locat[1], locat[3]);
  768. #endif
  769.  
  770.     clip_type = clip_store = 1;    /* select soft clipping */
  771.     return;
  772.     }
  773.  
  774. /*------------------------------------------------------*/
  775. /* routine to set new softclip limits using current units */
  776.  
  777. void clip (xmin, xmax, ymin, ymax) double xmin, xmax, ymin, ymax;
  778.     {
  779.     /* define softclip area within scaled locate area*/
  780.     /* (x, y) are in user units (udu's, mm's), or gdu's at g_init */
  781.  
  782.     clp[0][1] = (int) ((xmin - x_offset) * x_factor + locat[0] * x_ppm);
  783.     clp[1][1] = (int) ((xmax - x_offset) * x_factor + locat[0] * x_ppm);
  784.     clp[2][1] = (int) ((ymin - y_offset) * y_factor + locat[2] * y_ppm);
  785.     clp[3][1] = (int) ((ymax - y_offset) * y_factor + locat[2] * y_ppm);
  786.  
  787.     clip_type = clip_store = 1;    /* select soft clipping */
  788.     return;
  789.     }
  790.  
  791. /*------------------------------------------------------*/
  792. /* anisotropic scaling routine */
  793.  
  794. void scale (x1, x2, y1, y2) double x1, x2, y1, y2; /* coordinates are in udu's */
  795.     {
  796.     /* x_factor, y_factor are pixels/user_unit; x_offset, y_offset are in udu's */
  797.     x_factor =  x_ppm * (locat[1] - locat[0])/(x2 - x1);
  798.     y_factor =  y_ppm * (locat[3] - locat[2])/(y2 - y1);
  799.     x_offset = x1;
  800.     y_offset = y1;            /* offset in udu's */
  801.  
  802. #ifdef debug
  803. printf ("(scale): x_factor: %f, y_factor: %f, x_offset: %f, y_offset: %f\n", x_factor, y_factor, x_offset, y_offset);
  804. #endif
  805.  
  806.     units = 1; /* set to user units */
  807.  
  808.     pivot_x = locat[0];
  809.     pivot_y = locat[2];
  810.     pivot_cos = 1.0;
  811.     pivot_sin = 0.0;    /* clear existing pivot (if any) */
  812.  
  813.     clip_type = clip_store = 1;    /* select soft clipping */
  814.     return;
  815.     }
  816.  
  817. /*--------------------------------------------------------*/
  818. /* isotropic scaling routine */
  819.  
  820. void show (xmin, xmax, ymin, ymax) double xmin, xmax, ymin, ymax;
  821.     {
  822.     double xf, yf;
  823.     /* calculate number of mm / user_unit */
  824.     xf = (locat[1] - locat[0]) / (xmax - xmin);
  825.     yf = (locat[3] - locat[2]) / (ymax - ymin);
  826.  
  827.     /* scale window isotropically using the scale factor (xf or yf)
  828.     of the axis with the fewer mm / user_unit.  Then calculate
  829.     a new offset for the remaining axis so that the specified
  830.     scale (ymax - ymin or xmax - xmin) will be centered in the new
  831.     window. */
  832.  
  833.     if (xf < yf)
  834.         {
  835.         /* use xf mm / user_unit and center ymin and ymax in 
  836.         the new scale. */
  837.         x_factor = xf * x_ppm;
  838.         y_factor = xf * y_ppm;
  839.         x_offset = xmin;
  840.         y_offset = (ymax + ymin - (locat[3] - locat[2]) / xf) / 2;
  841.         }
  842.     else
  843.         {
  844.         /* use yf mm / user_unit and center xmin and xmax in 
  845.         the new scale. */
  846.         x_factor = yf * x_ppm;
  847.         y_factor = yf * y_ppm;
  848.         y_offset = ymin;
  849.         x_offset = (xmax + xmin - (locat[1] - locat[0]) / yf) / 2;
  850.         }
  851.     units = 1; /* set to user units */
  852.  
  853.     pivot_x = locat[0];
  854.     pivot_y = locat[2];
  855.     pivot_cos = 1.0;
  856.     pivot_sin = 0.0;    /* clear existing pivot (if any) */
  857.  
  858. #ifdef debug
  859. printf ("(show): x_factor: %f, y_factor: %f, x_offset: %f, y_offset: %f\n", x_factor, y_factor, x_offset, y_offset);
  860. #endif
  861.  
  862.     clip_type = clip_store = 1;    /* select soft clipping */
  863.     return;
  864.     }
  865. /*-------------------------------------------------------------*/
  866. /* mm scaling routine */
  867.  
  868. void mscale (x, y) double x, y;
  869.     {
  870.     /* x,y = displacement of origin (in mm's) from lower left corner of locate window */
  871.     x_factor = x_ppm;    /* pixels/mm for full screen */
  872.     y_factor = y_ppm;    /* invariant w/ hardclip limits */
  873.     x_offset = - x;
  874.     y_offset = - y;        /* offset of mscale (0,0) in mm */
  875.  
  876.     units = 1; /* set to user units */
  877.  
  878.     pivot_x = locat[0];
  879.     pivot_y = locat[2];
  880.     pivot_cos = 1.0;
  881.     pivot_sin = 0.0;    /* clear existing pivot (if any) */
  882.  
  883.     clip_type = clip_store = 1;    /* select soft clipping */
  884.     return;
  885.     }
  886.  
  887. /*-------------------------------------------------------------*/
  888.  
  889. void frame ()
  890.     {
  891.     int x1, y1, x2, y2;
  892.  
  893.     /* frame the current clipping window.  The soft clip limits never
  894.     exceed the hard clip limits.  drawline() is called with pixel units */
  895.  
  896.     pendown = 1;    /* Drop pen to draw */
  897.  
  898.     x1 = clp[0][clip_type]; /* draw frame around current clipping area */
  899.     x2 = clp[1][clip_type];
  900.     y1 = clp[2][clip_type];
  901.     y2 = clp[3][clip_type];
  902.  
  903.     drawline (x1, y1, x1, y2);
  904.     drawline (x1, y2, x2, y2);
  905.     drawline (x2, y2, x2, y1);
  906.     drawline (x2, y1, x1, y1);
  907.     rpos_x = xpos = x1;
  908.     rpos_y = ypos = y1;    /* move pen to lower left corner */
  909.     pendown = 0;    /* mark pen as up */
  910.     return;
  911.     }
  912.  
  913. /*-------------------------------------------------------------*/
  914.  
  915. void pdir (angle) double angle;
  916.     {
  917.     /* set plotting direction for relative & incremental plotting,
  918.     drawing, and moving */
  919.  
  920.     if (degree == 1) angle = angle / 57.2958;    /* convert to radians */
  921.     p_cos = cos (angle);
  922.     p_sin = sin (angle);
  923.  
  924. #ifdef debug
  925. printf ("(pdir): p_cos = %12.9lf, p_sin = %12.9lf\n", p_cos, p_sin);
  926. #endif
  927.  
  928.     return;
  929.     }
  930.  
  931. /*-------------------------------------------------------------*/
  932.  
  933. void move (x, y) double x, y;
  934.     {
  935.     /* direct screen move */
  936.     pendown = 0;    /* mark pen as up */
  937.     if (units)    /* udu's */
  938.         {
  939.         xpos = (int) ((x - x_offset) * x_factor) +  locat[0] * x_ppm ;
  940.         ypos = (int) ((y - y_offset) * y_factor) +  locat[2] * y_ppm;
  941.         }
  942.     else    /* gdu's: (gdu's) * (mm/gdu) * (pixels/mm) + offset of hardclip origin */
  943.         {
  944.         xpos = (int) (x * x_gdu * x_ppm) + clp[0][0];
  945.         ypos = (int) (y * y_gdu * y_ppm) + clp[2][0];
  946.         }
  947.     rpos_x = xpos;
  948.     rpos_y = ypos;    /* update relative plot origin coordinates */
  949.  
  950. #ifdef debug
  951. printf ("move to (pixel) (%d,%d)\n", xpos, ypos);
  952. #endif
  953.  
  954.     return;
  955.     }
  956.  
  957. /*-----------------------------------------------------------*/
  958.  
  959. void draw (x,y) double x,y;
  960.     {
  961.     /* draw from current (x,y) to new (x.y) */
  962.     /* passed parameters may be either gdu's or udu's */
  963.     int x_1, x_2, y_1, y_2;
  964.  
  965.     pendown = 1;    /* mark pen as down */
  966.     if (units)    /* udu's */
  967.         {
  968.         rpos_x = (int) ((x - x_offset) * x_factor) + locat[0] * x_ppm;
  969.         rpos_y = (int) ((y - y_offset) * y_factor) + locat[2] * y_ppm;
  970.         }
  971.     else    /* gdu's: (gdu's) * (mm/gdu) * (pixels/mm) + offset of hardclip origin */
  972.         {
  973.         rpos_x = (int) (x * x_gdu * x_ppm) + clp[0][0];
  974.         rpos_y = (int) (y * y_gdu * y_ppm) + clp[2][0];
  975.         }
  976.  
  977.     x_1 = (int)( ((double) (xpos - pivot_x)) * pivot_cos - ((double) (ypos - pivot_y)) * pivot_sin) + pivot_x;
  978.     y_1 = (int)( ((double) (ypos - pivot_y)) * pivot_cos + ((double) (xpos - pivot_x)) * pivot_sin) + pivot_y;
  979.     x_2 = (int)( ((double) (rpos_x - pivot_x)) * pivot_cos - ((double) (rpos_y - pivot_y)) * pivot_sin) + pivot_x;
  980.     y_2 = (int)( ((double) (rpos_y - pivot_y)) * pivot_cos + ((double) (rpos_x - pivot_x)) * pivot_sin) + pivot_y;
  981.  
  982.     drawline ( x_1, y_1, x_2, y_2 ); /* passed coordinates are pixel locations */
  983.  
  984. #ifdef debug
  985. printf ("draw from (pixel) (%d,%d) to (%d,%d)\n", xpos, ypos, rpos_x, rpos_y);
  986. #endif
  987.  
  988.     xpos = rpos_x;
  989.     ypos = rpos_y;    /* update logical pen position */
  990.     return;
  991.     }
  992.  
  993. /*------------------------------------------------------*/
  994.  
  995. void plot (x, y, penc) double x, y; int penc;
  996.     {
  997.     /* plot from current (x,y) to new (x,y) */
  998.  
  999.     switch ((( abs (penc) & 1) << 1) + (penc < 0))
  1000.         {
  1001.         case 0: /* even, penc >0 */
  1002.             if (pendown) draw (x,y);
  1003.             else move (x, y);
  1004.             pendown = 0;
  1005.             break;
  1006.         case 1:    /* even, penc < 0 */
  1007.             pendown = 0;
  1008.             move (x, y);
  1009.             break;
  1010.         case 2:    /* odd,  penc >= 0 */
  1011.             if (pendown) draw (x, y);
  1012.             else move (x, y);
  1013.             pendown = 1;
  1014.             break;
  1015.         case 3:    /* odd, penc < 0 */
  1016.             draw (x, y);
  1017.             pendown = 1;
  1018.         default:break;
  1019.         }
  1020.     return;        /* call to draw() updates pen position */
  1021.     }
  1022.  
  1023. /*-------------------------------------------------------------*/
  1024.  
  1025. void rplot (x, y, penc) double x, y; int penc;
  1026.     {
  1027.     /* plot relative to (rpos_x, rpos_y) */
  1028.  
  1029.     switch ((( abs (penc) & 1) << 1) + (penc < 0))
  1030.         {
  1031.         case 0: /* even, penc >0 */
  1032.             if (pendown) rdraw (x,y);
  1033.             else rmove (x, y);
  1034.             pendown = 0;
  1035.             break;
  1036.         case 1:    /* even, penc < 0 */
  1037.             pendown = 0;
  1038.             rmove (x, y);
  1039.             break;
  1040.         case 2:    /* odd,  penc >= 0 */
  1041.             if (pendown) rdraw (x, y);
  1042.             else rmove (x, y);
  1043.             pendown = 1;
  1044.             break;
  1045.         case 3:    /* odd, penc < 0 */
  1046.             rdraw (x, y);
  1047.             pendown = 1;
  1048.         default:break;
  1049.         }
  1050.     return;        /* call to rdraw() updates pen position */
  1051.     }
  1052.  
  1053. /*-------------------------------------------------------------*/
  1054.  
  1055. void rdraw (x,y) double x,y;
  1056.     {
  1057.     /* draw relative to (rpos_x, rpos_y) */
  1058.     double xp, yp;
  1059.     int xpix, ypix, x_1, y_1, x_2, y_2;
  1060.     pendown = 1;            /* mark pen as down */
  1061.     xp = x * p_cos - y * p_sin;
  1062.     yp = y * p_cos + x * p_sin;    /* relative rotation */
  1063.  
  1064.     /* get pixel coordinates of (x, y) relative to (rpos_x, rpos_y) */
  1065.     xpix = rpos_x + ( units ) ? ((int) (xp * x_factor)): ((int) (xp * x_gdu * x_ppm));
  1066.     ypix = rpos_y + ( units ) ? ((int) (yp * y_factor)): ((int) (yp * y_gdu * y_ppm));
  1067.  
  1068.     x_1 = (int)( ((double) (xpos - pivot_x)) * pivot_cos - ((double) (ypos - pivot_y)) * pivot_sin) + pivot_x;
  1069.     y_1 = (int)( ((double) (ypos - pivot_y)) * pivot_cos + ((double) (xpos - pivot_x)) * pivot_sin) + pivot_y;
  1070.     x_2 = (int)( ((double) (xpix - pivot_x)) * pivot_cos - ((double) (ypix - pivot_y)) * pivot_sin) + pivot_x;
  1071.     y_2 = (int)( ((double) (ypix - pivot_y)) * pivot_cos + ((double) (xpix - pivot_x)) * pivot_sin) + pivot_y;
  1072.  
  1073.     drawline (x_1, y_1, x_2, y_2);    /* draw line */
  1074.  
  1075. #ifdef debug
  1076. printf ("rdraw from (pixel) (%d,%d) to (%d,%d)\n", xpos, ypos, xpix, ypix);
  1077. #endif
  1078.  
  1079.     xpos = xpix;
  1080.     ypos = ypix;    /* update pen position */
  1081.     return;
  1082.     }
  1083.  
  1084. /*-------------------------------------------------------------*/
  1085.  
  1086. void rmove (x, y) double x, y;
  1087.     {
  1088.     /* move relative to rpos_x, rpos_y */
  1089.  
  1090.     double xp, yp;
  1091.     xp = x * p_cos - y * p_sin;
  1092.     yp = y * p_cos + x * p_sin;    /* relative rotation */
  1093.  
  1094.     if (units)     /* udu's */
  1095.         {
  1096.         xpos = rpos_x + (int) ( xp * x_factor);
  1097.         ypos = rpos_y + (int) ( yp * y_factor);
  1098.         }
  1099.     else        /* gdu's * */
  1100.         {
  1101.         xpos = rpos_x + (int) (xp * x_gdu * x_ppm);
  1102.         ypos = rpos_y + (int) (yp * y_gdu * y_ppm);
  1103.         }
  1104.  
  1105. #ifdef debug
  1106. printf ("rmove to (pixel) (%d,%d)\n", xpos, ypos);
  1107. #endif
  1108.  
  1109.     return;
  1110.     }
  1111.  
  1112. /*-------------------------------------------------------------*/
  1113.  
  1114. void iplot (x, y, penc) double x, y; int penc;
  1115.     {
  1116.     /* plot incrementally to (x, y) */
  1117.  
  1118.     switch ((( abs (penc) & 1) << 1) + (penc < 0))
  1119.         {
  1120.         case 0: /* even, penc >0 */
  1121.             if (pendown) idraw (x,y);
  1122.             else imove (x, y);
  1123.             pendown = 0;
  1124.             break;
  1125.         case 1:    /* even, penc < 0 */
  1126.             pendown = 0;
  1127.             imove (x, y);
  1128.             break;
  1129.         case 2:    /* odd,  penc >= 0 */
  1130.             if (pendown) idraw (x, y);
  1131.             else imove (x, y);
  1132.             pendown = 1;
  1133.             break;
  1134.         case 3:    /* odd, penc < 0 */
  1135.             idraw (x, y);
  1136.             pendown = 1;
  1137.         default:break;
  1138.         }
  1139.     return;        /* call to idraw() updates pen position */
  1140.     }
  1141.  
  1142. /*-------------------------------------------------------------*/
  1143.  
  1144. void idraw (x, y) double x, y;
  1145.     {
  1146.     /* incremental draw from (x,y) to (x + x',y + y') */
  1147.     int x_1, x_2, y_1, y_2;
  1148.     double xp, yp;
  1149.  
  1150. #ifdef debug
  1151. printf ("(idraw): x = %12.9lf, y = %12.9lf\n", x, y);
  1152. #endif
  1153.  
  1154.     pendown = 1;
  1155.     xp = x * p_cos - y * p_sin;
  1156.     yp = y * p_cos + x * p_sin;    /* rotate coordinates to p_dir() */
  1157.  
  1158.     if (units)     /* udu's */
  1159.         {
  1160.         rpos_x = xpos + (int) (xp * x_factor);
  1161.         rpos_y = ypos + (int) (yp * y_factor);
  1162.         }
  1163.     else
  1164.         {
  1165.         rpos_x = xpos + (int) (xp * x_gdu * x_ppm);
  1166.         rpos_y = ypos + (int) (yp * y_gdu * y_ppm);
  1167.         }
  1168.  
  1169. #ifdef debug
  1170. printf ("(idraw): rpos_x = %d, rpos_y = %d\n", rpos_x, rpos_y);
  1171. #endif
  1172.  
  1173.     x_1 = (int)( ((double) (xpos - pivot_x)) * pivot_cos - ((double) (ypos - pivot_y)) * pivot_sin) + pivot_x;
  1174.     y_1 = (int)( ((double) (ypos - pivot_y)) * pivot_cos + ((double) (xpos - pivot_x)) * pivot_sin) + pivot_y;
  1175.     x_2 = (int)( ((double) (rpos_x - pivot_x)) * pivot_cos - ((double) (rpos_y - pivot_y)) * pivot_sin) + pivot_x;
  1176.     y_2 = (int)( ((double) (rpos_y - pivot_y)) * pivot_cos + ((double) (rpos_x - pivot_x)) * pivot_sin) + pivot_y;
  1177.  
  1178.     drawline (xpos, ypos, rpos_x, rpos_y);
  1179.     xpos = rpos_x;
  1180.     ypos = rpos_y;        /* update relative pen position */
  1181.     return;
  1182.     }
  1183.  
  1184. /*-------------------------------------------------------------*/
  1185.  
  1186. void imove (x, y) double x, y;
  1187.     {
  1188.     /* move incrementally to x, y */
  1189.  
  1190.     double xp, yp;
  1191.     xp = x * p_cos - y * p_sin;
  1192.     yp = y * p_cos + x * p_sin;    /* rotate coordinates to p_dir() */
  1193.  
  1194.     if (units)     /* udu's */
  1195.         {
  1196.         rpos_x = xpos = xpos + (int) ( xp * x_factor);
  1197.         rpos_y = ypos = ypos + (int) ( yp * y_factor);
  1198.         }
  1199.     else    /* gdu's: (gdu's) * (mm/gdu) * (pixels/mm) + offset of hardclip origin */
  1200.         {
  1201.         rpos_x = xpos = xpos + (int) (x * x_gdu * x_ppm) + clp[0][0];
  1202.         rpos_y = ypos = ypos + (int) (y * y_gdu * y_ppm) + clp[2][0];
  1203.         }
  1204.     return;
  1205.     }
  1206.  
  1207. /*-------------------------------------------------------------*/
  1208.  
  1209. void setgu ()
  1210.     {
  1211.     /* select graphics units for display */
  1212.     units = 0;
  1213.     clip_store = clip_type;    /* save last clipping type */
  1214.     clip_type = 0;        /* use hardclip limits for gdu's */
  1215.     return;
  1216.     }
  1217.  
  1218. /*-------------------------------------------------------------*/
  1219.  
  1220. void setuu ()
  1221.     {
  1222.     /* select user units for display */
  1223.     units = 1;
  1224.     clip_type = clip_store;    /* retrieve last clipping type (if any) */
  1225.     return;
  1226.     }
  1227.  
  1228. /*-------------------------------------------------------------*/
  1229.  
  1230. void unclip ()
  1231.     {
  1232.     clip_store = clip_type = 0;    /* set clip window to the hard clip limits */
  1233.     return;
  1234.     }
  1235. /*-------------------------------------------------------------*/
  1236. void pivot (angle) double angle;
  1237.     {
  1238.     if (degree) angle /= 57.2958;
  1239.     pivot_cos = cos (angle);
  1240.     pivot_sin = sin (angle);
  1241.     pivot_x = xpos;
  1242.     pivot_y = ypos;
  1243.  
  1244. #ifdef debug
  1245. printf ("pivot_x = %d, pivot_y = %d\n", pivot_x, pivot_y);
  1246. printf ("pivot_cos = %12.9lf, pivot_sin = %12.9lf\n", pivot_cos, pivot_sin);
  1247. #endif
  1248.     return;
  1249.     }
  1250.  
  1251.  
  1252. /*-------------------------------------------------------------*/
  1253. /* drawline -- a graphics function
  1254.  
  1255. calling:
  1256.  
  1257.     void drawline (x1, y1, x2, y2) int x1, y1, x2, y2;
  1258.  
  1259. draws a line from (x1,y1) to (x2,y2) using Bresenham's algorithm.  The
  1260. line is drawn using the pen chosen unless no pen is chosen.  The previous
  1261. pen is then used.  Pen 0 is no pen, and pen < 0 undraws a line.
  1262.  
  1263. The cartesian coordinate system is divided into 8 sectors.
  1264.  
  1265.             ^y
  1266.            \ 3    |  2 /
  1267.            4  \  |  /  1
  1268.         _______\|/_________ x
  1269.                /|\
  1270.           5  /    |  \  8
  1271.            / 6    |  7 \
  1272.             v
  1273. This division is necessary because Bresenham's algorithm works only for slopes
  1274. up to 1.  Above 1, it is necessary to change to the next octant.  The same is
  1275. true for slopes below -1.  */
  1276.  
  1277.  
  1278.  
  1279. static void drawline (x1, y1, x2, y2) int x1, y1, x2, y2;
  1280.     {
  1281.     /* passed parameters are screen pixel coordinates */
  1282.     int x_inc, y_inc, dx, dy, dir, err, ct, i, tick;
  1283.  
  1284.     if ( (Pen == 0) || (pendown == 0) ) return;
  1285.     /* no point in drawing with no pen or pen up */
  1286.  
  1287.     err = 0;
  1288.     ct = clip_type;
  1289.  
  1290. #ifdef debug
  1291. printf ("drawline from (pixel) (%d,%d) to (%d,%d)\n", x1, y1, x2, y2);
  1292. #endif
  1293.  
  1294.     if (l_type == 2)    /* dot only at endpoint */
  1295.         {
  1296.         putdot (x2, y2);
  1297.         return;
  1298.         }
  1299.  
  1300.     dx = abs (x2 - x1);
  1301.     dy = abs (y2 - y1);
  1302.     x_inc = 2 * dx;
  1303.     y_inc = 2 * dy;
  1304.     if (dy > dx)                /* |slope| >1 */
  1305.         {
  1306.         tick = (int) (x_gdu * x_ppm / 2 + 0.5);
  1307.         if (l_type == 10) tick = (int) (x_gdu * x_ppm + 0.5); 
  1308.         pix_max = pen_py[pat_ptr];
  1309.         pen_stat = pen_c[pat_ptr];
  1310.         dir = (x2 > x1) ? 1: -1;    /* set direction to draw */
  1311.         if (y2 >= y1)            /* sector 2,3 */
  1312.             {
  1313.             while (y1 <= y2)    /* draw vector */
  1314.                 {        /* test clip limits */
  1315.                 if ( (!(x1 < clp[0][ct] || x1 > clp[1][ct]
  1316.                 || y1 < clp[2][ct] || y1 > clp[3][ct])) &&
  1317.                 (pen_stat > 0) ) putdot (x1, y1);
  1318.                 ++pix_cnt;
  1319.                 ++y1;            /* next y-incr */
  1320.                 err = err + x_inc;
  1321.                 if (err >= dy)        /* control x-increments */
  1322.                     {
  1323.                     err = err - y_inc;
  1324.                     x1 = x1 + dir;
  1325.                     ++pix_cnt;
  1326.                     }
  1327.                 if (pix_cnt >= pix_max ) 
  1328.                     {
  1329.                     ++pat_ptr;
  1330.                     if (pat_ptr >= pat_length)
  1331.                         {
  1332.                         pat_ptr = 0;
  1333.                         pix_cnt = 0;
  1334.                         }
  1335.                     if ( (l_type == 9) || (l_type == 10) )
  1336.                         {
  1337.                         for (i = -tick; i <= tick; ++i)
  1338.                             if (!(x1 + i < clp[0][ct] || x1 + i > clp[1][ct]
  1339.                             || y1 < clp[2][ct] || y1 > clp[3][ct]))
  1340.                             putdot ( x1 + i , y1);
  1341.                         }
  1342.                     pix_max = pen_py[pat_ptr];
  1343.                     pen_stat = pen_c[pat_ptr];
  1344.  
  1345. #ifdef debug
  1346. printf ("(draw_line): pat_ptr = %d\n", pat_ptr);
  1347. printf ("(draw_line): pix_max = %d, pen_stat = %d\n", pix_max, pen_stat);
  1348. #endif
  1349.  
  1350.                     }
  1351.                 }
  1352.             }
  1353.         else                    /* sector 6,7 */
  1354.             {
  1355.             while (y2 <= y1)        /* draw vector */
  1356.                 {            /* test clip limits */
  1357.                 if ( (!(x1 < clp[0][ct] || x1 > clp[1][ct]
  1358.                 || y1 < clp[2][ct] || y1 > clp[3][ct])) &&
  1359.                 (pen_stat > 0) ) putdot (x1, y1);
  1360.                 --y1;            /* next y-incr */
  1361.                 ++pix_cnt;
  1362.                 err = err + x_inc;
  1363.                 if ( err >= dy)        /* control x-increments */
  1364.                     {
  1365.                     err = err - y_inc;
  1366.                     x1 = x1 + dir;
  1367.                     ++pix_cnt;
  1368.                     }
  1369.                 if (pix_cnt >= pix_max ) 
  1370.                     {
  1371.                     ++pat_ptr;
  1372.                     if (pat_ptr >= pat_length)
  1373.                         {
  1374.                         pat_ptr = 0;
  1375.                         pix_cnt = 0;
  1376.                         }
  1377.                     if ( (l_type == 9) || (l_type == 10) )
  1378.                         {
  1379.                         for (i = -tick; i <= tick; ++i)
  1380.                             if (!(x1 + i < clp[0][ct] || x1 + i > clp[1][ct]
  1381.                             || y1 < clp[2][ct] || y1 > clp[3][ct]))
  1382.                             putdot ( x1 + i , y1);
  1383.                         }
  1384.                     pix_max = pen_py[pat_ptr];
  1385.                     pen_stat = pen_c[pat_ptr];
  1386.  
  1387. #ifdef debug
  1388. printf ("(draw_line): pat_ptr = %d\n", pat_ptr);
  1389. printf ("(draw_line): pix_max = %d, pen_stat = %d\n", pix_max, pen_stat);
  1390. #endif
  1391.                     }
  1392.  
  1393.                 }
  1394.             }
  1395.         return;
  1396.         }
  1397.     else                    /* |slope| <= 1 */
  1398.         {
  1399.         tick = (int) (x_gdu * x_ppm / 2 + 0.5);
  1400.         if (l_type == 10) tick = (int) (x_gdu * x_ppm + 0.5); 
  1401.         pix_max = pen_px[pat_ptr];
  1402.         pen_stat = pen_c[pat_ptr];
  1403.         dir = (y2 > y1) ? 1: -1;    /* set y direction */
  1404.         if (x2 >= x1)            /* sector 1,8 */
  1405.             {
  1406.             while (x1 <= x2)    /* draw vector */
  1407.                 {        /* test clip limits */
  1408.                 if ( (!(x1 < clp[0][ct] || x1 > clp[1][ct]
  1409.                 || y1 < clp[2][ct] || y1 > clp[3][ct])) &&
  1410.                 (pen_stat > 0) ) putdot (x1, y1);
  1411.                 ++x1;            /* next x-incr */
  1412.                 ++pix_cnt;
  1413.                 err = err + y_inc;
  1414.                 if (err >= dx)        /* controls y-increments */
  1415.                     {
  1416.                     err = err - x_inc;
  1417.                     y1 = y1 + dir;
  1418.                     ++pix_cnt;
  1419.                     }
  1420.                 if (pix_cnt >= pix_max ) 
  1421.                     {
  1422.                     ++pat_ptr;
  1423.                     if (pat_ptr >= pat_length)
  1424.                         {
  1425.                         pat_ptr = 0;
  1426.                         pix_cnt = 0;
  1427.                         }
  1428.                     if ( (l_type == 9) || (l_type == 10) )
  1429.                         {
  1430.                         for (i = -tick; i <= tick; ++i)
  1431.                             if (!(x1 < clp[0][ct] || x1 > clp[1][ct]
  1432.                             || y1 + i < clp[2][ct] || y1 + i > clp[3][ct]))
  1433.                             putdot ( x1 , y1 + i );
  1434.                         }
  1435.                     pix_max = pen_px[pat_ptr];
  1436.                     pen_stat = pen_c[pat_ptr];
  1437.  
  1438. #ifdef debug
  1439. printf ("(draw_line): pat_ptr = %d\n", pat_ptr);
  1440. printf ("(draw_line): pix_max = %d, pen_stat = %d\n", pix_max, pen_stat);
  1441. #endif
  1442.                     }
  1443.  
  1444.                 }
  1445.             }
  1446.         else                /* sector 4,5 */
  1447.             {
  1448.             while (x1 >= x2)    /* draw vector */
  1449.                 {        /* test clip limits */
  1450.                 if ( (!(x1 < clp[0][ct] || x1 > clp[1][ct]
  1451.                 || y1 < clp[2][ct] || y1 > clp[3][ct])) &&
  1452.                 (pen_stat > 0) ) putdot (x1, y1);
  1453.                 --x1;            /* next x-incr */
  1454.                 ++pix_cnt;
  1455.                 err = err + y_inc;
  1456.                 if (err >= dx)        /* controls y-increments */
  1457.                     {
  1458.                     err = err - x_inc;
  1459.                     y1 = y1 + dir;
  1460.                     ++pix_cnt;
  1461.                     }
  1462.                 if (pix_cnt >= pix_max ) 
  1463.                     {
  1464.                     ++pat_ptr;
  1465.                     if (pat_ptr >= pat_length)
  1466.                         {
  1467.                         pat_ptr = 0;
  1468.                         pix_cnt = 0;
  1469.                         }
  1470.                     if ( (l_type == 9) || (l_type == 10) )
  1471.                         {
  1472.                         for (i = -tick; i <= tick; ++i)
  1473.                             if (!(x1 < clp[0][ct] || x1 > clp[1][ct]
  1474.                             || y1 + i < clp[2][ct] || y1 + i > clp[3][ct]))
  1475.                             putdot ( x1 , y1 + i );
  1476.                         }
  1477.                     pix_max = pen_px[pat_ptr];
  1478.                     pen_stat = pen_c[pat_ptr];
  1479.  
  1480. #ifdef debug
  1481. printf ("(draw_line): pat_ptr = %d\n", pat_ptr);
  1482. printf ("(draw_line): pix_max = %d, pen_stat = %d\n", pix_max, pen_stat);
  1483. #endif
  1484.                     }
  1485.  
  1486.                 }
  1487.             }
  1488.         return;
  1489.         }
  1490.     }        /* end of line drawing algorithm */
  1491.  
  1492. /*-------------------------------------------------------------*/
  1493.  
  1494. /* putdot() */
  1495. /*
  1496. This routine places or removes a dot in the graphics crt at the
  1497. location it is told to place it.  putdot() shifts the origin from the
  1498. upper left corner of the screen to the lower left corner.  This makes
  1499. the display compatible with Hewlett-Packard's graphics display system.
  1500.  
  1501. putdot() expects the global variables max_x_dot and max_y_dot to be defined
  1502. in the screen setup routine for absolute screen limits.  Putdot checks only
  1503. for absolute screen boundaries and the current hardclip limits.  They are:
  1504.  
  1505. (clip[0][0],clip[2][0]), (clip[1][0],clip[3][0]) : (x1, y1), (x2, y2)
  1506. (lower left, upper right) screen boundaries.
  1507. */
  1508.  
  1509. void putdot (x,y) int x,y;
  1510.     {
  1511.     /* can never exceed hard clip limits under program control. */
  1512.  
  1513.     if (  (x < clp[0][0]) | (x > clp[1][0]) | 
  1514.         (y < clp[2][0]) | (y > clp[3][0]) )
  1515.         return;        /* outside hard clip limits: do nothing */
  1516.  
  1517.     if (x > max_x_dot || y > max_y_dot || x < 0 || y < 0)
  1518.         return;        /* outside physical screen limits */
  1519.  
  1520.     regs.x.dx = max_y_dot - y;        /* invert y-coordinate: row # */
  1521.     regs.x.cx = x;                /* setup x-coordinate: col # */
  1522.     regs.h.ah = WRT_PIX;            /* mode for BIOS graphics write */
  1523.     if (Pen > 0)
  1524.         regs.h.al = (unsigned char) Pen;    /* pixel color */
  1525.     else
  1526.         regs.h.al = (unsigned char) 0;        /* erase pixel */
  1527.  
  1528.  
  1529.     /* in order to clear pixels from the screen, it is necessary to
  1530.     read the screen first since the IBM PC will only XOR pixels.  Thus,
  1531.     to erase a pixel, one should first determine if it is on, and then
  1532.     XOR the pixel with the same data.  NOTE!!! if you change the pen
  1533.     color between write and erase, it will erase in the color chosen
  1534.     and this may NOT erase the line.  */
  1535.  
  1536.     int86 ( VIDEO, ®s, ®s);
  1537.  
  1538.     return;
  1539.     }
  1540.