{ Copyright by  T. W. Lougheed  27 April 1981 }

{ This program plots a set of points given by the function  Y = F(X). }

{ This is a plotting program that uses the graphic symbols of
the  VDP 80's  VIO  board.  It puts the VIO board in the extended
character set mode,  plots all the points given,  then returns
to the original mode.   All the magic with the screen takes place
in the external module PLOT.   All values of the points to be plotted
are generated by the external function  F. }

{ First version  20 August 1980

  By    T. W. Lougheed
        Dept. T. & A. Mechanics
        Thurston Hall,  Cornell U.
        Ithaca, NY  14853

  Last version   17 January 1981 }

{ This program is in the public domain and may not be sold by any person
or corperation without express permission of the author. }


PROGRAM  GRAPH14;

CONST   VERSION = 14;
        ROWS  = 23;  { Number of rows used for graphics on the screen. }
                     { Number of columns is assumed  80  see PLOT to change. }

TYPE    POINT = RECORD  X, Y :REAL END;

VAR     C               : CHAR;
        CENTER          : POINT;
        DATA            : ARRAY[ 1..100 ] OF POINT;
        DX,                             { Increment to make along X axis. }
        START, STOP,                    { First and last X values. }
        TOP, BOTTOM     : REAL;         { Largest & smallest Y values. }
        K, L            : INTEGER;      { Dummy indicies. }
 

{ This is the function to be plotted. }

EXTERNAL FUNCTION  F( X :REAL) :REAL;


{ This procedure plots an  X,Y  graph of the DATA points given on
the screen.  It handles the video itself, without outside help. }

EXTERNAL PROCEDURE  PLOT (
  L        : INTEGER;  { Number of points to plot. }
  VAR DATA : ARRAY[ M..N :INTEGER ] OF POINT;
  ORIGIN   : POINT;  { Center of the axes -- if out-of-bounds it is set to
                        lie at the upper corner of the screen. }
  X_MIN,
  X_MAX,      { Bounds for X & Y values.  If MIN <= MAX then .. }
  Y_MIN,      { .. scaling is done automaticly for that axis.   }
  Y_MAX    : REAL
 );



{ This procedure clears the video screen. }

PROCEDURE CLEAR;
   { Writing controll-Z erases the screen. }
   BEGIN  WRITE( CHR($1A) )  END;



{ The following procedure positions the cursor on the
screen to the row & column indicated,  using escape codes
appropriate to an IMSAI VIO board. }

PROCEDURE CURSOR( ROW, COLUMN :INTEGER);
   CONST  OFFSET = $1F;    { The VIO offsets all co-ordinates. }
          ESC    = $1B;    { ASCII <escape> character code. }
   VAR  A, B  : CHAR;
   BEGIN
   A := CHR( $1F + ROW );
   B := CHR( $1F + COLUMN );
   WRITE( CHR(ESC), '=', A, B );
   END;


  
{ Prints the plotters sign-on message. }

PROCEDURE SIGN_ON;
   BEGIN
   CLEAR;  { Erase screen. }
   WRITELN;
   WRITELN( '           F U N C T I O N    P L O T T E R          (version ',
     VERSION, ') ' );
   WRITELN;
   WRITELN;
   WRITELN(
    '  This program plots the value of the function "F" provided when the' );
   WRITELN(
    'program was linked.  Note that the abscissa (X-axis) runs down the' );
   WRITELN(
    'screen and the ordinate (Y-axis) runs across:  they are rotated ninety' );
   WRITELN( 'degrees from the customary directions for plotting functions.' );
   WRITELN;
   WRITELN(
    '  The program will now ask you for initial and final values of  X  and' );
   WRITELN(
    'extreem values for Y in order to determine the scales for the two axes.'
    );
   WRITELN(
    'After the plot is made you may start over, so if the plot does not' );
   WRITELN( 'satisfy you, you may try again using different paramiters.' );
   WRITELN; WRITELN;
   END;



{ This procedure querries the user for paramiters. }

PROCEDURE PARAMITERS;
   BEGIN

   REPEAT
      WRITELN;
      WRITE( 'Where is the plot to start on the abscissa ? ',
       '(X axis)  ' );  READ( START );
      WRITE( ' ... and where is it to stop ? ' );  READ( STOP );
      IF START = STOP THEN WRITELN( 'HOLD IT !  They''re the same. ' );
      UNTIL START <> STOP;

   WRITELN;
   WRITE( 'Do you want automatic scaling ?  (Y/N)  ' );  READ( C );  WRITELN;
   IF C IN [ 'n', 'N' ]
      THEN REPEAT
         WRITE( 'What is the lower limit for plotted values ',
          'along the ordinate ? (Y-Axis)  ' );    READ( BOTTOM );
         WRITE( ' ... and the upper limit ? ' );  READ( TOP );
         IF BOTTOM = TOP THEN WRITELN( 'Wait a minute:  They''re the same !' );
         UNTIL BOTTOM <> TOP
      ELSE BEGIN  BOTTOM := 0; TOP := 0  END;  { Forces auto-scaling. }

   END;



BEGIN  { GRAPHICS. }

{ Introduce the program: }  SIGN_ON;

REPEAT

   PARAMITERS; { Find out where to start and stop,  &c. }

   { Figure what the points ought to be. }
   WRITELN;  WRITE( 'Calculating points ' );
   L  := 3*ROWS;
   DX := (STOP - START)/(L - 1);
   FOR K := 1 TO L DO WITH DATA[K] DO
      BEGIN
      WRITE('.');  IF K MOD 5 = 0 THEN WRITE( ' ' );  { Talley of points. }
      IF K MOD 50 = 0 THEN BEGIN  WRITELN; WRITE( ' ':18 )  END;
      X := K*DX + START;  Y := F(X);  { This is the only appearance of "F" }
      END;
   WRITELN( '   Done. ' );


   WRITELN;
   WRITE( 'Hit any key when you''re ready to see the plot.' );
   READ( C );  { Dummy input. }


   { Call plotting routine. }

   { CENTER is the location of the origin 
   -- if impropper it will default to the upper corner. }

   CENTER.X := 0.0;   CENTER.Y := 0.0;
    { For the meaning of the paramiters, consult comments on PLOT. }
   PLOT( L, DATA, CENTER, START, STOP, BOTTOM, TOP );

   WRITELN;
   REPEAT
      WRITE( 'Another plot ? (Y/N)  ' );  READ( C );  WRITELN;
      UNTIL C IN [ 'y', 'Y', 'n', 'N' ];

   UNTIL C IN [ 'n', 'N' ];


WRITELN;
WRITELN( 'Normal end of program.' );

END
.

