home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / plotter / plotlib.pas < prev   
Pascal/Delphi Source File  |  1988-02-18  |  50KB  |  1,334 lines

  1. unit plotlib;
  2.  
  3. {                  Written by Bob Harbour / CP Systems
  4.  
  5.   This is a library of routines to drive a Tektronix 4662 flatbed plotter.
  6.   It is written in Turbo Pascal V4.0. You can use it for yourself but if
  7.   you plan to sell it or otherwise include it in something for sale please
  8.   contact me. All of the plotter relevant information was obtained from the
  9.   Tektronix manual.
  10.   The data is passed around in a record ( type datablock ) to organize it.
  11.   The record contains the following fields :
  12.  
  13.          xdata, ydata : datarray;             data point storage area
  14.          npoints : integer;                   number of points in array
  15.          Xmin, Xmax, Ymin, Ymax : real;       limits of data in array
  16.          Xscale, Yscale : real;               plot scaling parameters
  17.  
  18.      datarray = array [ 1..1000 ] of real;
  19.  
  20.   The xdata, ydata and npoints fields must be filled in but the routine
  21.   limits will fill in the min and max fields and scalecalc will fill in
  22.   the scale fields. All of these fields must be filled in prior to calling
  23.   either of the plot routines lineplot or dashplot.
  24.   There are routines here to generate linear plots, semi-logarithmic plots
  25.   and log-log plots. These are ready to call complete with labeling.
  26.   The primatives are available so that special plotting requirements can
  27.   be accomodated easily. There are routines for titling in several formats.
  28.   The 4662 plotter requires data in an integer format which are Absolute.
  29.   The plotting routines scale the real data to the absolute format required
  30.   by the plotter. The plotter accepts data as ascii characters so the
  31.   integer data must be converted by vectorgen to an ascii string.
  32.   Below is a list of the externally available routines and a short description
  33.   of what they do.
  34.   The plotter is connected to serial port COM2. }
  35.  
  36.  
  37.  
  38.  
  39. interface
  40.  
  41. {----------------------------------------------------------------------------}
  42.  
  43. uses crt;
  44. {$M 32768,0,655360}                         { increase stack size }
  45.  
  46. type vecstring = string [5];
  47.      linestring = string [ 40 ];
  48.      datarray = array [ 1..1000 ] of real;
  49.  
  50.      datablock = record
  51.          xdata, ydata : datarray;            { data point storage area }
  52.          npoints : integer;                  { number of points in array }
  53.          Xmin, Xmax, Ymin, Ymax : real;      { limits of data in array }
  54.          Xscale, Yscale : real;              { plotting parameters }
  55.      end;
  56.  
  57.  
  58. var aux : text;
  59.  
  60. { ==========  procedures and functions in unit ============================}
  61.  
  62. procedure vectorgen ( x, y :integer; var outstring : vecstring );
  63. { generate a vector string from input parameters x and y }
  64.  
  65. procedure wait ( x,y : integer );
  66. { calculate length of vector and wait proper amount of time to prevent plotter
  67.   buffer overrun. Assumes full sized plotter area, can be sped up if plotting
  68.   is always done on smaller paper by changing the global constants actualX , Y
  69.   to the smaller paper size }
  70.  
  71.  
  72. procedure moveto ( x, y : integer );
  73. { move pen to position x,y }
  74.  
  75. procedure drawto ( x, y : integer );
  76. { draw line to position x,y. note that this routine will repeat unneeded
  77.   bytes if used repetitivly for graphing, filling up the plotter buffer }
  78.  
  79.  
  80. procedure writechar ( x, y, theta : integer; charstr : linestring );
  81. { writes alpha characters starting at position x, y and at angle theta, with
  82.   x and y in plotter address integers and theta in degrees }
  83.  
  84. procedure deswrite ( x,y : integer; charstr : linestring );
  85. { writes a descending vertical string starting at x,y in absolute plotter
  86.   coordinates }
  87.  
  88. procedure vtitle ( x : integer; charstr : linestring );
  89. { writes title in a descending vertical strip starting at x with x in
  90.   absolute plotter coordinates, Y is chosen by routine to center the title }
  91.  
  92. procedure htitle ( y : integer; charstr : linestring );
  93. { prints a horizontal title centered in X on plot at vertical pos Y in
  94.   absolute plotter coordinates }
  95.  
  96.  
  97. procedure limits ( var plotdata : datablock );
  98. { finds the minimum and maximum values for X and Y in the databblock
  99.   and inserts them in the appropriate fields }
  100.  
  101. procedure scalecalc ( square :boolean; var plotdata : datablock );
  102. { calculates the scale factor from the min and max values in the block
  103.   if square, the x and y scale factors will be equal and set to the
  104.   smaller of the two. Must be called after mins and maxes are determined }
  105.  
  106. procedure edlimits ( var plotdata : datablock );
  107. { shows user the values in min and max for both axes and allows them to be
  108.   changed. Note that the max values cannot be made less than the ones in the
  109.   data block when called and the min values cannot be made greater so it is
  110.   important to call limits before calling this routine. }
  111.  
  112. procedure showlimits ( var plotdata : datablock );
  113. { shows values in limit fields and scale fields. mostly for debugging }
  114.  
  115. procedure lineplot ( var plotdata : datablock );
  116. { plots solid line through all points in data array }
  117.  
  118. procedure dashplot ( var plotdata : datablock );
  119. { plots dashed line through all points in data array, drawing the vectors
  120.   from originating from odd number points and leaving open the vectors
  121.   originating from even number points. Even and odd refering to the array
  122.   indices }
  123.  
  124.  
  125. procedure lineargrid ( var plotdata : datablock );
  126. { prints a grid of linear divisions on plot. must be called after limits
  127.   and scalecalc in order to have the correct values for the line positioning }
  128.  
  129. procedure linearaxes ( var plotdata : datablock );
  130. { draws the axes into the graph at the zero lines if they are in the range
  131.   plotted else puts the axes at the edges of the plot. requires the min and
  132.   max and scale data in the incoming block to operate }
  133.  
  134. procedure lincal ( var plotdata : datablock );
  135. { writes the mins and maxes in the corners of a linear plot }
  136.  
  137.  
  138. procedure semiloggrid ( var griddata : datablock );
  139. { plots the semi-log axes or grid from the limits in griddata }
  140.  
  141. procedure semilogcal ( var plotdata : datablock );
  142. { writes the mins and maxes in the corners of the plot on a semilog plot }
  143.  
  144.  
  145. procedure logloggrid ( var griddata : datablock );
  146. { plots the log-log grid from the limits in griddata }
  147.  
  148. procedure loglogcal ( var plotdata : datablock );
  149. { writes the mins and maxes in the corners of the plot on a log-log plot }
  150.  
  151.  
  152. procedure linearplot ( var plotstuff : datablock; Hname,Vname : linestring; grid,square : boolean );
  153. { plots the data in plotstuff on a linear graph. Writes Hname and Vname in the
  154.   appropriate margins and writes the limits in the margins too. If grid, a
  155.   regular graph paper type grid is drawn, else a line at the zeros or closest
  156.   to zero on graph is drawn. If square, scale factors are forced to the minimum
  157.   of X or Y and both are equal. useful for circles or true geometries }
  158.  
  159. procedure semilogplot ( var plotstuff : datablock; Hname,Vname : linestring );
  160. { generates a semi-logarithmic plot of the data in plotstuff. Writes string in
  161.   Vname and H name in the margins of the plot. X data is transformed to log
  162.   before plotting }
  163.  
  164. procedure logplot ( var plotstuff : datablock; Hname,Vname : linestring );
  165. { generates a log log plot of the data in plotstuff. titles in Hname and Vname
  166.   and data in both axes is transformed to log before plotting }
  167.  
  168. {--------------------------------------------------------------------------}
  169.  
  170.  
  171. implementation
  172.  
  173. { control characters and plotter commands and constants }
  174. const esc = #$1B;                           { ascii control characters }
  175.       del = #$7F;
  176.       gs  = #$1D;
  177.       us  = #$1F;
  178.       cr  = #$0D;
  179.       bel = #$07;
  180.       device = 'A';                         { plotter address set in dip sw }
  181.       plotteron = 'E';                      { plotter command characters }
  182.       plotteroff = 'F';
  183.       plotreset = 'N';
  184.       alphareset = 'V';
  185.       alpharotate = 'J';
  186.       comma = ',';
  187.  
  188.       plotXmax = 4095;                      { extreme right side of plotter }
  189.       plotXmin = 0;                         { extreme left side of plotter }
  190.       plotYmax = 2731;                      { extreme top side of plotter }
  191.       plotYmin = 0;                         { extreme bottom side of pltter }
  192.  
  193.       axesXmax = 3900;                      { right margin of plot area }
  194.       axesXmin = 600;                       { left margin of plot area }
  195.       axesYmax = 2550;                      { top margin }
  196.       axesYmin = 600;                       { bottom margin }
  197.  
  198.       lineheight = 88;                      { plotter default line spacing }
  199.       charwidth  = 56;                      { default character width }
  200.  
  201.       actualX = 10.0;                       { length in inches of plot surface}
  202.       actualY = 8.0;                        { height in inches of plot surface}
  203.  
  204. {-----------------------------------------------------------------------------}
  205.  
  206. var  lastX, lastY : integer;
  207.      scaleX, scaleY : real;
  208.  
  209. { ============================================================================}
  210.  
  211.  
  212. function log ( x : real ) : real;
  213. { calculates the base 10 logarithm of x }
  214.  
  215. begin
  216.     log := ln ( x ) / ln ( 10.0 );
  217. end;
  218.  
  219.  
  220.  
  221. function pow ( x : real ) : real;
  222. { calculates 10 ** x }
  223.  
  224. begin
  225.      pow := exp ( x * ln ( 10.0));
  226. end;
  227.  
  228.  
  229.  
  230. procedure vectorgen ( x, y :integer; var outstring : vecstring );
  231. { generate a vector string from input parameters x and y }
  232.  
  233. const Hioffset = $20;
  234.       LoXoffset = $40;
  235.       LoYoffset = $60;
  236.       XloYoffset = $60;
  237.  
  238. var   HiX, LoX, vlX, HiY, LoY, vlY, XloY : integer;
  239.  
  240. begin
  241.       if x > plotXmax then x := plotXmax;      { range check incomming data }
  242.       if x < plotXmin then x := plotXmin;
  243.       if y > plotYmax then y := plotYmax;
  244.       if y < plotYmin then y := plotYmin;
  245.  
  246.       HiX := x div 128;                 { split off the most significant part }
  247.       LoX := x mod 128;                 { get less significant part }
  248.       vlX := LoX mod 4;                 { get least significant part }
  249.       LoX := LoX div 4;                 { remove least significant part }
  250.  
  251.       HiY := y div 128;                 { repeat process for Y variable now }
  252.       LoY := y mod 128;
  253.       vlY := LoY mod 4;
  254.       LoY := LoY div 4;
  255.  
  256.       XloY := vlX + ( 4 * vlY );       { compose extra byte for ls 2 bits x,y }
  257.  
  258.       outstring := chr ( HiY + Hioffset );    { fill output string now }
  259.       outstring := outstring + chr ( XloY + XloYoffset );
  260.       outstring := outstring + chr ( LoY + LoYoffset );
  261.       outstring := outstring + chr ( HiX + Hioffset );
  262.       outstring := outstring + chr ( LoX + LoXoffset );
  263. end;
  264.  
  265.  
  266.  
  267. procedure wait ( x,y : integer );
  268. { calculate length of vector and wait proper amount of time to prevent plotter
  269.   buffer overrun. Assumes full sized plotter area, can be sped up if plotting
  270.   is always done on smaller paper by changing the global constants actualX , Y
  271.   to the smaller paper size }
  272.  
  273.  
  274. var Xcomp, Ycomp, delta, time : real;
  275.     wtime : word;
  276.  
  277. begin                                              { find vector length }
  278.     Xcomp := ( lastX - x ) * scaleX;               { get X component }
  279.     Ycomp := ( lastY - y ) * scaleY;
  280.     delta := sqrt ( sqr ( Xcomp ) + sqr ( Ycomp )); { python theorem }
  281.  
  282.     lastX := x;                                    { swap new end to old end }
  283.     lastY := y;                                    { for next vector }
  284.  
  285.     if delta < 0.05                                { select calculation meth }
  286.     then time := 0.0                               { these constants came from}
  287.     else if delta < 0.3                            { interpolating the curves }
  288.           then time := 166.0 * delta + 25.0        { in the tektronix manual }
  289.           else if delta < 1.0                      { time is in miliseconds }
  290.                 then time := 115.0 * delta + 30.0
  291.                 else if delta < 2.55
  292.                       then time := 70.0 * delta + 70.0
  293.                       else time := ( delta - 2.55 ) * 61.5 + 240;
  294.     if time > 0.5                                  { see if any time to wait }
  295.     then begin
  296.             wtime := round ( time );
  297.             delay ( wtime );                       { wait for the plotter }
  298.          end;
  299. end;
  300.  
  301.  
  302. procedure moveto ( x, y : integer );
  303. { move pen to position x,y }
  304. var destination : vecstring;
  305.  
  306. begin
  307.      vectorgen ( x, y, destination );
  308.      write ( aux, gs, destination );
  309. end;
  310.  
  311.  
  312.  
  313. procedure drawto ( x, y : integer );
  314. { draw line to position x,y. note that this routine will repeat unneeded
  315.   bytes if used repetitivly for graphing, filling up the plotter buffer }
  316.  
  317. var destination : vecstring;
  318.  
  319. begin
  320.      vectorgen ( x, y, destination );
  321.      write ( aux, gs, bel, destination );
  322. end;
  323.  
  324.  
  325.  
  326. procedure writechar ( x, y, theta : integer; charstr : linestring );
  327. { writes alpha characters starting at position x, y and at angle theta, with
  328.   x and y in plotter address integers and theta in degrees }
  329.  
  330. begin
  331.       moveto ( x, y );                        { move pen to lower left of ch }
  332.       write ( aux, esc, device, alpharotate, theta );      { set angle }
  333.       write ( aux, us, charstr )              { send string to the plotter }
  334. end;
  335.  
  336.  
  337.  
  338.  
  339. procedure deswrite ( x,y : integer; charstr : linestring );
  340. { writes a descending vertical string starting at x,y in absolute plotter
  341.   coordinates }
  342.  
  343. var i, stop : integer;
  344.  
  345. begin
  346.      moveto ( x, y );
  347.      stop := length ( charstr );                     { findout how many ch }
  348.      write ( aux, esc, device, alpharotate, '0' );   { set to horizontal }
  349.      write ( aux, us );
  350.      for i := 1 to stop do                           { write chars one/line }
  351.        write ( aux, charstr [ i ], cr );
  352. end;
  353.  
  354.  
  355.  
  356. procedure vtitle ( x : integer; charstr : linestring );
  357. { writes title in a descending vertical strip starting at x with x in
  358.   absolute plotter coordinates, Y is chosen by routine to center the title }
  359.  
  360. var y, n : integer;
  361.  
  362. begin
  363.      n := length ( charstr );                        { findout how many ch }
  364.      y:= ( axesYmax + axesYmin  + ( n * lineheight )) div 2;
  365.      deswrite ( x,y, charstr );                      { go print it }
  366. end;
  367.  
  368.  
  369.  
  370. procedure htitle ( y : integer; charstr : linestring );
  371. { prints a horizontal title centered in X on plot at vertical pos Y in
  372.   absolute plotter coordinates }
  373.  
  374. var x :integer;
  375.  
  376. begin
  377.      x := ( axesXmax + axesXmin - ( length ( charstr ) * charwidth )) div 2 ;
  378.      writechar ( x, y, 0, charstr );               { write it }
  379. end;
  380.  
  381.  
  382. procedure limits ( var plotdata : datablock );
  383. { fills in the limits for the data }
  384.  
  385. const
  386.       maxreal = 1.7E37;
  387.       minreal = - maxreal;
  388.  
  389. var   i : integer;
  390.  
  391. begin
  392.   with plotdata do                      { setup to access the data block }
  393.   begin
  394.      Xmax := minreal;                    { init to extreme opposite values }
  395.      Xmin := maxreal;
  396.      Ymax := minreal;
  397.      Ymin := maxreal;
  398.  
  399.      for i := 1 to npoints do            { scan for largest and smallest }
  400.      begin
  401.            if xdata [ i ] > Xmax
  402.              then Xmax := xdata [ i ];
  403.  
  404.            if xdata [ i ] < Xmin
  405.              then Xmin := xdata [ i ];
  406.  
  407.            if ydata [ i ] > Ymax
  408.              then Ymax := ydata [ i ];
  409.  
  410.            if ydata [ i ] < Ymin
  411.              then Ymin := ydata [ i ];
  412.      end;
  413.  
  414.    end;
  415. end;
  416.  
  417.  
  418. procedure scalecalc ( square :boolean; var plotdata : datablock );
  419. { calculates the scale factor from the min and max values in the block
  420.   if square, the x and y scale factors will be equal and set to the
  421.   smaller of the two. Must be called after mins and maxes are determined }
  422.  
  423. var tempX, tempY : real;
  424.  
  425. begin
  426.      with plotdata do
  427.       begin
  428.         tempX := axesXmax - axesXmin;
  429.         tempY := axesYmax - axesYmin;
  430.                  { calculate scaling factors }
  431.         xscale := tempX / ( Xmax - Xmin ) ;
  432.         yscale := tempY / ( Ymax - Ymin ) ;
  433.  
  434.         if square                          { if square, make scale factors = }
  435.         then begin if xscale < yscale
  436.                      then yscale := xscale;
  437.                    if yscale < xscale
  438.                      then xscale := yscale;
  439.              end;
  440.       end;
  441. end;
  442.  
  443.  
  444.  
  445. function getnum ( numstr : linestring ) : real;
  446. { checks string for non numeric characters and converts the remaining string
  447.   to a real number. }
  448.  
  449. var i, strlength, code : integer;
  450.     temp : real;
  451.     tempstr : linestring;
  452. begin
  453.      repeat
  454.        i := 1;                            { set up to find first number }
  455.        strlength := length ( numstr );
  456.        while not ( numstr [ i ] in [ '+','-','0'..'9' ] ) and (i <= strlength) do
  457.         i := i + 1;                       { find first numeric }
  458.  
  459.        if i <= strlength
  460.        then begin
  461.              tempstr := copy ( numstr ,i ,strlength );
  462.              val ( tempstr, temp, code );{ convert it }
  463.              if code <> 0
  464.               then begin write ( 'Please re-enter new value : ');
  465.                          readln ( numstr );
  466.                    end;
  467.             end
  468.  
  469.        else begin write ( 'Please re-enter new value : ');
  470.                   readln ( numstr );
  471.                   code := 1;                         { set dummy value }
  472.             end;
  473.  
  474.      until code = 0;
  475.  
  476.      getnum := temp;                                 { assign function value}
  477. end;
  478.  
  479.  
  480. procedure edlimits ( var plotdata : datablock );
  481. { displays mins and maxes and allows the user to edit them }
  482.  
  483. var instring : linestring;
  484.     command : string [ 4 ];
  485.     temp : real;
  486.  
  487. begin
  488.    with plotdata do
  489.           repeat                                  { until instring ='' }
  490.  
  491.              writeln ('Xmax = ',Xmax,'     Ymax = ',Ymax );
  492.              writeln ('Xmin = ',Xmin,'     Ymin = ',Ymin );
  493.              writeln;
  494.              write ('Enter : parameter new_value     or return to continue : ');
  495.              readln ( instring );
  496.  
  497.              if instring <> ''                    { is there a string there ?}
  498.              then
  499.                begin
  500.                  command := copy ( instring, 1, 4 );
  501.  
  502.                  if (command = 'ymin') or (command = 'Ymin')
  503.                   then begin
  504.                          temp := getnum ( instring );
  505.                          if temp <= Ymin                  { is change legal? }
  506.                            then Ymin := temp              { yes, do it }
  507.                            else writeln ('New value too large!');
  508.                        end
  509.  
  510.                   else if (command = 'ymax') or (command = 'Ymax')
  511.                         then begin
  512.                               temp := getnum ( instring );
  513.                               if temp >= Ymax              { is change legal? }
  514.                                 then Ymax := temp          { yes, do it }
  515.                                 else writeln ('New value too small!');
  516.                              end
  517.  
  518.  
  519.                         else if (command = 'xmin') or (command = 'Xmin')
  520.                               then begin
  521.                                      temp := getnum ( instring );
  522.                                      if temp <= Xmin       { is change legal? }
  523.                                        then Xmin := temp   { yes, do it }
  524.                                        else writeln ('New value too large!');
  525.                                    end
  526.  
  527.  
  528.                               else if (command = 'xmax') or (command = 'Xmax')
  529.                                     then begin
  530.                                            temp := getnum ( instring );
  531.                                            if temp >= Xmax
  532.                                              then Xmax := temp
  533.                                              else writeln ('New value too small!');
  534.                                          end
  535.  
  536.                                     else writeln ('Invalid parameter name ');
  537.                end;
  538.           until instring = '';
  539.  
  540. end;
  541.  
  542.  
  543.  
  544.  
  545.  
  546. procedure showlimits ( var plotdata : datablock );
  547. { displays the contents of the min and max and scale factors for block
  548.   passed in }
  549.  
  550. begin with plotdata do
  551.         begin
  552.            writeln ( 'Xmax = ',Xmax,'  Xmin = ',Xmin,'   X scale = ',xscale );
  553.            writeln ( 'Ymax = ',Ymax,'  Ymin = ',Ymin,'   Y scale = ',yscale );
  554.         end;
  555. end;
  556.  
  557.  
  558.  
  559.  
  560. procedure lineplot ( var plotdata : datablock );
  561. { plots solid line through all points in data array }
  562.  
  563. var i, x, y :integer;
  564.     destination : vecstring;
  565.     firstpair : boolean;
  566.  
  567. begin
  568.      firstpair := true;                 { indicate first pair transmitted }
  569.      with plotdata do                   { get access to data and limits }
  570.        begin
  571.             for i := 1 to npoints do    { do whole array of points }
  572.             begin
  573.                      { calculate plotter coords from data }
  574.               x := round (( xdata [ i ] - Xmin ) * xscale ) + axesXmin;
  575.               y := round (( ydata [ i ] - Ymin ) * yscale ) + axesYmin;
  576.               vectorgen ( x, y, destination );      { generate output string }
  577.  
  578.               if firstpair                          { see if first point sent }
  579.                 then begin                          { yes, send whole command }
  580.                        write ( aux, gs, destination );
  581.                        firstpair := false;          { reset flag }
  582.                      end
  583.                 else
  584.                      write ( aux, destination );
  585.  
  586.               wait ( x,y );                         { wait for plotter to draw}
  587.  
  588.             end;
  589.        end;
  590. end;
  591.  
  592.  
  593. procedure dashplot ( var plotdata : datablock );
  594. { plots dashed line through all points in data array, drawing the vectors
  595.   from originating from odd number points and leaving open the vectors
  596.   originating from even number points. Even and odd refering to the array
  597.   indices }
  598.  
  599. var i, x, y :integer;
  600.     destination : vecstring;
  601.     odd : boolean;
  602.  
  603. begin
  604.      odd := true;                       { indicate odd pair to transmit }
  605.      with plotdata do                   { get access to data and limits }
  606.        begin
  607.             for i := 1 to npoints do    { do whole array of points }
  608.             begin
  609.                      { calculate plotter coords from data }
  610.               x := round (( xdata [ i ] - Xmin ) * xscale ) + axesXmin;
  611.               y := round (( ydata [ i ] - Ymin ) * yscale ) + axesYmin;
  612.  
  613.               vectorgen ( x, y, destination );      { generate output string }
  614.  
  615.               if odd                                { see if odd or even  }
  616.                 then begin                          { odd, move to it }
  617.                        write ( aux, gs, destination );
  618.                        odd := false;                { toggle flag }
  619.                      end
  620.                 else
  621.                      begin                          { even, draw to this one }
  622.                        write ( aux, destination );
  623.                        odd := true;                 { toggle flag }
  624.                      end;
  625.  
  626.               wait ( x,y );                         { wait for plotter to draw}
  627.  
  628.             end;
  629.        end;
  630. end;
  631.  
  632.  
  633. procedure lineargrid ( var plotdata : datablock );
  634. { prints a grid of linear divisions on plot. must be called after limits
  635.   and scalecalc in order to have the correct values for the line positioning }
  636.  
  637. const Hlines = 11;                             { number of horizontal lines }
  638.       Vlines = 11;
  639. var griddata : datablock;
  640.     Xrange, Yrange, Xincrement, Yincrement, X, Y : real;
  641.     i, firstY, lastY :integer;
  642.     odd : boolean;
  643.  
  644. begin
  645.      with plotdata do
  646.      begin
  647.          griddata.Xmax := Xmax;               { copy this data over }
  648.          griddata.Xmin := Xmin;
  649.          griddata.Xscale := Xscale;
  650.          griddata.Ymax := Ymax;
  651.          griddata.Ymin := Ymin;
  652.          griddata.Yscale := Yscale;
  653.  
  654.          Xrange := Xmax - Xmin;               { Get stuff out of this block }
  655.          Yrange := Ymax - Ymin;
  656.      end;
  657.  
  658.      Xincrement := Xrange / ( Vlines - 1 );  { determine the spacing of lines }
  659.      Yincrement := Yrange / ( Hlines - 1 );
  660.  
  661.      with griddata do                        { start filling the grid data }
  662.      begin
  663.        X := Xmin;                            { init the counters }
  664.        Y := Ymin;
  665.        odd := true;                          { init the flag }
  666.  
  667.        for i := 1 to ( Hlines  * 2 ) do      { generate the horizontal lines }
  668.        begin
  669.            if odd
  670.            then begin                        { begin a written vector }
  671.                   xdata [ i ] := Xmin;       { put data into the data block }
  672.                   ydata [ i ] := Y;
  673.                   odd := false;              { toggle flag }
  674.                 end
  675.            else begin                        { start an unwritten vector }
  676.                   xdata [ i ] := Xmax;
  677.                   ydata [ i ] := Y;
  678.                   Y:= Y + Yincrement;        { advance to next line up }
  679.                   odd := true;               { toggle flag }
  680.                 end;
  681.       end;                                   { horizontal lines are done }
  682.  
  683.       firstY := ( hlines * 2 ) + 1;          { first vertical line beginning }
  684.       lastY := ( hlines * 2 ) + 1 + ( vlines *2 );  { last point for vert }
  685.  
  686.       for i := firstY to lastY do            { generate vertical lines now }
  687.       if odd
  688.         then begin                           { generate a written vector }
  689.                  xdata [ i ] := X;
  690.                  ydata [ i ] := Ymin;
  691.                  odd := false;               { toggle flag }
  692.              end
  693.         else begin                           { generate an unwritten vector }
  694.                  xdata [ i ] := X;
  695.                  ydata [ i ] := Ymax;
  696.                  X := X + Xincrement;        { set up for next line }
  697.                  odd := true;                { toggle flag }
  698.              end;
  699.                                              { last of vertical lines }
  700.  
  701.       npoints := lastY;                      { tell it how many points }
  702.      end;                                    { with griddata }
  703.      dashplot ( griddata );                  { draw the lines }
  704. end;
  705.  
  706.  
  707.  
  708. procedure linearaxes ( var plotdata : datablock );
  709. { draws the axes into the graph at the zero lines if they are in the range
  710.   plotted else puts the axes at the edges of the plot. requires the min and
  711.   max and scale data in the incoming block to operate }
  712.  
  713. const ticsize = 0.01;                         { size of scale tick marks }
  714.       numXtics = 10;
  715.       numYtics = 10;
  716.  
  717. var axesdata : datablock;
  718.     i : integer;
  719.     ticdev, x, y, xincrement, yincrement, xrun, yrun : real;
  720.  
  721. begin
  722.    with plotdata do
  723.      begin
  724.          axesdata.Xmin := Xmin;              { copy required parameters }
  725.          axesdata.Xmax := Xmax;
  726.          axesdata.Ymin := Ymin;
  727.          axesdata.Ymax := Ymax;
  728.          axesdata.Xscale := Xscale;
  729.          axesdata.Yscale := Yscale;
  730.      end;
  731.  
  732.    with axesdata do
  733.      begin                                    { find where to put axes }
  734.          if ( Ymax * Ymin ) < 0.0             { is Ymin < 0 < Ymax ? }
  735.            then y := 0.0                      { yes, put axis on it }
  736.            else if Ymin >= 0.0                { no, is graph above the X axis }
  737.                  then y := Ymin               { yes, put axis at the bottom }
  738.                  else y := Ymax;              { no, put axis at the top }
  739.  
  740.          if ( Xmax * Xmin ) < 0.0             { is Xmin < 0 < Xmax ? }
  741.            then x := 0.0                      { yes, put axis on it }
  742.            else if Xmin >= 0.0                { no, is graph right of Y axis }
  743.                  then x := Xmin               { yes, put axis on left side }
  744.                  else x := Xmax;              { no, put axis at the left }
  745.  
  746.  
  747.          xincrement := ( Xmax - Xmin ) / numXtics;  { calculate spacing }
  748.          yincrement := ( Ymax - Ymin ) / numYtics;
  749.  
  750.          xrun := x;                             { initialize running variable }
  751.          yrun := y;
  752.  
  753.          while ( xrun - xincrement ) > Xmin do  { back up close to edge }
  754.             xrun := xrun - xincrement;
  755.  
  756.          while ( yrun - yincrement ) > Ymin do
  757.             yrun := yrun - yincrement;
  758.  
  759.                                                 { set up to put X axis in }
  760.          ticdev := ( Ymax - Ymin ) * ticsize;   { scale the tics to the graph }
  761.  
  762.          npoints := 1;                          { init counter / index }
  763.          xdata [ npoints ] := Xmin;             { start at left edge }
  764.          Ydata [ npoints ] := y;
  765.  
  766.          while xrun <= Xmax do
  767.          begin                                  { cross whole graph }
  768.            npoints := npoints + 1;
  769.            xdata [ npoints ] := xrun;
  770.            ydata [ npoints ] := y;
  771.  
  772.            npoints := npoints + 1;              { place top half of tic }
  773.            xdata [ npoints ] := xrun;
  774.            ydata [ npoints ] := y + ticdev;
  775.  
  776.            npoints := npoints + 1;              { place bottom half of tic }
  777.            xdata [ npoints ] := xrun;
  778.            ydata [ npoints ] := y - ticdev;
  779.  
  780.            npoints := npoints + 1;              { move back to the axis }
  781.            xdata [ npoints ] := xrun;
  782.            ydata [ npoints ] := y;
  783.  
  784.            xrun := xrun + xincrement;           { advance to next tic }
  785.          end;
  786.  
  787.          npoints := npoints +1;
  788.          xdata [ npoints ] := Xmax;             { make sure axis goes to edge }
  789.          ydata [ npoints ] := y;
  790.  
  791.      end;                                       { with axesdata }
  792.  
  793.      lineplot ( axesdata );                     { draw x axis }
  794.  
  795.      with axesdata do
  796.        begin
  797.        npoints := 1;                            { init counter / index }
  798.        ticdev := ( Xmax - Xmin ) * ticsize;
  799.  
  800.        xdata [ npoints ] := x;                  { start at bottom edge }
  801.        ydata [ npoints ] := Ymin;
  802.  
  803.          while yrun <= Ymax do
  804.          begin                                  { cross whole graph }
  805.            npoints := npoints + 1;
  806.            xdata [ npoints ] := x;
  807.            ydata [ npoints ] := yrun;
  808.  
  809.            npoints := npoints + 1;              { place right half of tic }
  810.            xdata [ npoints ] := x + ticdev;
  811.            ydata [ npoints ] := yrun;
  812.  
  813.            npoints := npoints + 1;              { place left half of tic }
  814.            xdata [ npoints ] := x - ticdev;
  815.            ydata [ npoints ] := yrun;
  816.  
  817.            npoints := npoints + 1;              { move back to the axis }
  818.            xdata [ npoints ] := x;
  819.            ydata [ npoints ] := yrun;
  820.  
  821.            yrun := yrun + yincrement;           { advance to next tic }
  822.          end;
  823.  
  824.          npoints := npoints + 1;                { make sure axis goes to edge }
  825.          xdata [ npoints ] := x;
  826.          ydata [ npoints ] := Ymax;
  827.  
  828.      end;                                       { with axesdata }
  829.  
  830.      lineplot ( axesdata );                     { draw y axis }
  831. end;
  832.  
  833.  
  834.  
  835.  
  836.  
  837.  
  838.  
  839.  
  840. procedure lincal ( var plotdata : datablock );
  841. { writes the mins and maxes in the corners of a linear plot }
  842.  
  843. var x,y,n : integer;
  844.     outstring : linestring;
  845.  
  846. begin
  847.     with plotdata do
  848.     begin
  849.         str ( Ymax:5, outstring );                { get string version of 1st }
  850.         n := length ( outstring );                { how many chars }
  851.         x := axesXmin - ( n + 1 ) * charwidth;    { calc where to print it }
  852.         y := axesYmax - lineheight div 2;
  853.         writechar ( x,y,0,outstring );            { write it }
  854.  
  855.         str ( Ymin:5, outstring );                { get string version of 2nd }
  856.         n := length ( outstring );                { how many chars }
  857.         x := axesXmin - ( n + 1 ) * charwidth;    { calc where to print it }
  858.         y := axesYmin - lineheight div 2;
  859.         writechar ( x,y,0,outstring );            { write it }
  860.  
  861.         str ( Xmin:5, outstring );                { get string version of 3rd }
  862.         n := length ( outstring );                { how many chars }
  863.         x := axesXmin - (( n * charwidth ) div 2 );  { calc where to put it }
  864.         y := axesYmin - 2 * lineheight;
  865.         writechar ( x,y,0, outstring );           { write it }
  866.  
  867.         str ( Xmax:4, outstring );                { get string version of 4th }
  868.         n := length ( outstring );                { how many chars }
  869.  
  870.         x := axesXmax - (( n * charwidth ) div 2 );    { calc where to put it }
  871.         if ( x + ( n + 1 ) * charwidth ) > plotXmax    { make sure it fits }
  872.           then x := plotXmax - ( n + 2 ) * charwidth;  { no, make it fit! }
  873.  
  874.         y := axesYmin - 2 * lineheight;
  875.         writechar ( x,y,0, outstring );           { write it }
  876.     end;
  877. end;
  878.  
  879.  
  880.  
  881.  
  882. procedure semiloggrid ( var griddata : datablock );
  883. { plots the semi-log axes or grid from the limits in griddata }
  884.  
  885. const hlines = 11;
  886.  
  887. var hiX,loX, dectemp, decade, units, x, yrange, yincrement, y : real;
  888.     i, n : integer;
  889.  
  890. begin
  891.   with griddata do
  892.     begin
  893.        i := 1;                                { init index counter }
  894.        hiX := Xmax;
  895.        loX := Xmin;
  896.        decade := loX;
  897.  
  898.                                     { generate vertical lines first }
  899.        while decade < hiX do                  { generate the decade loop }
  900.        begin
  901.           dectemp := pow ( decade );          { keep this out of the loop }
  902.           units := 1.0;
  903.  
  904.           while units <= 9.0 do
  905.           begin
  906.               x:= log ( units * dectemp);
  907.               xdata [ i ] := x;
  908.               ydata [ i ] := Ymin;
  909.               i := i + 1;                     { increment index }
  910.  
  911.               xdata [ i ] := x;
  912.               ydata [ i ] := Ymax;
  913.               i := i + 1;
  914.  
  915.               units := units + 1.0;          { increment units }
  916.           end;
  917.  
  918.         decade := decade + 1.0;            { increment power of ten }
  919.        end;
  920.  
  921.        if x < Xmax                         { is log axis complete ? }
  922.          then begin
  923.                 xdata [ i ] := Xmax;       { no, put in last line }
  924.                 ydata [ i ] := Ymax;
  925.                 i := i + 1;
  926.                 xdata [ i ] := Xmax;
  927.                 ydata [ i ] := Ymin;
  928.                 i := i + 1;
  929.               end;
  930.  
  931.                                   { now do the horizontal lines }
  932.        yrange := Ymax - Ymin;
  933.        yincrement := Yrange / ( hlines - 1 );   { calculate the spacing }
  934.        y := Ymin;                               { init the running pointer }
  935.  
  936.        for n := 1 to hlines do
  937.        begin
  938.             xdata [ i ] := Xmax;                { generate line vectors }
  939.             ydata [ i ] := y;
  940.             i := i + 1;                         { increment index counter }
  941.  
  942.             xdata [ i ] := Xmin;
  943.             ydata [ i ] := y;
  944.             i := i + 1;
  945.             y := y + yincrement;                { set up for next line }
  946.        end;
  947.  
  948.        npoints := i - 1;                        { save point count in block }
  949.  
  950.     end;                                        { with }
  951.  
  952.        dashplot ( griddata );                   { draw the vectors }
  953. end;
  954.  
  955.  
  956.  
  957.  
  958.  
  959.  
  960. procedure semilogcal ( var plotdata : datablock );
  961. { writes the mins and maxes in the corners of the plot on a semilog plot }
  962.  
  963. var x,y,n,temp : integer;
  964.     outstring, digstring : linestring;
  965.  
  966. begin
  967.     with plotdata do
  968.     begin
  969.         str ( Ymax:5, outstring );                { get string version of 1st }
  970.         n := length ( outstring );                { how many chars }
  971.         x := axesXmin - ( n + 1 ) * charwidth;    { calc where to print it }
  972.         y := axesYmax - lineheight div 2;
  973.         writechar ( x,y,0,outstring );            { write it }
  974.  
  975.         str ( Ymin:5, outstring );                { get string version of 2nd }
  976.         n := length ( outstring );                { how many chars }
  977.         x := axesXmin - ( n + 1 ) * charwidth;    { calc where to print it }
  978.         y := axesYmin - lineheight div 2;
  979.         writechar ( x,y,0,outstring );            { write it }
  980.  
  981.         outstring := '10 E';                      { start horizontal label }
  982.         temp := round ( Xmin );
  983.         str ( temp, digstring );                  { get string version }
  984.         outstring := outstring + digstring;
  985.         n := length ( outstring );                { how many chars }
  986.         x := axesXmin - (( n * charwidth ) div 2 );  { calc where to put it }
  987.         y := axesYmin - 2 * lineheight;
  988.         writechar ( x,y,0, outstring );           { write it }
  989.  
  990.         outstring := '10 E';
  991.         temp := round ( Xmax );
  992.         str ( temp, digstring );                  { get string version  }
  993.         outstring := outstring + digstring;
  994.         n := length ( outstring );                { how many chars }
  995.  
  996.         x := axesXmax - (( n * charwidth ) div 2 );    { calc where to put it }
  997.         if ( x + ( n + 1 ) * charwidth ) > plotXmax    { make sure it fits }
  998.           then x := plotXmax - ( n + 2 ) * charwidth;  { no, make it fit! }
  999.  
  1000.         y := axesYmin - 2 * lineheight;
  1001.         writechar ( x,y,0, outstring );           { write it }
  1002.     end;
  1003. end;
  1004.  
  1005.  
  1006.  
  1007. procedure loglogcal ( var plotdata : datablock );
  1008. { writes the mins and maxes in the corners of the plot on a log-log plot }
  1009.  
  1010. var x,y,n,temp : integer;
  1011.     outstring, digstring : linestring;
  1012.  
  1013. begin
  1014.     with plotdata do
  1015.     begin
  1016.         outstring := '10 E';                      { get first part of label }
  1017.         temp := round ( Ymax );                   { get value for exponent }
  1018.         str (temp, digstring );                   { get string version of exp }
  1019.         outstring := outstring + digstring;       { combine them }
  1020.         n := length ( outstring );                { how many chars }
  1021.         x := axesXmin - ( n + 1 ) * charwidth;    { calc where to print it }
  1022.         y := axesYmax - lineheight div 2;
  1023.         writechar ( x,y,0,outstring );            { write it }
  1024.  
  1025.         outstring := '10 E';                      { get first part of label }
  1026.         temp := round ( Ymin );                   { get value for exponent }
  1027.         str (temp, digstring );                   { get string version of exp }
  1028.         outstring := outstring + digstring;       { combine them }
  1029.         n := length ( outstring );                { how many chars }
  1030.         x := axesXmin - ( n + 1 ) * charwidth;    { calc where to print it }
  1031.         y := axesYmin - lineheight div 2;
  1032.         writechar ( x,y,0,outstring );            { write it }
  1033.  
  1034.         outstring := '10 E';                      { start horizontal label }
  1035.         temp := round ( Xmin );
  1036.         str ( temp, digstring );                  { get string version }
  1037.         outstring := outstring + digstring;
  1038.         n := length ( outstring );                { how many chars }
  1039.         x := axesXmin - (( n * charwidth ) div 2 );  { calc where to put it }
  1040.         y := axesYmin - 2 * lineheight;
  1041.         writechar ( x,y,0, outstring );           { write it }
  1042.  
  1043.         outstring := '10 E';
  1044.         temp := round ( Xmax );
  1045.         str ( temp, digstring );                  { get string version  }
  1046.         outstring := outstring + digstring;
  1047.         n := length ( outstring );                { how many chars }
  1048.  
  1049.         x := axesXmax - (( n * charwidth ) div 2 );    { calc where to put it }
  1050.         if ( x + ( n + 1 ) * charwidth ) > plotXmax    { make sure it fits }
  1051.           then x := plotXmax - ( n + 2 ) * charwidth;  { no, make it fit! }
  1052.  
  1053.         y := axesYmin - 2 * lineheight;
  1054.         writechar ( x,y,0, outstring );           { write it }
  1055.     end;
  1056. end;
  1057.  
  1058.  
  1059.  
  1060. procedure logloggrid ( var griddata : datablock );
  1061. { plots the log-log grid from the limits in griddata }
  1062.  
  1063. var dectemp, decade, units, x, y : real;
  1064.     i, n : integer;
  1065.  
  1066. begin
  1067.   with griddata do
  1068.     begin
  1069.        i := 1;                                { init index counter }
  1070.        decade := Xmin;
  1071.  
  1072.                                     { generate vertical lines first }
  1073.        while decade < Xmax do                 { generate the decade loop }
  1074.        begin
  1075.           dectemp := pow ( decade );          { keep this out of the loop }
  1076.           units := 1.0;
  1077.  
  1078.           while units <= 9.0 do
  1079.           begin
  1080.               x:= log ( units * dectemp);
  1081.               xdata [ i ] := x;
  1082.               ydata [ i ] := Ymin;
  1083.               i := i + 1;                     { increment index }
  1084.  
  1085.               xdata [ i ] := x;
  1086.               ydata [ i ] := Ymax;
  1087.               i := i + 1;
  1088.  
  1089.               units := units + 1.0;          { increment units }
  1090.           end;
  1091.  
  1092.         decade := decade + 1.0;            { increment power of ten }
  1093.        end;
  1094.  
  1095.        if x < Xmax                         { is log axis complete ? }
  1096.          then begin
  1097.                 xdata [ i ] := Xmax;       { no, put in last line }
  1098.                 ydata [ i ] := Ymax;
  1099.                 i := i + 1;
  1100.                 xdata [ i ] := Xmax;
  1101.                 ydata [ i ] := Ymin;
  1102.                 i := i + 1;
  1103.               end;
  1104.  
  1105.                                   { now do the horizontal lines }
  1106.        decade := Ymin;
  1107.  
  1108.        while decade < Ymax do                 { generate the decade loop }
  1109.        begin
  1110.           dectemp := pow ( decade );          { keep this out of the loop }
  1111.           units := 1.0;
  1112.  
  1113.           while units <= 9.0 do
  1114.           begin
  1115.               y:= log ( units * dectemp);
  1116.               xdata [ i ] := Xmin;
  1117.               ydata [ i ] := y;
  1118.               i := i + 1;                     { increment index }
  1119.  
  1120.               xdata [ i ] := Xmax;
  1121.               ydata [ i ] := y;
  1122.               i := i + 1;
  1123.  
  1124.               units := units + 1.0;          { increment units }
  1125.           end;
  1126.  
  1127.         decade := decade + 1.0;            { increment power of ten }
  1128.        end;
  1129.  
  1130.        if y < Ymax                         { is log grid complete ? }
  1131.          then begin
  1132.                 xdata [ i ] := Xmax;       { no, put in last line }
  1133.                 ydata [ i ] := Ymax;
  1134.                 i := i + 1;
  1135.                 xdata [ i ] := Xmin;
  1136.                 ydata [ i ] := Ymax;
  1137.                 i := i + 1;
  1138.               end;
  1139.  
  1140.  
  1141.        npoints := i - 1;                        { save point count in block }
  1142.  
  1143.     end;                                        { with }
  1144.  
  1145.        dashplot ( griddata );                   { draw the vectors }
  1146. end;
  1147.  
  1148.  
  1149.  
  1150. procedure logplot ( var plotstuff : datablock; Hname,Vname : linestring );
  1151. { generates a log log plot of the data in plotstuff }
  1152.  
  1153. var gridstuff : datablock;
  1154.     temp : real;
  1155.     i : integer;
  1156. label exit;
  1157. begin
  1158.     limits ( plotstuff );                    { find the mins and maxs }
  1159.  
  1160.     if plotstuff.Xmin <= 0.0                 { make sure legal for log }
  1161.       then begin writeln ('Xmin <= 0, can''t take log for log plot');
  1162.                  goto exit;
  1163.            end;
  1164.  
  1165.     if plotstuff.Ymin <= 0.0                 { make sure legal for log }
  1166.       then begin writeln ('Ymin <= 0, can''t take log for log plot');
  1167.                  goto exit;
  1168.            end;
  1169.  
  1170.     edlimits ( plotstuff );                  { allow user chance to change }
  1171.  
  1172.     if plotstuff.Xmin <= 0.0                 { make sure legal for log }
  1173.       then begin writeln ('Xmin <= 0, can''t take log for log plot');
  1174.                  goto exit;
  1175.            end;
  1176.  
  1177.     if plotstuff.Ymin <= 0.0                 { make sure legal for log }
  1178.       then begin writeln ('Ymin <= 0, can''t take log for log plot');
  1179.                  goto exit;
  1180.            end;
  1181.  
  1182.     with plotstuff do
  1183.     begin                    { set up mins and maxes so grid comes out right }
  1184.  
  1185.       temp := log ( Xmin );
  1186.       if temp >= 0.0
  1187.       then Xmin := int ( temp )              { get the plotting min for >1 }
  1188.       else if frac ( temp ) = 0.0            { or for 0 < Xmin < 1 }
  1189.              then Xmin := int ( temp )
  1190.              else Xmin := int ( temp ) - 1.0;
  1191.  
  1192.       temp := log ( Xmax );
  1193.       Xmax := int ( temp );                  { and max }
  1194.       if frac ( temp ) > 0.0
  1195.          then Xmax := Xmax + 1.0;            { if any decimal part,use whole }
  1196.  
  1197.       temp := log ( Ymin );
  1198.       if temp >= 0.0
  1199.       then Ymin := int ( temp )              { get the plotting min for >1 }
  1200.       else if frac ( temp ) = 0.0            { or for 0 < Ymin < 1 }
  1201.              then Ymin := int ( temp )
  1202.              else Ymin := int ( temp ) - 1.0;
  1203.  
  1204.       temp := log ( Ymax );
  1205.       Ymax := int ( temp );                  { and max }
  1206.       if frac ( temp ) > 0.0
  1207.          then Ymax := Ymax + 1.0;            { if any decimal part,use whole }
  1208.  
  1209.       gridstuff.Ymax := Ymax;                { copy the Y limits over }
  1210.       gridstuff.Ymin := Ymin;
  1211.       gridstuff.Xmax := Xmax;                { copy the X limits over }
  1212.       gridstuff.Xmin := Xmin;
  1213.       writeln('converting data array ');
  1214.       for i := 1 to npoints do
  1215.        begin
  1216.         xdata [ i ] := log ( xdata [ i ] );  { translate linear to log }
  1217.         ydata [ i ] := log ( ydata [ i ] );
  1218.        end;
  1219.  
  1220.       scalecalc ( false, plotstuff );        { figure out the scale factors }
  1221.       gridstuff.xscale := xscale;            { copy the scale factors over }
  1222.       gridstuff.yscale := yscale;
  1223.     end;
  1224.  
  1225.     writeln (' generating grid coords ');
  1226.     logloggrid ( gridstuff );                { draw the grid }
  1227.     lineplot ( plotstuff );                  { plot the transformed data }
  1228.     loglogcal ( plotstuff );                 { put the limits on the graph }
  1229.     Htitle ( 200,Hname );                    { put names on the axes }
  1230.     Vtitle ( 200,Vname );
  1231. exit : end;
  1232.  
  1233.  
  1234.  
  1235.  
  1236. procedure semilogplot ( var plotstuff : datablock; Hname,Vname : linestring );
  1237. { generates a semi-logarithmic plot of the data in plotstuff }
  1238.  
  1239. var gridstuff : datablock;
  1240.     temp : real;
  1241.     i : integer;
  1242.  
  1243. label exit;
  1244.  
  1245. begin
  1246.     limits ( plotstuff );                    { find the mins and maxs }
  1247.  
  1248.     if plotstuff.Xmin <= 0.0                 { make sure legal for log }
  1249.       then begin writeln ('Xmin <= 0, can''t take log for semilog plot');
  1250.                  goto exit;
  1251.            end;
  1252.  
  1253.     edlimits ( plotstuff );                  { allow user chance to change }
  1254.  
  1255.     if plotstuff.Xmin <= 0.0                 { make sure legal for log }
  1256.       then begin writeln ('Xmin <= 0, can''t take log for semilog plot');
  1257.                  goto exit;
  1258.            end;
  1259.  
  1260.     with plotstuff do
  1261.     begin
  1262.  
  1263.       temp := log ( Xmin );
  1264.       if temp >= 0.0
  1265.       then Xmin := int ( temp )              { get the plotting min for >0 }
  1266.       else if frac ( temp ) = 0.0            { or for negative }
  1267.              then Xmin := int ( temp )
  1268.              else Xmin := int ( temp ) - 1.0;
  1269.  
  1270.       temp := log ( xmax );
  1271.       Xmax := int ( temp );                  { and max }
  1272.       if frac ( temp ) > 0.0
  1273.          then Xmax := Xmax + 1.0;            { if any decimal part,use whole }
  1274.  
  1275.       gridstuff.Ymax := Ymax;                { copy the Y limits over }
  1276.       gridstuff.Ymin := Ymin;
  1277.       gridstuff.Xmax := Xmax;                { copy the X limits over }
  1278.       gridstuff.Xmin := Xmin;
  1279.  
  1280.       writeln ('converting X data to log ');
  1281.       for i := 1 to npoints do
  1282.         xdata [ i ] := log ( xdata [ i ] );  { translate linear to log }
  1283.  
  1284.       scalecalc ( false, plotstuff );        { figure out the scale factors }
  1285.       gridstuff.xscale := xscale;            { copy the scale factors over }
  1286.       gridstuff.yscale := yscale;
  1287.     end;
  1288.  
  1289.     semiloggrid ( gridstuff );               { draw the grid }
  1290.     lineplot ( plotstuff );                  { plot the transformed data }
  1291.     semilogcal ( plotstuff );                { put the limits on the graph }
  1292.     Htitle ( 200,Hname );                    { put names on the axes }
  1293.     Vtitle ( 200,Vname );
  1294. exit : end;
  1295.  
  1296.  
  1297.  
  1298. procedure linearplot ( var plotstuff : datablock; Hname,Vname : linestring; grid,square : boolean );
  1299. { plots the data in plotstuff on a linear graph. Writes Hname and Vname in the
  1300.   appropriate margins and writes the limits in the margins too. If grid, a
  1301.   regular graph paper type grid is drawn, else a line at the zeros or closest
  1302.   to zero on graph is drawn. If square, scale factors are forced to the minimum
  1303.   of X or Y and both are equal. useful for circles or true geometries }
  1304.  
  1305. begin
  1306.     limits ( plotstuff );                    { scan for mins and maxes }
  1307.     edlimits ( plotstuff );                  { allow user to change limits }
  1308.     scalecalc ( false, plotstuff );          { calculate the scale factors }
  1309.  
  1310.     if grid                                  { use grid or axes ? }
  1311.       then lineargrid ( plotstuff )
  1312.       else linearaxes ( plotstuff );
  1313.  
  1314.     lineplot ( plotstuff );                  { plot the data itself }
  1315.     lincal ( plotstuff );                    { put values at the axes }
  1316.     vtitle ( 200,Vname);                     { put labels on the axes }
  1317.     htitle ( 200,Hname);
  1318. end;
  1319.  
  1320.  
  1321.  
  1322.  
  1323. begin                                       { initialization }
  1324.       assign ( aux, 'com1' );               { open the file for plotter i/o }
  1325.       rewrite ( aux );
  1326.       write ( aux, esc, device, plotteron );
  1327.  
  1328.       lastX := plotXmax;                    { init previous position vars }
  1329.       lastY := plotYmax;
  1330.       scaleX := actualX / ( plotXmax - plotXmin );   { inches / integer }
  1331.       scaleY := actualY / ( plotYmax - plotYmin );
  1332.  
  1333. end.
  1334.