home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / microcrn / issue_45.arc / PR-GRAPH.ARC / PR-GRAPH.C < prev   
Text File  |  1988-03-20  |  25KB  |  690 lines

  1. /* PR-GRAPH.C - library of printer graphics functions
  2.  
  3.    This supports an article in Micro Cornucopia Magazine Issue #45.
  4.    As always, the code is up for grabs. In the immortal words of Laine Stump,
  5.    "Permission to do whatever the hell you want with it." I do ask that if
  6.    you use this code to become rich beyond your wildest dreams, please send
  7.    me a six-pack of the best local brew in your neck of the woods.
  8.  
  9.    You'll notice the structure (of type plot) is different from the one
  10.    printed in the mag. I originally wrote only the East version of the
  11.    graphing routines. When I started the others I realized that it made more
  12.    sense to define an axis in terms of its origin and axis lengths. Much
  13.    easier to rotate a given axis to different orientations with it defined
  14.    this way.
  15.  
  16.    I also fiddled with the axis labeling in p_draw_scale with less than
  17.    wonderful results. If you choose axis lengths (x_length and y_length)
  18.    judiciously there's no problem. Play with different axis lengths for a
  19.    given plot and you'll see what I mean.
  20.  
  21.    Needs DUMP.C (from Issue #44) for printer setup, etc. The function
  22.    setup_gr_line () in DUMP.C should be changed to accept (char p_mode,
  23.    int width) as parameters. I originally wrote it with 60 dpi mode hard
  24.    coded in.
  25.  
  26.    Requires the font file PR_CHARS.DAT generated by CHARGEN.C.
  27.  
  28.    Oh yeah, I used Turbo C v1.5 compact model.
  29.  
  30.    Larry Fogg - Halloween, 1988
  31. */
  32.  
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <dos.h>
  36. #include <math.h>                        /* only included for sin () example */
  37. #include "dump.c"     /* printer setup and Herc screen dump from Micro C #44 */
  38.  
  39. #define boolean char
  40. #define yes 1
  41. #define no 0
  42.  
  43. #define N 'N'                               /* "directions" on printer paper */
  44. #define E 'E'                    /* N is the direction of normal text output */
  45. #define W 'W'
  46. #define S 'S'
  47.  
  48. #define herc_base 0xb000                                  /* Herc parameters */
  49. #define v_max_row 347
  50. #define v_max_col 719
  51. #define ch_size 11                           /* dot highth of a printer char */
  52.  
  53. typedef struct                           /* used for graph plotting routines */
  54. {
  55.   char orientation;                          /* direction of X axis of graph */
  56.   int x_min;             /* actual axis origin coordinates (x-east, y-north) */
  57.   int y_min;
  58.   int x_length;                                     /* actual length of axis */
  59.   int y_length;
  60.   char x_label [50];                                          /* axis labels */
  61.   char y_label [50];
  62.   int xdata_min;                                              /* data bounds */
  63.   int xdata_max;
  64.   int ydata_min;
  65.   int ydata_max;
  66.   int x_step;                                /* increments for labeling axis */
  67.   int y_step;
  68.   int points [2][100];                               /* data in (x, y) pairs */
  69. } plot;
  70.  
  71. char *p_buf;                                    /* pointer to printer memory */
  72. char p_chars [256][11];       /* holds 11 byte definition for each character */
  73.  
  74. int p_max_line;                                 /* printer memory boundaries */
  75. int p_max_col;
  76. unsigned p_buf_size;
  77. char p_mode;                                                 /* printer mode */
  78.  
  79.  
  80.  
  81. boolean p_init (char p_m, int max_line, int max_col)
  82. {
  83.   p_buf_size = (max_col + 1) * (((max_line+1)/8) + 1); /* alloc print memory */
  84.   p_buf = malloc (p_buf_size);
  85.   if (p_buf != NULL)                   /* malloc () returns null if it fails */
  86.   {
  87.     p_max_line = max_line;                                /* set global vars */
  88.     p_max_col = max_col;
  89.     p_mode = p_m;
  90.     return (yes);
  91.   }
  92.   else
  93.     return (no);                     /* not enough memory for printer memory */
  94. }  /* p_init */
  95.  
  96.  
  97.  
  98. void p_load_chars ()                    /* load the character font from file */
  99. {                                          /* this file created by CHARGEN.C */
  100.   FILE *f;
  101.  
  102.   f = fopen ("PR_CHARS.DAT", "rb");
  103.   fread (p_chars, 0xb00, 1, f);
  104. }  /* p_load_chars */
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111. void p_clear_buf ()                                 /* clears printer memory */
  112. {
  113.   unsigned i;
  114.  
  115.   for (i=0; i<p_buf_size; i++)
  116.     *(p_buf+i) = 0;
  117. }  /* p_clear_buf */
  118.  
  119.  
  120.  
  121.  
  122. void p_draw_point (int col, int line, boolean fill)
  123. {
  124.   int i;               /* offset within memory for byte containing the point */
  125.   char mask;                                /* locates point within the byte */
  126.  
  127.   if ((col>=0) && (line>=0) && (col<=p_max_col) && (line<=p_max_line)) /* OK */
  128.   {
  129.     mask = 1 << (7 - (line % 8));
  130.     i = (line/8)*(p_max_col+1) + col;
  131.       if (fill)                                            /* draw the point */
  132.         *(p_buf+i)= *(p_buf+i) | mask;
  133.       else                                                /* erase the point */
  134.         *(p_buf+i) = *(p_buf+i) & ~mask;
  135.   }
  136.   else;                            /* do nothing - coordinates out of bounds */
  137. }  /* p_draw_point */
  138.  
  139.  
  140.  
  141.  
  142.  
  143. void p_big_point (int col, int line, boolean fill)
  144. {                                      /* draws point and its nine neighbors */
  145.   int i, j;
  146.  
  147.   for (i=col-1; i<=col+1; i++)
  148.     for (j=line-1; j<=line+1; j++)
  149.       p_draw_point (i, j, fill);
  150. }  /* p_big_point */
  151.  
  152.  
  153.  
  154.  
  155.  
  156.  
  157. void p_draw_line (int col1, int line1, int col2, int line2, boolean on)
  158. {                                 /* uses Bresenham algorithm to draw a line */
  159.   int dX, dY;                                           /* vector components */
  160.   int row, col,
  161.       final,                                   /* final row or column number */
  162.       G,                               /* used to test for new row or column */
  163.       inc1,                 /* G increment when row or column doesn't change */
  164.       inc2;                        /* G increment when row or column changes */
  165.   boolean pos_slope;
  166.  
  167.   dX = line2 - line1;                              /* find vector components */
  168.   dY = col2 - col1;
  169.   pos_slope = (dX > 0);                                /* is slope positive? */
  170.   if (dY < 0)
  171.     pos_slope = !pos_slope;
  172.   if (abs (dX) > abs (dY))                              /* shallow line case */
  173.   {
  174.     if (dX > 0)                     /* determine start point and last column */
  175.     {
  176.       col = line1;
  177.       row = col1;
  178.       final = line2;
  179.     }
  180.     else
  181.     {
  182.       col = line2;
  183.       row = col2;
  184.       final = line1;
  185.     }
  186.     inc1 = 2 * abs (dY);               /* determine increments and initial G */
  187.     G = inc1 - abs (dX);
  188.     inc2 = 2 * (abs (dY) - abs (dX));
  189.     if (pos_slope)
  190.       while (col <= final)      /* step through columns chacking for new row */
  191.       {
  192.         p_draw_point (row, col, on);
  193.         col++;
  194.         if (G >= 0)                              /* it's time to change rows */
  195.         {
  196.           row++;             /* positive slope so increment through the rows */
  197.           G += inc2;
  198.         }
  199.         else                                         /* stay at the same row */
  200.           G += inc1;
  201.       }
  202.     else
  203.       while (col <= final)      /* step through columns checking for new row */
  204.       {
  205.         p_draw_point (row, col, on);
  206.         col++;
  207.         if (G > 0)                               /* it's time to change rows */
  208.         {
  209.           row--;             /* negative slope so decrement through the rows */
  210.           G += inc2;
  211.         }
  212.         else                                         /* stay at the same row */
  213.           G += inc1;
  214.       }
  215.   }  /* if |dX| > |dY| */
  216.   else                                                    /* steep line case */
  217.   {
  218.     if (dY > 0)                        /* determine start point and last row */
  219.     {
  220.       col = line1;
  221.       row = col1;
  222.       final = col2;
  223.     }
  224.     else
  225.     {
  226.       col = line2;
  227.       row = col2;
  228.       final = col1;
  229.     }
  230.     inc1 = 2 * abs (dX);               /* determine increments and initial G */
  231.     G = inc1 - abs (dY);
  232.     inc2 = 2 * (abs (dX) - abs (dY));
  233.     if (pos_slope)
  234.       while (row <= final)      /* step through rows checking for new column */
  235.       {
  236.         p_draw_point (row, col, on);
  237.         row++;
  238.         if (G >= 0)                           /* it's time to change columns */
  239.         {
  240.           col++;          /* positive slope so increment through the columns */
  241.           G += inc2;
  242.         }
  243.         else                                      /* stay at the same column */
  244.           G += inc1;
  245.       }
  246.     else
  247.       while (row <= final)      /* step throuth rows checking for new column */
  248.       {
  249.         p_draw_point (row, col, on);
  250.         row++;
  251.         if (G > 0)                            /* it's time to change columns */
  252.         {
  253.           col--;          /* negative slope so decrement through the columns */
  254.           G += inc2;
  255.         }
  256.         else                                      /* stay at the same column */
  257.           G += inc1;
  258.       }
  259.   }
  260. }  /* p_draw_line */
  261.  
  262.  
  263.  
  264.  
  265.  
  266. void p_put_c (unsigned char ch, int col, int line, char direction)
  267. {
  268.   int r, c;
  269.  
  270.   switch (direction)
  271.   {
  272.     case E: for (r=0; r<11; r++)
  273.               for (c=0; c<8; c++)
  274.                 p_draw_point (col+r, line+c, p_chars [ch][r] & (1 << (7-c)));
  275.             break;
  276.     case W: for (r=0; r<11; r++)
  277.               for (c=0; c<8; c++)
  278.                 p_draw_point (col-r, line-c, p_chars [ch][r] & (1 << (7-c)));
  279.             break;
  280.     case N: for (r=0; r<11; r++)
  281.               for (c=0; c<8; c++)
  282.                 p_draw_point (col+c, line-r, p_chars [ch][r] & (1 << (7-c)));
  283.             break;
  284.     case S: for (r=0; r<11; r++)
  285.               for (c=0; c<8; c++)
  286.                 p_draw_point (col-c, line+r, p_chars [ch][r] & (1 << (7-c)));
  287.             break;
  288.   }  /* switch */
  289. }  /* p_put_c */
  290.  
  291.  
  292.  
  293.  
  294. void p_put_s (unsigned char str_out [80], int col, int line, char direction)
  295. {
  296.   int i;
  297.  
  298.   i = 0;
  299.   switch (direction)
  300.   {
  301.     case E: while (str_out [i] != '\0')
  302.             {
  303.               p_put_c (str_out [i], col, line + 9*i, E);
  304.               i++;
  305.             }
  306.             break;
  307.     case W: while (str_out [i] != '\0')
  308.             {
  309.               p_put_c (str_out [i], col, line - 9*i, W);
  310.               i++;
  311.             }
  312.             break;
  313.     case N: while (str_out [i] != '\0')
  314.             {
  315.               p_put_c (str_out [i], col + 9*i, line, N);
  316.               i++;
  317.             }
  318.             break;
  319.     case S: while (str_out [i] != '\0')
  320.             {
  321.               p_put_c (str_out [i], col - 9*i, line, S);
  322.               i++;
  323.             }
  324.             break;
  325.   }  /* switch */
  326. }  /* p_put_s */
  327.  
  328.  
  329.  
  330.  
  331. void p_print_buf ()                  /* print out contents of printer memory */
  332. {
  333.   int col, line, total_lines;
  334.  
  335.   total_lines = p_max_line/8 + 1;           /* # passes for the printer head */
  336.   prn_setup ();
  337.   for (line=0; line<total_lines; line++)
  338.   {
  339.     setup_gr_line (p_mode, p_max_col+1);
  340.     for (col=0; col<=p_max_col; col++)                 /* send graphics line */
  341.       prn_out (*(p_buf + (unsigned)(line*(p_max_col+1) + col)));
  342.     prn_out (10);                                                /* print it */
  343.   }
  344. }  /* p_print_buf */
  345.  
  346.  
  347.  
  348.  
  349.  
  350. void p_draw_border (int col1, int line1, int col2, int line2)
  351. {
  352.   p_draw_line (col1, line1, col2, line1, yes);
  353.   p_draw_line (col2, line1, col2, line2, yes);
  354.   p_draw_line (col2, line2, col1, line2, yes);
  355.   p_draw_line (col1, line2, col1, line1, yes);
  356. }  /* p_draw_border */
  357.  
  358.  
  359.  
  360.  
  361.  
  362. /* This function reads Hercules graphics page 0 and stuffs it in the printer
  363.    memory. Position the video graphics within the printer page using the two
  364.    offset parameters. Note that a line_ofs of 1 is really 8 printer lines. I
  365.    didn't want to fool with "uneven" line offsets. Be sure there's room for
  366.    the screen - the function doesn't check. */
  367.  
  368. void p_get_screen (int col_ofs, int line_ofs)
  369. {
  370.   unsigned buf_index;                  /* offset from base of printer memory */
  371.   int byte_ofs,                          /* offset from base of video memory */
  372.       vid_col, vid_row, blanks;
  373.  
  374.   blanks = p_max_col - v_max_row;    /* skip this much between video columns */
  375.   buf_index = line_ofs*(p_max_col + 1) + col_ofs; /*video starts filling here*/
  376.   for (vid_col=0; vid_col<v_max_col; vid_col+=8, buf_index+=blanks)
  377.     for (vid_row=v_max_row; vid_row>=0; vid_row--, buf_index++)
  378.     {
  379.       byte_ofs = 0x2000*(vid_row % 4) + 90*(vid_row/4) + (vid_col/8);
  380.       *(p_buf + buf_index) = peekb (herc_base, byte_ofs);  /*video to printer*/
  381.     }
  382. }  /* p_get_screen */
  383.  
  384.  
  385.  
  386.  
  387.  
  388. void p_draw_axis (plot *plt)              /* draw axis and print text labels */
  389. {
  390.   switch (plt->orientation)
  391.   {
  392.     case E: p_draw_line (plt->y_min, plt->x_min,
  393.                          plt->y_min, plt->x_min + plt->x_length, yes);
  394.             p_draw_line (plt->y_min, plt->x_min,
  395.                          plt->y_min + plt->y_length, plt->x_min, yes);
  396.             p_put_s (plt->x_label, plt->y_min-3*ch_size, plt->x_min+15, E);
  397.             p_put_s (plt->y_label, plt->y_min+15, plt->x_min-2*ch_size, N);
  398.             break;
  399.     case W: p_draw_line (plt->y_min, plt->x_min,
  400.                          plt->y_min, plt->x_min - plt->x_length, yes);
  401.             p_draw_line (plt->y_min, plt->x_min,
  402.                          plt->y_min - plt->y_length, plt->x_min, yes);
  403.             p_put_s (plt->x_label, plt->y_min+3*ch_size, plt->x_min-15, W);
  404.             p_put_s (plt->y_label, plt->y_min-15, plt->x_min+2*ch_size, S);
  405.             break;
  406.     case N: p_draw_line (plt->y_min, plt->x_min,
  407.                          plt->y_min, plt->x_min - plt->x_length, yes);
  408.             p_draw_line (plt->y_min, plt->x_min,
  409.                          plt->y_min + plt->y_length, plt->x_min, yes);
  410.             p_put_s (plt->x_label, plt->y_min+15, plt->x_min+3*ch_size, N);
  411.             p_put_s (plt->y_label, plt->y_min-2*ch_size, plt->x_min-15, W);
  412.             break;
  413.     case S: p_draw_line (plt->y_min, plt->x_min,
  414.                          plt->y_min, plt->x_min + plt->x_length, yes);
  415.             p_draw_line (plt->y_min, plt->x_min,
  416.                          plt->y_min - plt->y_length, plt->x_min, yes);
  417.             p_put_s (plt->x_label, plt->y_min-15, plt->x_min-3*ch_size, S);
  418.             p_put_s (plt->y_label, plt->y_min+2*ch_size, plt->x_min+15, E);
  419.             break;
  420.   }  /* switch */
  421. }  /* p_draw_axis */
  422.  
  423.  
  424.  
  425.  
  426.  
  427. void p_draw_scale (plot *plt)
  428. {
  429.   int x, y,                    /* current drawing location (x-east, y-north) */
  430.       x_label, y_label;                           /* incremental axis labels */
  431.   float xdata_span, ydata_span,   /* data range (float forces real division) */
  432.     dx, dy;                                           /* axis increments */
  433.   char temp [6];                       /* x_label and y_label in string form */
  434.  
  435.   xdata_span = plt->xdata_max - plt->xdata_min;           /* find data range */
  436.   ydata_span = plt->ydata_max - plt->ydata_min;
  437.   dx = (plt->x_step/xdata_span) * plt->x_length + 0.5; /*find axis increments*/
  438.   dy = (plt->y_step/ydata_span) * plt->y_length + 0.5;
  439.   switch (plt->orientation)
  440.   {
  441.     case E: x = plt->x_min;                                /* initial values */
  442.             x_label = plt->xdata_min;
  443.             while (x <= plt->x_min + plt->x_length)
  444.             {
  445.               p_draw_point (plt->y_min - 1, x, yes);  /* draw "tick" on axis */
  446.               p_draw_point (plt->y_min - 2, x, yes);
  447.               itoa (x_label, temp, 10);      /* convert tick label to string */
  448.               p_put_s (temp, plt->y_min - 16, x - 4, E);   /* label the tick */
  449.               x_label += plt->x_step;                /* set up for next tick */
  450.               x += dx;
  451.             }
  452.             y = plt->y_min;                               /* same for y-axis */
  453.             y_label = plt->ydata_min;
  454.             while (y <= plt->y_min + plt->y_length)
  455.             {
  456.               p_draw_point (y, plt->x_min - 1, yes);
  457.               p_draw_point (y, plt->x_min - 2, yes);
  458.               itoa (y_label, temp, 10);
  459.               p_put_s (temp, y - 4, plt->x_min - 5, N);
  460.               y_label += plt->y_step;
  461.               y += dy;
  462.             }
  463.             break;
  464.     case W: x = plt->x_min;                                /* initial values */
  465.             x_label = plt->xdata_min;
  466.             while (x >= plt->x_min - plt->x_length)
  467.             {
  468.               p_draw_point (plt->y_min + 1, x, yes);  /* draw "tick" on axis */
  469.               p_draw_point (plt->y_min + 2, x, yes);
  470.               itoa (x_label, temp, 10);      /* convert tick label to string */
  471.               p_put_s (temp, plt->y_min + 16, x + 4, W);   /* label the tick */
  472.               x_label += plt->x_step;                /* set up for next tick */
  473.               x -= dx;
  474.             }
  475.             y = plt->y_min;                               /* same for y-axis */
  476.             y_label = plt->ydata_min;
  477.             while (y >= plt->y_min - plt->y_length)
  478.             {
  479.               p_draw_point (y, plt->x_min + 1, yes);
  480.               p_draw_point (y, plt->x_min + 2, yes);
  481.               itoa (y_label, temp, 10);
  482.               p_put_s (temp, y + 4, plt->x_min + 5, S);
  483.               y_label += plt->y_step;
  484.               y -= dy;
  485.             }
  486.             break;
  487.     case N: y = plt->y_min;                                /* initial values */
  488.             x_label = plt->xdata_min;
  489.             while (y <= plt->y_min + plt->x_length)
  490.             {
  491.               p_draw_point (y, plt->x_min + 1, yes);  /* draw "tick" on axis */
  492.               p_draw_point (y, plt->x_min + 2, yes);
  493.               itoa (x_label, temp, 10);      /* convert tick label to string */
  494.              p_put_s (temp, y - 4, plt->x_min + 16, N);   /* label the tick */
  495.               x_label += plt->x_step;                /* set up for next tick */
  496.               y += dx;
  497.             }
  498.             x = plt->x_min;                               /* same for y-axis */
  499.             y_label = plt->ydata_min;
  500.             while (x >= plt->x_min - plt->y_length)
  501.             {
  502.               p_draw_point (plt->y_min - 1, x, yes);
  503.               p_draw_point (plt->y_min - 2, x, yes);
  504.               itoa (y_label, temp, 10);
  505.               p_put_s (temp, plt->y_min - 5, x + 4, W);
  506.               y_label += plt->y_step;
  507.               x -= dy;
  508.             }
  509.             break;
  510.     case S: y = plt->y_min;                                /* initial values */
  511.             x_label = plt->xdata_min;
  512.             while (y >= plt->y_min - plt->x_length)
  513.             {
  514.               p_draw_point (y, plt->x_min - 1, yes);  /* draw "tick" on axis */
  515.               p_draw_point (y, plt->x_min - 2, yes);
  516.               itoa (x_label, temp, 10);      /* convert tick label to string */
  517.               p_put_s (temp, y + 4, plt->x_min - 16, S);   /* label the tick */
  518.               x_label += plt->x_step;                /* set up for next tick */
  519.               y -= dx;
  520.             }
  521.             x = plt->x_min;                               /* same for y-axis */
  522.             y_label = plt->ydata_min;
  523.             while (x <= plt->x_min + plt->y_length)
  524.             {
  525.               p_draw_point (plt->y_min + 1, x, yes);
  526.               p_draw_point (plt->y_min + 2, x, yes);
  527.               itoa (y_label, temp, 10);
  528.               p_put_s (temp, plt->y_min + 5, x - 4, E);
  529.               y_label += plt->y_step;
  530.               x += dy;
  531.             }
  532.             break;
  533.   }  /* switch */
  534. }  /* p_draw_scale */
  535.  
  536.  
  537.  
  538.  
  539. void p_draw_data (plot *plt)
  540. {
  541.   int i;
  542.   float xdata_span, ydata_span;   /* data range (float forces real division) */
  543.  
  544.   xdata_span = plt->xdata_max - plt->xdata_min;           /* find data range */
  545.   ydata_span = plt->ydata_max - plt->ydata_min;
  546.   switch (plt->orientation)
  547.   {
  548.     case E: for (i=1; i<=plt->points [0][0]; i++)     /* 0,0 has # of points */
  549.               p_big_point (plt->y_min +
  550.                            (plt->points [1][i]/ydata_span)*plt->y_length + 0.5,
  551.                            plt->x_min +
  552.                            (plt->points [0][i]/xdata_span)*plt->x_length + 0.5,
  553.                            yes);
  554.             break;
  555.     case W: for (i=1; i<=plt->points [0][0]; i++)     /* 0,0 has # of points */
  556.               p_big_point (plt->y_min -
  557.                            (plt->points [1][i]/ydata_span)*plt->y_length + 0.5,
  558.                            plt->x_min -
  559.                            (plt->points [0][i]/xdata_span)*plt->x_length + 0.5,
  560.                            yes);
  561.             break;
  562.     case N: for (i=1; i<=plt->points [0][0]; i++)     /* 0,0 has # of points */
  563.               p_big_point (plt->y_min +
  564.                            (plt->points [1][i]/ydata_span)*plt->y_length + 0.5,
  565.                            plt->x_min -
  566.                            (plt->points [0][i]/xdata_span)*plt->x_length + 0.5,
  567.                            yes);
  568.             break;
  569.     case S: for (i=1; i<=plt->points [0][0]; i++)     /* 0,0 has # of points */
  570.               p_big_point (plt->y_min -
  571.                            (plt->points [1][i]/ydata_span)*plt->y_length + 0.5,
  572.                            plt->x_min +
  573.                            (plt->points [0][i]/xdata_span)*plt->x_length + 0.5,
  574.                            yes);
  575.             break;
  576.   }  /* switch */
  577. }  /* p_draw_data */
  578.  
  579.  
  580.  
  581.  
  582. void p_draw_plot (plot *plt)
  583. {
  584.   p_draw_axis (plt);
  585.   p_draw_scale (plt);
  586.   p_draw_data (plt);
  587. }  /* p_draw_plt */
  588.  
  589.  
  590.  
  591.  
  592.  
  593. void graph_test ()                                   /* example of graph use */
  594. {                                    /* use 705 x 470 in p_init call in main */
  595.   int i;
  596.   plot *p;
  597.  
  598.   p = (plot *) malloc (sizeof (plot));           /* get memory for structure */
  599.   p->orientation = E;                               /* load structure values */
  600.   p->x_min = 35;  p->x_length = p_max_line - p->x_min - 25;
  601.   p->y_min = 35;  p->y_length = p_max_col - p->y_min - 25;
  602.   strcpy (p->x_label, "Sample PR-GRAPH Output - (X)");
  603.   strcpy (p->y_label, "150+100*sin(X/4)");
  604.   p->xdata_min = 0;  p->xdata_max = 100;
  605.   p->ydata_min = 0;  p->ydata_max = 300;
  606.   p->x_step = 20;
  607.   p->y_step = 100;
  608.   p->points [0][0] = 99;               /* element 0,0 holds # of data points */
  609.   for (i=1; i<=99; i++)                                   /* load data array */
  610.   {
  611.     p->points [0][i] = i;                                         /* x value */
  612.     p->points [1][i] = 150 + 100*sin(i/4.0);                      /* y value */
  613.   }
  614.   p_draw_plot (p);                                           /* do the graph */
  615.   p_draw_border (0, 0, p_max_col, p_max_line);
  616.   p_print_buf ();                                                /* print it */
  617. }  /* graph_test */
  618.  
  619.  
  620.  
  621.  
  622.  
  623. void graph_test4 ()                    /* example of four graph orientations */
  624. {                                    /* use 450 x 450 in p_init call in main */
  625.   int i;
  626.   plot *p;
  627.  
  628.   p = (plot *) malloc (sizeof (plot));           /* get memory for structure */
  629.  
  630.   p->orientation = E;                    /* load structure values for E plot */
  631.   p->x_min = 275;  p->x_length = 150;
  632.   p->y_min = 275;  p->y_length = 150;
  633.   strcpy (p->x_label, "EAST X-axis");
  634.   strcpy (p->y_label, "EAST Y-axis");
  635.   p->xdata_min = 0;  p->xdata_max = 10;
  636.   p->ydata_min = 0;  p->ydata_max = 100;
  637.   p->x_step = 2;
  638.   p->y_step = 25;
  639.   p->points [0][0] = 10;               /* element 0,0 holds # of data points */
  640.   for (i=1; i<=10; i++)                                   /* load data array */
  641.   {
  642.     p->points [0][i] = i;                                         /* x value */
  643.     p->points [1][i] = 10*i;                                      /* y value */
  644.   }
  645.   p_draw_plot (p);                                           /* do the graph */
  646.  
  647.   p->orientation = W;                                   /* load new W values */
  648.   p->x_min = 175;
  649.   p->y_min = 175;
  650.   strcpy (p->x_label, "WEST X-axis");
  651.   strcpy (p->y_label, "WEST Y-axis");
  652.   p_draw_plot (p);                                           /* do the graph */
  653.  
  654.   p->orientation = N;                                   /* load new N values */
  655.   p->x_min = 175;
  656.   p->y_min = 275;
  657.   strcpy (p->x_label, "NORTH X-axis");
  658.   strcpy (p->y_label, "NORTH Y-axis");
  659.   p_draw_plot (p);                                           /* do the graph */
  660.  
  661.   p->orientation = S;                                   /* load new S values */
  662.   p->x_min = 275;
  663.   p->y_min = 175;
  664.   strcpy (p->x_label, "SOUTH X-axis");
  665.   strcpy (p->y_label, "SOUTH Y-axis");
  666.   p_draw_plot (p);                                           /* do the graph */
  667.  
  668.   p_draw_border (0, 0, p_max_col, p_max_line);
  669.   p_print_buf ();                                                /* print it */
  670. }  /* graph_test4 */
  671.  
  672.  
  673.  
  674.  
  675.  
  676. main ()
  677. {
  678.   if (p_init (75, 450, 450))
  679.   {
  680.     p_clear_buf ();
  681.     p_load_chars ();
  682. /*    graph_test ();*/
  683.     graph_test4 ();
  684.   }
  685.   else
  686.     printf ("\n\n  Not enough memory ...\n\n");
  687.   free (p_buf);                                   /* retreive printer memory */
  688. }
  689.  
  690.