home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Science / Science.zip / imdisp79.zip / PLOT.C < prev    next >
C/C++ Source or Header  |  1993-02-15  |  41KB  |  1,324 lines

  1. /***  IMDISP module PLOT.C
  2.  
  3.         PLOT contains the routines for plotting spectra and lines from
  4.     images.  It was originally written by Ed Esfandari to support the
  5.     International Halley Watch CD-ROM.  This module was extensively
  6.     modified and moderately tested by:
  7.  
  8.           A. Warnock
  9.           ST Systems Corp
  10.           Mail Code 681
  11.           NASA/Goddard Space Flight Center
  12.           Greenbelt, MD.
  13.  
  14.      All bugs contained herein are mine and mine alone.
  15.  
  16. ***/
  17.  
  18. #define __MSC
  19.  
  20. /* * * * INCLUDE files * * * */
  21.  
  22. #include <conio.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <malloc.h>
  27. #include "mshell.h"
  28. #include "imdef.h"
  29. #include "dispio.h"
  30. #include "imdisp.h"
  31. #include "imdutil.h"
  32. #include "imageio.h"
  33. #include "disputil.h"
  34. #include "keywutil.h"
  35. #include "textutil.h"
  36. #include "refresh.h"
  37. #include "plot.h"
  38. #include "spectra.h"
  39.  
  40. /* * * * External functions * * * */
  41.  
  42. /* * * * Function declarations * * * */
  43.  
  44. void Plot32 (long *, long, long, int, int, char *, int, int, int, int, int,
  45.              int, char);
  46. void Plot8 (unsigned char *, unsigned char, unsigned char, int, char *,
  47.             int, int, int, int, int, int, char);
  48. void Plotpair (long *, long *, long, long, long, long, int, char *, int, int);
  49. long min3arr (long *, int);
  50. long max3arr (long *, int);
  51. int  DoPlot (void);
  52. int  DoPerspect (void);
  53. void FramePlot (int, int, int, int, long, long, long, long);
  54. void NewZoomEndpoints( int *, int *, int *, int *, int, int, int, int);
  55. long screen_to_DN_y (int);
  56. int  DN_to_screen_y (long);
  57.  
  58. /* * * * Global Variables * * * */
  59.  
  60. extern Spectrum    baseliner;
  61. extern float       slope, intercept;
  62. extern Plot        ThePlot;
  63.  
  64. float scale_ydata_to_screen;
  65. long  y_min;
  66. int   lowedge;
  67.  
  68. long screen_to_DN_y( int y_screen)
  69. {
  70.     return( (long) ( (float) (lowedge - y_screen) / scale_ydata_to_screen) + y_min);
  71. }
  72.  
  73. int  DN_to_screen_y( long y_DN)
  74. {
  75.     return( lowedge - (int) ((float)(y_DN - y_min) * scale_ydata_to_screen));
  76. }
  77.  
  78. void Plot32( long * buf, long miny, long maxy, int start, int len, char * symbol,
  79.              int color_flag, int top, int bottom, int left, int right,
  80.              int zoom, char Overlay)
  81.  
  82. /***  Plot32 plots a single array of 32-bit y-values against a running
  83.       index on the x-axis.  The code provides for zooming in on a region
  84.       of interest, plotting with dots or lines and plotting in different
  85.       colors.
  86.  
  87.       Original version - 3/31/89 AEE
  88.       Modified version - 8/90 AW3
  89.  
  90.    Parameter    Type    In/out   Description
  91.       buf     long ptr   in      The buffer containing the y data
  92.       miny      long     in      The minimum y value to plot
  93.       maxy      long     in      The maximum y value to plot
  94.      start      int      in      The subscript of the first point in the array
  95.       len       int      in      The number of points in the y array
  96.      symbol     char     in      Plotting symbol flag: 'D' for dots
  97.                                     anything else for line
  98.    color_flag   int      in      Plotting color (index into current pal
  99.                                  or -1 if variable colors)
  100.       zoom      int      in      Zoom flag:  0 if no zooming this time
  101.                                              1 if zooming desired (i.e., ask)
  102.     Overlay     char     in      Overlay flag - 'Y' to overlay plot,
  103.                                                 'N' to redraw whole thing
  104.  
  105. ***/
  106. {
  107.     int            i, j, yaxisrev;
  108.     int            adjval, nextx, prevy, prevx;
  109.     int            ycoord, leftedge;
  110.     int            line1, samp1, line2, samp2, line, samp;
  111.     int            wave_flag, string_len;
  112.     int            height, width, end;
  113.     int            tic, numbins;
  114.     int            color;
  115.     long           minx, maxx, hold_minx, hold_maxx;
  116.     char           ch='N', dispstr[64];
  117.     float          scale_color;
  118.     float          pixperbin, yrange;
  119.  
  120. /*  Find the actual starting and ending X values from the header, if
  121.     present */
  122.  
  123.     if (xflag)
  124.     {
  125.         minx = (long) xstart;
  126.         maxx = (long)(xstart + (len * xinterval));
  127.     }
  128.     else
  129.     {
  130.         xstart = (float) start;
  131.         xinterval = 1.0 / len;
  132.         minx = (long) start;
  133.         maxx = (long)(len - 1);
  134.     }
  135.     end = len - start - 1;
  136.     hold_minx = minx;
  137.     hold_maxx = maxx;
  138.     ThePlot.X.start = xstart;
  139.     ThePlot.X.interval = xinterval;
  140.  
  141. /*  Set display sizes in units of screen pixels */
  142.     height    = bottom - top;
  143.     width     = right - left;
  144.     right     = left + width;            /* reset right edge */
  145.     numbins   = width;
  146.     pixperbin = (float)len / numbins;
  147.     tic = (numbins / 16) * pixperbin;
  148.     if (color_flag >= 0)
  149.        color = color_flag;
  150.  
  151.     ThePlot.Y.parms.range_s = height;
  152.     ThePlot.Y.parms.low_s = bottom;
  153.     ThePlot.Y.parms.high_s = top;
  154.     ThePlot.Y.parms.low_DN = miny;
  155.     ThePlot.Y.parms.high_DN = maxy;
  156.  
  157.     ThePlot.X.parms.range_s = width;
  158.     ThePlot.X.parms.low_s = left;
  159.     ThePlot.X.parms.high_s = right;
  160.     ThePlot.X.parms.range_DN = len - start;
  161.     ThePlot.X.parms.low_DN = start;
  162.     ThePlot.X.parms.high_DN = len;
  163.     y_min = miny;
  164.  
  165. /*  Top of the plotting loop - do this until no more zooming */
  166.     while (zoom >= 0)
  167.     {
  168.        yrange = (float) (maxy - y_min) ;
  169.        ThePlot.Y.parms.range_DN = maxy - y_min;
  170.        if (ThePlot.Y.parms.range_DN != 0)
  171.        {
  172.           scale_ydata_to_screen = ( (float) height) / yrange;
  173.           ThePlot.Y.scale.DN_to_s = scale_ydata_to_screen;
  174.           scale_color = ( (float) numDN) / yrange ;
  175.        }
  176.  
  177.        if (Overlay != 'Y')
  178.        {
  179.            FramePlot( top, bottom, left, right, minx, maxx, y_min, maxy);
  180.        }
  181.  
  182. /*  Set the starting points for the plot */
  183.        lowedge = bottom;
  184.        leftedge= left;
  185.        prevy   = max( buf[0], y_min);
  186.        prevy   = DN_to_screen_y (prevy);
  187. /*
  188.        prevy   = lowedge - ( (int) (((float) (prevy - miny)) * scale_ydata_to_screen));
  189. */
  190.        prevx   = left;
  191.  
  192. /*  Loop over the points in the y array */
  193.        for (i=start; i<start+len; i++)
  194.        {
  195.           if(buf[i] <= maxy && buf[i] >= y_min)
  196.           {
  197.  
  198.           /* adjval to fall in plot range */
  199.               ycoord = DN_to_screen_y (buf[i]);
  200. /*
  201.               adjval = (int) (((float) (buf[i]-miny)) * scale_ydata_to_screen);
  202. */
  203.               if (color_flag == -1)
  204.                   color = (int) (((float) (buf[i]-y_min)) * scale_color);
  205.  
  206.  
  207.           /* make y-axis increase upward */
  208. /*              ycoord = lowedge - adjval; */
  209.  
  210.           /* scales the length of X-axis (samples) correctly */
  211.               nextx = leftedge + (int) ((i-start) * ((float)width/len));
  212.  
  213.           /* plot the next point */
  214.  
  215.               if (strlen(symbol) == 0)
  216.               {
  217.               /* use lines; connect the points */
  218.                   DrawLine(prevy, prevx, ycoord, nextx, color);
  219.                   prevy = ycoord;
  220.                   prevx = nextx;
  221.               }
  222.               else if (strstr(symbol, ".") != NULL)
  223.                   WritePixel(ycoord, nextx, color);
  224.               else
  225.                   DrawText(symbol, ycoord, nextx, 8, 0, color);
  226.           }
  227.        }
  228.  
  229.        if (zoom == 2) /* We've already zoomed once */
  230.        {
  231.           DrawText("Would you like to zoom again (y/n)?  ",10,1,8,0,numDN-1);
  232.           ch = getch();
  233.        }
  234.  
  235.        if (zoom == 1) /* We haven't zoomed, and we want to */
  236.        {
  237.           ch   = 'Y';
  238.           zoom = 2;
  239.        }
  240.  
  241.        /*  Either way, find the new endpoints and redraw the plot */
  242.        if (ch == 'y' || ch == 'Y')
  243.        {
  244.           /* clears the prompt line */
  245.           DrawText("Would you like to zoom again (y/n)?  ", 10, 1, 8, 0, 0);
  246.  
  247.           NewZoomEndpoints(&line1, &samp1, &line2, &samp2, left, right,
  248.                             width, bottom);
  249.  
  250.           /* set the new starting points */
  251.           start = minx + (samp1-left) *  ((float) len /(float)width);
  252.           start = max( start, minx);
  253.           end   = minx + (samp2-left) *  ((float) len /(float)width);
  254.           end   = min( end, maxx);
  255.           len   = end - start + 1;
  256.  
  257.           /* find the array indexes for the new starting points */
  258.  
  259.           if(len > 0)
  260.           {
  261.           /* X-axis range selected is > 0 */
  262.               minx = start;
  263.               maxx = end;
  264.               y_min = 0x7fffffff;
  265.               maxy = 0x80000000;
  266.  
  267.           /* new min and max for the plot */
  268.               for (i= start; i<start+len; i++)
  269.               {
  270.                   if (buf[i] < y_min)
  271.                       y_min= buf[i];
  272.                   if (buf[i] > maxy)
  273.                       maxy= buf[i];
  274.               }
  275.               prevy = DN_to_screen_y (buf[start]);
  276. /*
  277.               prevy= lowedge - ((int) (((float) (buf[start] - miny)) * scale_ydata_to_screen));
  278. */
  279.               prevx= leftedge;
  280.           }
  281.           else
  282.           {
  283.           /* selected X range is zero */
  284.               zoom = -1;
  285.           }
  286. /*
  287.           minx= (long) (xstart + (float) (minx) * xinterval - xinterval);
  288.           maxx= (long) (xstart + (float) (maxx) * xinterval);
  289. */
  290.  
  291.        }
  292.        else
  293.            zoom = -1;
  294.     }
  295.  
  296.     if (baseliner.DoBaseline == 'Y')
  297.     {
  298.        DoSpect(start, len, left, right, buf);
  299.     }
  300.  
  301. } /* end plot32 */
  302.  
  303. void Plot8( unsigned char * buf, unsigned char miny, unsigned char maxy,
  304.             int len, char * symbol, int color_flag, int top, int bottom,
  305.             int left, int right, int zoom, char Overlay)
  306.  
  307. /***  Plot8 plots a single array of 8-bit y-values against a running
  308.       index on the x-axis.  The code provides for zooming in on a region
  309.       of interest, plotting with dots or lines and plotting in different
  310.       colors.
  311.  
  312.       Original version - 3/31/89 AEE
  313.       Modified version - 8/90 AW3
  314.  
  315.    Parameter    Type    In/out   Description
  316.       buf    uns ch ptr  in      The buffer containing the y data
  317.       miny    uns char   in      The minimum y value to plot
  318.       maxy    uns char   in      The maximum y value to plot
  319.       len       int      in      The number of points in the y array
  320.      symbol     char     in      Plotting symbol flag: 'D' for dots
  321.                                     anything else for line
  322.    color_flag   int      in      Plotting color (index into current pal
  323.                                  or -1 if variable colors)
  324.       zoom      int      in      Zoom flag:  0 if no zooming this time
  325.                                              1 if zooming desired (i.e., ask)
  326.     Overlay     char     in      Overlay flag - 'Y' to overlay plot,
  327.                                                 'N' to redraw whole thing
  328.  
  329. ***/
  330. {
  331.     int    i, j, yaxisrev;
  332.     int    adjval, leftedge, nextx, lowedge, ycord, prevy, prevx;
  333.     int    line1, samp1, line2, samp2, line, samp;
  334.     int    start = 0, tmplen = len, tmpdn = numDN;
  335.     int    wave_flag, string_len;
  336.     int    height, width;
  337.     int    num_Xtics=16, num_Ytics=10, num_Xlabels=8, num_Ylabels=5;
  338.     int    tic, tic_height=5, numbins;
  339.     int    color;
  340.     long   minx, maxx;
  341.     long   tmpminy = miny, tmpmaxy = maxy;
  342.     long   tmpminx = minx, tmpmaxx = maxx;
  343.     char   bufmin[15], bufmax[15], xbufmin[15], xbufmax[15];
  344.     char   ch='N', dispstr[64];
  345.     int    scale_ydata;
  346.     int    scale_color;
  347.     int    yrange;
  348.     float  pixperbin;
  349.  
  350. /*  Find the actual starting and ending X values from the header, if
  351.     present */
  352.  
  353.     minx = (long) xstart;
  354.     maxx = minx + (long)(len * xinterval);
  355.  
  356. /*  Set display sizes in units of screen pixels */
  357.     height    = bottom - top;
  358.     width     = right - left;
  359.     right     = left + width;            /* reset right edge */
  360.     numbins   = width;
  361.     pixperbin = (float)len / numbins;
  362.     tic = (numbins / 16) * pixperbin;
  363.     tic_height = dispnl / 100;
  364.     if (color_flag >= 0)
  365.        color = color_flag;
  366.  
  367.  
  368. /*  Top of the plotting loop - do this until no more zooming */
  369.     while (zoom >= 0)
  370.     {
  371.        yrange = maxy - miny;
  372.        if (yrange != 0)
  373.        {
  374.            scale_ydata = (100 * height) / yrange;
  375.            scale_color = (100 * numDN) / yrange ;
  376.        }
  377.        else
  378.        {
  379.            scale_ydata = 1;
  380.            scale_color = 1;
  381.        }
  382.  
  383.        if (Overlay != 'Y')
  384.        {
  385.            FramePlot( top, bottom, left, right, minx, maxx, miny, maxy);
  386.        }
  387.  
  388. /*  Set the starting points for the plot */
  389.        lowedge = bottom;
  390.        leftedge= left;
  391.        prevy   = max( buf[0], miny);
  392.        prevy   = lowedge - ((prevy - miny) * scale_ydata)/100;
  393.        prevx   = left;
  394.  
  395. /*  Loop over the points in the y array */
  396.        for (i=start; i<start+len; i++)
  397.        {
  398.           if(buf[i] <= maxy && buf[i] >= miny)
  399.           {
  400.  
  401.           /* adjval to fall in plot range */
  402.               adjval = (buf[i]-miny) * scale_ydata/100;
  403.               if (color_flag == -1)
  404.                   color = (buf[i]-miny) * scale_color/100;
  405.  
  406.  
  407.           /* make y-axis increase upward */
  408.               ycord = lowedge - adjval;
  409.  
  410.           /* scales the length of X-axis (samples) correctly */
  411.               nextx = leftedge + ( ((long)(i-start) * (long)width) / len);
  412.  
  413.           /* plot the next point */
  414.  
  415.               if (strlen(symbol) == 0)
  416.               {
  417.               /* use lines; connect the points */
  418.                   DrawLine(prevy, prevx, ycord, nextx, color);
  419.                   prevy = ycord;
  420.                   prevx = nextx;
  421.               }
  422.               else if (strstr(symbol, ".") != NULL)
  423.                   WritePixel(ycord, nextx, color);
  424.               else
  425.                   DrawText(symbol, ycord, nextx, 8, 0, color);
  426.           }
  427.        }
  428.  
  429.        if (zoom == 2) /* We've already zoomed once */
  430.        {
  431.           minx  = tmpminx;
  432.           miny  = tmpminy;
  433.           maxx  = tmpmaxx;
  434.           maxy  = tmpmaxy;
  435.           len   = tmplen;
  436.           start = 0;
  437.           numDN = tmpdn;
  438.           DrawText("Would you like to zoom again (y/n)?  ",10,1,8,0,numDN-1);
  439.           ch = getch();
  440.        }
  441.  
  442.        if (zoom == 1) /* We haven't zoomed, and we want to */
  443.        {
  444.           ch   = 'Y';
  445.           zoom = 2;
  446.        }
  447.  
  448.        /*  Either way, find the new endpoints and redraw the plot */
  449.        if (ch == 'y' || ch == 'Y')
  450.        {
  451.           /* clears the prompt line */
  452.           DrawText("Would you like to zoom again (y/n)?  ", 10, 1, 8, 0, 0);
  453.  
  454.           /* select the endpoints of the zoom */
  455.           DrawText("   Arrow keys move + around. +,- (in/de)crements cursor steps.",
  456.                        10, 1, 8, 0,numDN-1);
  457.  
  458.           LengthText("Hit Return to Select End Points", 8, &string_len);
  459.           DrawText("Hit Return to Select End Points",
  460.                        dispnl-10, left+(width-string_len)/2, 8, 0, numDN-1);
  461.  
  462.           PlaceCursor(bottom+6, right/2, numDN-1);
  463.           MoveCursor(&line1, &samp1);
  464.           DrawText("*", line1+4, samp1-4, 8, 0, numDN-1);
  465.  
  466.           MoveCursor(&line2, &samp2);
  467.           DrawText("*", line2+4, samp2-4, 8, 0, numDN-1);
  468.  
  469.           /* clean up the screen */
  470.           RemoveCursor();
  471.           ClearDisplay(0);
  472.  
  473.           /* watch for reversed endpoints */
  474.           if (samp1 > samp2)
  475.           {
  476.               i     = samp2;
  477.               samp2 = samp1;
  478.               samp1 = i;
  479.           }
  480.  
  481.           /* watch for values off the plot */
  482.           if (samp1 < left)
  483.               samp1 = left;
  484.           if (samp2 > right)
  485.               samp2 = right;
  486.           if (samp2 < left)
  487.               samp2 = left;   /* both end points < minx of plot */
  488.           if (samp1 > right)
  489.               samp1 = right;  /* both end points > maxx of plot */
  490.  
  491.           /* set the new starting points */
  492.           start = ((long)(samp1 - left) * (long)len) / width;
  493.           len   = ((long)(samp2 -samp1) * (long)len) / width;
  494.  
  495.           if(len > 0)
  496.           {
  497.           /* X-axis range selected is > 0 */
  498.               minx = start+1;
  499.               maxx = len+start;
  500.               miny = 0x7fffffff;
  501.               maxy = 0x80000000;
  502.  
  503.           /* new min and max for the plot */
  504.               for (i= start; i<start+len; i++)
  505.               {
  506.                   if (buf[i] < miny)
  507.                       miny= buf[i];
  508.                   if (buf[i] > maxy)
  509.                       maxy= buf[i];
  510.               }
  511.               prevy= lowedge - ((buf[start] - miny) * scale_ydata)/100;
  512.               prevx= leftedge;
  513.           }
  514.           else
  515.           {
  516.           /* selected X range is zero */
  517.               zoom = -1;
  518.           }
  519.  
  520.           minx= (long) (xstart + (float) (minx) * xinterval - xinterval);
  521.           maxx= (long) (xstart + (float) (maxx) * xinterval);
  522.  
  523.  
  524.        }
  525.        else
  526.            zoom = -1;
  527.     }
  528.  
  529.     if (baseliner.DoBaseline == 'Y')
  530.     {
  531.        DoSpect(start, len, left, right, (long *) buf);
  532.     }
  533.  
  534. } /* end plot8 */
  535.  
  536.  
  537. void Plotpair(long * xbuf, long * ybuf, long minx, long maxx, long miny,
  538.              long maxy, int len, char * symbol, int color, int zoom)
  539.  
  540. /***  PlotPair plots two arrays of 32-bit values against each other.  The
  541.       code provides for zooming in on a region of interest, plotting
  542.       with dots or lines and plotting in different colors.
  543.  
  544.       Original version - 3/31/89 AEE
  545.       Modified version - 8/90 AW3
  546.  
  547.    Parameter    Type    In/out   Description
  548.       xbuf    long ptr   in      The buffer containing the x data
  549.       ybuf    long ptr   in      The buffer containing the y data
  550.       miny      long     in      The minimum y value to plot
  551.       maxy      long     in      The maximum y value to plot
  552.       len       int      in      The number of points in the y array
  553.      symbol     char     in      Plotting symbol flag: 'D' for dots
  554.                                     anything else for line
  555.       color     int      in      Plotting color (index into current pal)
  556.       zoom      int      in      Zoom flag:  0 if no zooming this time
  557.                                    1 if zooming desired (i.e., ask)
  558.  
  559. ***/
  560. {
  561.     int            i, j, yaxisrev;
  562.     int            adjval, leftedge, nextx, lowedge, ycord, prevy, prevx;
  563.     int            line1, samp1, line2, samp2, line, samp;
  564.     int            start = 0, x_right, x_width;
  565.     int            tmplen = len, tmpdn = numDN;
  566.     long           tmpminy = miny, tmpmaxy = maxy;
  567.     long           tmpminx = minx, tmpmaxx = maxx;
  568.     char           ybufmin[15], ybufmax[15], xbufmin[15], xbufmax[15];
  569.     float          scale_xdata_to_screen;
  570.     float          yrange, xrange;
  571.     char           ch='N', dispstr[64];
  572.     int            wave_flag, string_len;
  573.     int            top, bottom, left, right, height, width;
  574.     int            num_Xtics=16, num_Ytics=10, num_Xlabels=8, num_Ylabels=5;
  575.     int            tic, tic_height=5, numbins;
  576.     float          pixperbin;
  577.  
  578.     top        = dispnl / 10;
  579.     bottom     = dispnl - top;
  580.     left       = dispns / 10;
  581.     right      = dispns - (dispns / 32);
  582.     height     = bottom - top;
  583.     width      = right - left;
  584.     right      = left + width;            /* reset right edge */
  585.     numbins    = width;
  586.     pixperbin  = (float)len / numbins;
  587.     tic        = (numbins / 16) * pixperbin;
  588.     tic_height = dispnl / 100;
  589.  
  590.  
  591.     while (zoom >= 0)
  592.     {
  593.        yrange = (float) (maxy - miny) ;
  594.        if (yrange != 0)
  595.           scale_ydata_to_screen = ( (float) height) / yrange;
  596.  
  597.        xrange= (float) (maxx - minx);
  598.        if (xrange != 0)
  599.           scale_xdata_to_screen= ((float) width)/xrange;
  600.  
  601.            FramePlot( top, bottom, left, right, minx, maxx, miny, maxy);
  602.        /* draw box outline */
  603. /*       FrameBox( top, left, bottom, right, numDN-1, TRUE); */
  604.  
  605.        /* Put in the tic marks */
  606. /*       for (i = 0;  i <= num_Xtics;  i++)
  607.        {
  608.            j = left + width*i/num_Xtics;
  609.            DrawLine (bottom, j, bottom-tic_height, j, numDN-1);
  610.        }
  611.  
  612.        for (i = 0;  i <= num_Ytics;  i++)
  613.        {
  614.            j = bottom - height*i/num_Ytics;
  615.            DrawLine (j, left, j, left-tic_height, numDN-1);
  616.        }
  617. */
  618.        /* write coordinates */
  619. /*
  620.        sprintf(ybufmin, "%10.2G", (float)miny);
  621.        LengthText(ybufmin, 6, &string_len);
  622.        string_len = string_len + tic_height + 2;
  623.        DrawText(ybufmin, bottom+5, left-string_len, 6, 0, numDN-1);
  624.  
  625.        sprintf(ybufmax, "%10.2G", (float)maxy);
  626.        LengthText(ybufmax, 6, &string_len);
  627.        string_len = string_len + tic_height + 2;
  628.        DrawText(ybufmax, bottom-height+5, left-string_len, 6, 0, numDN-1);
  629.  
  630.        sprintf(xbufmin, "%ld", minx);
  631.        LengthText(xbufmin, 10, &string_len);
  632.        DrawText(xbufmin, bottom+20, left-string_len/2, 10, 0, numDN-1);
  633.  
  634.        sprintf(xbufmax, "%ld", maxx);
  635.        LengthText(xbufmax, 10, &string_len);
  636.        DrawText(xbufmax, bottom+20, right-string_len/2, 10, 0, numDN-1);
  637.  
  638.        DrawText(xunit, bottom+30, left+(width/2)-75, 15, 0, numDN-1);
  639.        DrawText("Counts", bottom-(height/2)+50, left-20, 15, 90, numDN-1);
  640. */
  641.        lowedge = bottom;
  642.        leftedge= left;
  643.  
  644.        prevy   = max( ybuf[start], miny);
  645.        prevy   = lowedge - ( (int) (((float) (prevy - miny)) * scale_ydata_to_screen));
  646.        prevx   = left;
  647.  
  648.        for (i=start; i<start+len; i++)
  649.        {
  650.           if(ybuf[i] <= maxy && ybuf[i] >= miny)
  651.           {
  652.  
  653.           /* adjval to fall in plot range */
  654.               adjval= (int) (((float) (ybuf[i]-miny)) * scale_ydata_to_screen);
  655.  
  656.           /* make y-axis increase upward */
  657.               ycord= lowedge - adjval;
  658.  
  659.           /* scales the length of X-axis(samples) correctly */
  660.               nextx= leftedge + (int) ( ((float) (xbuf[i] - minx)) * scale_xdata_to_screen);
  661.  
  662.               if (strlen(symbol) == 0)
  663.               {
  664.               /* use lines; connect the points */
  665.                   DrawLine(prevy, prevx, ycord, nextx, color);
  666.                   prevy = ycord;
  667.                   prevx = nextx;
  668.               }
  669.               else
  670.                   DrawText(symbol, ycord, nextx, 8, 0, color);
  671.           }
  672.        }
  673.  
  674.        if (zoom == 2) /* We've already zoomed once */
  675.        {
  676.           minx  = tmpminx;
  677.           miny  = tmpminy;
  678.           maxx  = tmpmaxx;
  679.           maxy  = tmpmaxy;
  680.           len   = tmplen;
  681.           start = 0;
  682.           numDN = tmpdn;
  683.           DrawText("Would you like to zoom again (y/n)?  ",10,1,8,0,numDN-1);
  684.           ch = getch();
  685.        }
  686.  
  687.        if (zoom == 1) /* We haven't zoomed, and we want to */
  688.        {
  689.           ch= 'Y';
  690.           zoom = 2;
  691.        }
  692.  
  693.        if (ch == 'y' || ch == 'Y')
  694.        {
  695.           /*clears this line*/
  696.           DrawText("Would you like to zoom again (y/n)?  ",10,1,8,0,0);
  697.  
  698.           DrawText("   Arrow keys move + around. +,- (in/de)crements cursor steps.",
  699.                        10, 1, 8, 0,numDN-1);
  700.           LengthText("Hit Return to Select End Points", 8, &string_len);
  701.           DrawText("Hit Return to Select End Points",
  702.                        dispnl-10, left+(width-string_len)/2, 8, 0, numDN-1);
  703.  
  704.           PlaceCursor(bottom+6,right/2,numDN-1);
  705.           MoveCursor(&line1,&samp1);
  706.           DrawText("*",line1+4,samp1-4,8,0,numDN-1);
  707.           MoveCursor(&line2,&samp2);
  708.           DrawText("*",line2+4,samp2-4,8,0,numDN-1);
  709.           RemoveCursor();
  710.           ClearDisplay(0);
  711.  
  712.           if (samp1 > samp2)
  713.           {
  714.               i= samp2;
  715.               samp2= samp1;
  716.               samp1= i;
  717.           }
  718.           if (samp1 < left)
  719.               samp1 = left;
  720.           if (samp2 > right)
  721.               samp2 = right;
  722.           if (samp2 < left)
  723.               samp2 = left;   /* both end points < minx of plot */
  724.           if (samp1 > right)
  725.               samp1 = right;  /* both end points > maxx of plot */
  726.  
  727.           start = (samp1-left) *  ((float) len /(float)width);
  728.           len   = (samp2-samp1) *  ((float) len /(float)width);
  729.  
  730.           if(len > 0)
  731.           {
  732.           /* X-axis range selected is > 0 */
  733.  
  734.               minx = 0x7fffffff;
  735.               maxx = 0x80000000;
  736.               miny = 0x7fffffff;
  737.               maxy = 0x80000000;
  738.               for (i= start; i<start+len; i++)
  739.               {
  740.                   if (xbuf[i] < minx)
  741.                       minx = xbuf[i];
  742.                   if (xbuf[i] > maxx)
  743.                       maxx = xbuf[i];
  744.                   if (ybuf[i] < miny)
  745.                       miny = ybuf[i];
  746.                   if (ybuf[i] > maxy)
  747.                       maxy = ybuf[i];
  748.               }
  749.               prevy = lowedge  - ((int) (((float) (ybuf[start] - miny)) * scale_ydata_to_screen));
  750.               prevx = leftedge - ((int) (((float) (xbuf[start] - minx)) * scale_xdata_to_screen));
  751.           }
  752.           else
  753.           {
  754.           /* selected X range is zero */
  755.               zoom = -1;
  756.           }
  757.        }
  758.        else
  759.            zoom = -1;
  760.     }
  761.  
  762.     if (baseliner.DoBaseline == 'Y')
  763.     {
  764.         StatusLine(1, "Option not implemented for this data type");
  765.     }
  766.  
  767. } /* end Plotpair */
  768.  
  769. long min3arr( long * buf, int nvals)
  770. /*
  771.     Finds the third smallest value in a 32-bit integer array
  772. */
  773. {
  774.     long   min1 = 0x7fffffff, min2 = 0x7fffffff, min3 = 0x7fffffff;
  775.     int    i;
  776.  
  777.     for ( i=0; i<nvals; i++)
  778.     {
  779.        if (buf[i] < min1)
  780.        {
  781.            min3 = min2;
  782.            min2 = min1;
  783.            min1 = buf[i];
  784.        }
  785.        else if (buf[i] < min2)
  786.        {
  787.            min3 = min2;
  788.            min2 = buf[i];
  789.        }
  790.        else if (buf[i] < min3)
  791.        {
  792.            min3 = buf[i];
  793.        }
  794.     }
  795.     if (nvals > 2)
  796.        return(min3);
  797.     else
  798.        return(min1);
  799. }
  800.  
  801.  
  802. long max3arr( long * buf, int nvals)
  803. /*
  804.     Finds the third largest value in a 32-bit integer array
  805. */
  806. {
  807.     long   max1 = 0x80000000, max2 = 0x80000000, max3 = 0x80000000;
  808.     int    i;
  809.  
  810.     for ( i=0; i<nvals; i++)
  811.     {
  812.        if (buf[i] > max1)
  813.        {
  814.            max3 = max2;
  815.            max2 = max1;
  816.            max1 = buf[i];
  817.        }
  818.        else if (buf[i] > max2)
  819.        {
  820.            max3 = max2;
  821.            max2 = buf[i];
  822.        }
  823.        else if (buf[i] > max3)
  824.        {
  825.            max3 = buf[i];
  826.        }
  827.     }
  828.     if (nvals > 2)
  829.        return(max3);
  830.     else
  831.        return(max1);
  832. }
  833.  
  834. int DoPlot()
  835. /*
  836.     DoPlot performs the plot command.  First the parameters are scanned.
  837.     Then the image is read in and plotted.  Ordered pairs are plotted by
  838.     Plotpair, other data by Plot32.
  839. */
  840. {
  841.     int            wordbits=16, longbits=32;
  842.     int            line, i, k, zoom, color, symbolflag, spectraflag;
  843.     int            lineflag, ovlflag, zoomflag, minflag, maxflag, flag;
  844.     int            top, bottom, left, right, hss;
  845.     char           status[128], Symbol[2], PlotOvly;
  846.     long           miny=0x7FFFFFFF, maxy=0x80000000;
  847.     long           minx=0x7FFFFFFF, maxx=0x80000000;
  848.  
  849.     long           *buf32, *xbuf, *ybuf;
  850.     unsigned char  *buffer;
  851.     int            *intbuf;
  852.  
  853.     GetKeywordSubcommand (CommandString, "OVE", &ovlflag);
  854.     if (ovlflag == 1)
  855.     {
  856.     /* OVErlay specified, don't clear the screen */
  857.         PlotOvly = 'Y';
  858.     }
  859.     else
  860.     {
  861.         ClearDisplay(0);
  862.         PlotOvly = 'N';
  863.     }
  864.  
  865.  
  866.     GetKeywordSubcommand (CommandString, "ZOO", &zoomflag);
  867.     if (zoomflag == 1)
  868.         zoom = 1;
  869.     else
  870.     /* ZOOm not specified, don't ask to zoom plot */
  871.         zoom = 0;
  872.  
  873.     GetKeywordInteger (CommandString, "LIN", 1, &line, &lineflag);
  874.     if (line > nl || line < 1)
  875.         line = 1;
  876.  
  877.     GetKeywordInteger (CommandString, "COL", numDN-1, &color, &lineflag);
  878.     GetKeywordLong (CommandString, "MIN", miny, &miny, &minflag);
  879.     GetKeywordLong (CommandString, "MAX", maxy, &maxy, &maxflag);
  880.     GetKeywordString (CommandString, "SYM", "", Symbol, &symbolflag);
  881.     GetKeywordInteger (CommandString, "SS", 0, &hss, &flag);
  882.     GetKeywordSubcommand (CommandString, "SPE", &spectraflag);
  883.  
  884.     if (spectraflag >0)
  885.        baseliner.DoBaseline = 'Y';
  886.  
  887.     if (PDSused == 1 && switched == 1 && ns == 1 && nl > 1)
  888.     {
  889.     /*PDS label used */
  890.        i    = nl;
  891.        nl   = ns;
  892.        ns   = i;
  893.     }
  894.  
  895.     /* Allocate enough memory for the 32-bit buffers */
  896.     if ((buf32 = (long *)malloc(4*ns)) == NULL)
  897.     {
  898.        FatalError("Not enough memory to run program");
  899.     }
  900.  
  901.  
  902.     if ( (ns == 2 || ns == 3) && bitsperpix == 32)
  903.     {
  904.  
  905.         if ((xbuf = (long *)malloc(4*nl)) == NULL)
  906.         {
  907.             free(buf32);
  908.             FatalError("Not enough memory to run program");
  909.         }
  910.  
  911.         if ((ybuf = (long *)malloc(4*nl)) == NULL)
  912.         {
  913.            free(xbuf);
  914.            free(buf32);
  915.            FatalError("Not enough memory to run program");
  916.         }
  917.    /* 32 bit samples, ordered pairs */
  918.        k = 0;
  919.        for (i = 0;  i < nl;  i++)
  920.        {
  921.            ReadLine (0, buf32, line, 1, ns, status);
  922.            if (BadStatus(status))
  923.            {
  924.                free(ybuf);
  925.                free(xbuf);
  926.                free(buf32);
  927.                return(0);
  928.            }
  929.            xbuf[i] = buf32[0];
  930.            ybuf[i] = buf32[1];
  931.            line++;
  932.            k++;
  933.        }
  934.  
  935.        for (i=0; i<nl; i++)
  936.        {
  937.            if (xbuf[i] < minx)
  938.                minx = xbuf[i];
  939.            if (xbuf[i] > maxx)
  940.                maxx = xbuf[i];
  941.        }
  942.        if (minflag < 1)
  943.        {
  944.            miny = min3arr( ybuf, nl);
  945.            miny = miny + miny/10;
  946.        }
  947.        if (maxflag < 1)
  948.        {
  949.            maxy = max3arr( ybuf, nl);
  950.            maxy = maxy + maxy/10;
  951.        }
  952.  
  953.        Plotpair( xbuf, ybuf, minx, maxx, miny, maxy, k, Symbol, color, zoom);
  954.        TextLine = TextHeight + 5; TextSample = 1;
  955.        free(ybuf);
  956.        free(xbuf);
  957.        free(buf32);
  958.        return(0);
  959.     }
  960.  
  961.     if (ns != 2)  /*  images (not pairs) */
  962.     {
  963.        if (bitsperpix == 8)          /*  8 bit images */
  964.        {
  965.           if ((buffer = malloc(ns)) == NULL)
  966.           {
  967.               FatalError("Not enough memory to run program");
  968.           }
  969.  
  970.           ReadLine( 0, buffer, line, 1, ns, status);
  971.           if (BadStatus(status))
  972.           {
  973.               free (buffer);
  974.               free (buf32);
  975.               return(0);
  976.           }
  977.  
  978.           ConvertLine( buffer, buf32, bitsperpix, longbits, ns, status);
  979.           free (buffer);
  980.        }
  981.  
  982.        else if (bitsperpix == 16)          /* 16 bit images */
  983.        {
  984.           if ((intbuf = malloc(2*ns)) == NULL)
  985.           {
  986.               FatalError("Not enough memory to run program");
  987.           }
  988.  
  989.           ReadLine( 0, intbuf, line, 1, ns, status);
  990.           if (BadStatus(status))
  991.           {
  992.               free (intbuf);
  993.               free (buf32);
  994.               return(0);
  995.           }
  996.  
  997.           ConvertLine( intbuf, buf32, bitsperpix, longbits, ns, status);
  998.           free (intbuf);
  999.        }
  1000.        else if (bitsperpix == 32)          /* 32 bit images */
  1001.        {
  1002.            ReadLine (0, buf32, line, 1, ns, status);
  1003.            if (BadStatus(status))
  1004.            {
  1005.                free(buf32);
  1006.                return(0);
  1007.            }
  1008.        }
  1009.  
  1010.        if (minflag < 1)
  1011.        {
  1012.            miny = min3arr( buf32, ns);
  1013.            miny = miny + miny/10;
  1014.        }
  1015.  
  1016.        if (maxflag < 1)
  1017.        {
  1018.            maxy = max3arr( buf32, ns);
  1019.            maxy = maxy + maxy/10;
  1020.        }
  1021.  
  1022.        top       = dispnl / 10;
  1023.        bottom    = dispnl - top;
  1024.        left      = dispns / 10;
  1025.        right     = dispns - (dispns / 32);
  1026.        Plot32( buf32, miny, maxy, hss, ns, Symbol, color, top, bottom, left,
  1027.                right, zoom, PlotOvly);
  1028.        TextLine = TextHeight + 5; TextSample = 1;
  1029.        free(buf32);
  1030.        return(0);
  1031.     }
  1032. }
  1033.  
  1034. int DoPerspect()
  1035. /*
  1036.     DoPerspect performs the plot command.  First the parameters are scanned.
  1037.     Then the image is read in and plotted by Plot32.
  1038. */
  1039. {
  1040.     int    wordbits=16, longbits=32;
  1041.     int    line, i, k, zoom, color;
  1042.     int    minflag, maxflag, flag, displayflag;
  1043.     int    start_line, imgline, start_sample;
  1044.     int    top, bottom, left, right, height, width;
  1045.     char   status[128], PlotOvly, Symbol[2], ch;
  1046.     long   miny=0x7FFFFFFF, maxy=0x80000000;
  1047.     long   minx=0x7FFFFFFF, maxx=0x80000000;
  1048.     unsigned char min8, max8;
  1049.  
  1050.     long   *buf32;
  1051.     void   *buffer;
  1052.  
  1053.     ClearDisplay(0);
  1054.  
  1055.     /* Have MAX or MIN been specified? */
  1056.     GetKeywordLong (CommandString, "MIN", miny, &miny, &minflag);
  1057.     GetKeywordLong (CommandString, "MAX", maxy, &maxy, &maxflag);
  1058.     GetKeywordInteger (CommandString, "SL", 1, &start_line, &flag);
  1059.     if (start_line > nl || start_line < 1)
  1060.         start_line = 1;
  1061.     GetKeywordSubcommand (CommandString, "SCR", &displayflag);
  1062.     start_sample = 0;
  1063.  
  1064.     if (PDSused == 1 && switched == 1 && ns == 1 && nl > 1)
  1065.     {
  1066.     /*PDS label used */
  1067.        i    = nl;
  1068.        nl   = ns;
  1069.        ns   = i;
  1070.     }
  1071.  
  1072.     /* Allocate enough memory for the 32-bit buffer */
  1073.     if ((buf32 = (long *)malloc(4*ns)) == NULL)
  1074.     {
  1075.        StatusLine(0, "Not enough memory to run program");
  1076.        return;
  1077.     }
  1078.  
  1079.     /* Now allocate an 8- or 16-bit buffer, if that's the way the image is */
  1080.     if (bitsperpix == 8)          /*  8 bit images */
  1081.     {
  1082.        if ((buffer = (unsigned char *) malloc(ns)) == NULL)
  1083.        {
  1084.            StatusLine(0, "Not enough memory to run program");
  1085.            free( buf32 );
  1086.            return(-1);
  1087.        }
  1088.     }
  1089.     if (bitsperpix == 16)         /*  16 bit images */
  1090.     {
  1091.        if ((buffer = (int *) malloc(2*ns)) == NULL)
  1092.        {
  1093.            StatusLine(0, "Not enough memory to run program");
  1094.            free( buf32 );
  1095.            return(-1);
  1096.        }
  1097.     }
  1098.  
  1099.     /* Set some initial plot parameters */
  1100.     height   = dispnl / 8;
  1101.     width    = min( dispns, ns ) - (dispns / 10);
  1102.     left     = 1;
  1103.     right    = width - (dispns / 32);
  1104.     color    = -1;
  1105.     PlotOvly = 'Y';
  1106.     zoom     = 0;
  1107.     top      = 1;
  1108.     bottom   = height+1;
  1109.     strcpy(Symbol, ".");
  1110.     line = 1;
  1111.     imgline = start_line;
  1112.  
  1113.     /*  Now, loop over the entire image, one line at a time */
  1114.     while ((line<dispnl) && (bottom<dispnl) && (imgline<nl))
  1115.     {
  1116.  
  1117.        if (displayflag != -1)
  1118.        {
  1119.            GetLine( buffer, line, 1, dispns);
  1120.            min8 = 0;
  1121.            max8 = 255;
  1122.            Plot8( buffer, min8, max8, ns, Symbol, color, top, bottom, left,
  1123.                    right, zoom, PlotOvly);
  1124.        }
  1125.        else if (bitsperpix == 8)
  1126.        {
  1127.            ReadLine (0, buffer, imgline, 1, ns, status);
  1128.            min8 = 0;
  1129.            max8 = 255;
  1130.            Plot8( buffer, min8, max8, ns, Symbol, color, top, bottom, left,
  1131.                    right, zoom, PlotOvly);
  1132.        }
  1133.        else if (bitsperpix == 32)          /* 32 bit images */
  1134.        {
  1135.            ReadLine (0, buf32, imgline, 1, ns, status);
  1136.            if (BadStatus(status))
  1137.            {
  1138.                free(buf32);
  1139.                return(-1);
  1140.            }
  1141.            if (minflag < 1)
  1142.            {
  1143.                miny = min3arr( buf32, ns);
  1144.                miny = miny + miny/10;
  1145.            }
  1146.  
  1147.            if (maxflag < 1)
  1148.            {
  1149.                maxy = max3arr( buf32, ns);
  1150.                maxy = maxy + maxy/10;
  1151.            }
  1152.            Plot32( buf32, miny, maxy, start_sample, ns, Symbol, color,
  1153.                    top, bottom, left, right, zoom, PlotOvly);
  1154.        }
  1155.        else if (bitsperpix == 16)
  1156.        {
  1157.            ReadLine( 0, buffer, imgline, 1, ns, status);
  1158.            if (BadStatus(status))
  1159.            {
  1160.                free (buffer);
  1161.                free (buf32);
  1162.                return(-1);
  1163.            }
  1164.  
  1165.            ConvertLine( buffer, buf32, bitsperpix, longbits, ns, status);
  1166.            if (minflag < 1)
  1167.            {
  1168.                miny = min3arr( buf32, ns);
  1169.                miny = miny + miny/10;
  1170.            }
  1171.  
  1172.            if (maxflag < 1)
  1173.            {
  1174.                maxy = max3arr( buf32, ns);
  1175.                maxy = maxy + maxy/10;
  1176.            }
  1177.            Plot32( buf32, miny, maxy, start_sample, ns, Symbol, color,
  1178.                    top, bottom, left, right, zoom, PlotOvly);
  1179.        }
  1180.  
  1181. /*
  1182.    keyboard abort added
  1183. */
  1184.        if (kbhit())  /* abort disp if keypressed mdm 2/19/88*/
  1185.        {
  1186.            if ((ch = getch()) == 0) ch = 0x80 | getch();
  1187.            if (ch != 17) /* don't abort if cntl q */
  1188.            {
  1189.                bottom     = dispnl;
  1190.                abort_disp = 1;
  1191.            }
  1192.        }
  1193.        line++;
  1194.        top++;
  1195.        bottom++;
  1196.        imgline++;
  1197.     }
  1198.  
  1199.     if (RefreshLines > 0)           /* Save to refresh buffer   */
  1200.        Screen2Refresh();            /* Ron Baalke - 07/91       */
  1201.  
  1202.     TextLine = TextHeight + 5; TextSample = 1;
  1203.     free(buf32);
  1204.     free(buffer);
  1205.     return(0);
  1206. }
  1207.  
  1208. void FramePlot(int top, int bottom, int left, int right, long minx,
  1209. long maxx, long miny, long maxy)
  1210. /***  FramePlot draws a box around the plot, puts in the tic marks and
  1211.       the axes labels
  1212.  
  1213.       Original version - 8/92 AW3, adapted from Plot32() and Plot8()
  1214.  
  1215.    Parameter    Type    In/out   Description
  1216.       top        int     in
  1217.      bottom      int     in
  1218.       left       int     in
  1219.      right       int     in
  1220.       minx      long     in
  1221.       maxx      long     in
  1222.       miny       int     in
  1223.       maxy       int     in
  1224.  
  1225.  
  1226. ***/
  1227. {
  1228.     char           bufmin[15], bufmax[15], xbufmin[15], xbufmax[15];
  1229.     int            tic_height, width, height, i, j, string_len;
  1230.     int            num_Xtics=16, num_Ytics=10, num_Xlabels=8, num_Ylabels=5;
  1231.  
  1232. /* Calculate some useful quantities */
  1233.     tic_height = dispnl / 100;
  1234.     width = right - left;
  1235.     height = bottom - top;
  1236.  
  1237.     /* Draw box around the plot */
  1238.            FrameBox( top, left, bottom, right, numDN-1, TRUE);
  1239.  
  1240.     /* Draw in the tic marks */
  1241.            for (i = 0;  i <= num_Xtics;  i++)
  1242.            {
  1243.                j = left + width*i/num_Xtics;
  1244.                DrawLine (bottom, j, bottom-tic_height, j, numDN-1);
  1245.            }
  1246.  
  1247.            for (i = 0;  i <= num_Ytics;  i++)
  1248.            {
  1249.                j = bottom - height*i/num_Ytics;
  1250.                DrawLine (j, left, j, left-tic_height, numDN-1);
  1251.            }
  1252.  
  1253.     /* Label the axes and draw in plot and axis titles */
  1254.            sprintf(bufmin, "%10.2G", (float)miny);
  1255.            LengthText(bufmin, 6, &string_len);
  1256.            string_len = string_len + tic_height + 2;
  1257.            DrawText(bufmin, bottom+5, left-string_len, 6, 0, numDN-1);
  1258.  
  1259.            sprintf(bufmax, "%10.2G", (float)maxy);
  1260.            LengthText(bufmax, 6, &string_len);
  1261.            string_len = string_len + tic_height + 2;
  1262.            DrawText(bufmax, bottom-height+5, left-string_len, 6, 0, numDN-1);
  1263.  
  1264.            sprintf(xbufmin, "%ld", minx);
  1265.            LengthText(xbufmin, 10, &string_len);
  1266.            DrawText(xbufmin, bottom+20, left-string_len/2, 10, 0, numDN-1);
  1267.  
  1268.            sprintf(xbufmax, "%ld", maxx);
  1269.            LengthText(xbufmax, 10, &string_len);
  1270.            DrawText(xbufmax, bottom+20, right-string_len/2, 10, 0, numDN-1);
  1271.  
  1272.            LengthText(xunit, 15, &string_len);
  1273.            DrawText(xunit, bottom+30, left+(width-string_len)/2, 15, 0, numDN-1);
  1274.            DrawText("Counts", bottom-(height/2)+50, left-20, 15, 90, numDN-1);
  1275.  
  1276.            return;
  1277. }
  1278.  
  1279. void    NewZoomEndpoints( int * p_line1, int * p_samp1, int * p_line2,
  1280.                           int * p_samp2, int left, int right, int width,
  1281.                           int bottom)
  1282. {
  1283.     int string_len;
  1284.     int i;
  1285.  
  1286.       /* select the endpoints of the zoom */
  1287.       DrawText("   Arrow keys move + around. +,- (in/de)crements cursor steps.",
  1288.                    10, 1, 8, 0,numDN-1);
  1289.  
  1290.       LengthText("Hit Return to Select End Points", 8, &string_len);
  1291.       DrawText("Hit Return to Select End Points",
  1292.                    dispnl-10, left+(width-string_len)/2, 8, 0, numDN-1);
  1293.  
  1294.       PlaceCursor(bottom+6, right/2, numDN-1);
  1295.       MoveCursor(p_line1, p_samp1);
  1296.       DrawText("*", *p_line1+4, *p_samp1-4, 8, 0, numDN-1);
  1297.  
  1298.       MoveCursor(p_line2, p_samp2);
  1299.       DrawText("*", *p_line2+4, *p_samp2-4, 8, 0, numDN-1);
  1300.  
  1301.       /* clean up the screen */
  1302.       RemoveCursor();
  1303.       ClearDisplay(0);
  1304.  
  1305.       /* watch for reversed endpoints */
  1306.       if (*p_samp1 > *p_samp2)
  1307.       {
  1308.           i     = *p_samp2;
  1309.           *p_samp2 = *p_samp1;
  1310.           *p_samp1 = i;
  1311.       }
  1312.  
  1313.       /* watch for values off the plot */
  1314.       if (*p_samp1 < left)
  1315.           *p_samp1 = left;
  1316.       if (*p_samp2 > right)
  1317.           *p_samp2 = right;
  1318.       if (*p_samp2 < left)
  1319.           *p_samp2 = left;   /* both end points < minx of plot */
  1320.       if (*p_samp1 > right)
  1321.           *p_samp1 = right;  /* both end points > maxx of plot */
  1322. }
  1323.  
  1324.