OVERLAY PROCEDURE ELLIPSE_MENU;

  { This procedure is based on code by John Cary / Department of
    Wildlife Ecology / University of Wisconsin-Madison.

    Modifications are made to Cary's code to facilitate it running
    in the McPAAL environment.  }

  PROCEDURE ELLIPSE_RUN;

    TYPE
      DATA_PTR  = ^DATA_VALUE;

      DATA_VALUE = RECORD
                     X    : REAL;
                     Y    : REAL;
                     NEXT : DATA_PTR;
                   END;

    VAR
      I,J,K   : INTEGER;
      NPOINTS : INTEGER;

      X1      : REAL;
      X2      : REAL;
      Y1      : REAL;
      Y2      : REAL;

      FIRST_DATA   : DATA_PTR;
      LAST_DATA    : DATA_PTR;
      NEW_DATA     : DATA_PTR;
      HEAP_TOP     : ^INTEGER;

    PROCEDURE CALC_ELLIPSE;

      VAR
       N           : REAL;
       SX          : REAL;
       SY          : REAL;
       SXX         : REAL;
       SYY         : REAL;
       SXY         : REAL;
       XBAR        : REAL;
       YBAR        : REAL;
       VARX        : REAL;
       VARY        : REAL;
       COVXY       : REAL;
       QB          : REAL;
       QC          : REAL;
       QD          : REAL;
       LAMBDA1     : REAL;
       LAMBDA2     : REAL;
       THETA       : REAL;
       SIN_THETA   : REAL;
       COS_THETA   : REAL;
       TX          : REAL;
       TY          : REAL;
       VX          : REAL;
       VY          : REAL;
       SEMI_MAJOR  : REAL;
       SEMI_MINOR  : REAL;
       STEP        : REAL;
       ALFA        : REAL;

      PROCEDURE XY_STATS;

        BEGIN  { XY_STATS PROCEDURE }

          WRITELN;
          WRITELN('Calculating the X and Y statistics.');

          N   := 0;
          SX  := 0;
          SY  := 0;
          SXX := 0;
          SYY := 0;
          SXY := 0;

          RESET (FILEVAR2);
          SEEK  (FILEVAR2,3);          { POSTION FILE BEYOND HEADERS }

          WHILE NOT EOF(FILEVAR2) DO
            BEGIN
              READ(FILEVAR2,FILE2REC);
              WITH FILE2REC DO
                BEGIN
                  N   := N + 1;
                  SX  := SX + X;
                  SY  := SY + Y;
                  SXX := SXX + X * X;
                  SYY := SYY + Y * y;
                  SXY := SXY + X * Y;
                END;

            END;  { WHILE NOT EOF FILEVAR2 }

          XBAR  := SX / N;
          YBAR  := SY / N;
          VARX  := (SXX - SX * SX / N) / (N - 1);
          VARY  := (SYY - SY * SY / N) / (N - 1);
          COVXY := (SXY - SX * SY / N) / (N - 1);

        END;  { XY_STATS PROCEDURE }

      FUNCTION F95 (N : REAL) : REAL;

        VAR
          I   : INTEGER;

        BEGIN  { F95 FUNCTION }
          I := ROUND( N - 2 );
          IF I <= 30 THEN
            CASE I OF
              1:  F95 := 199.5;
              2:  F95 := 19.0;
              3:  F95 := 9.55;
              4:  F95 := 6.94;
              5:  F95 := 5.79;
              6:  F95 := 5.14;
              7:  F95 := 4.74;
              8:  F95 := 4.46;
              9:  F95 := 4.26;
              10: F95 := 4.10;
              11: F95 := 3.98;
              12: F95 := 3.89;
              13: F95 := 3.81;
              14: F95 := 3.74;
              15: F95 := 3.68;
              16: F95 := 3.63;
              17: F95 := 3.59;
              18: F95 := 3.55;
              19: F95 := 3.52;
              20: F95 := 3.49;
              21: F95 := 3.47;
              22: F95 := 3.44;
              23: F95 := 3.42;
              24: F95 := 3.40;
              25: F95 := 3.39;
              26: F95 := 3.37;
              27: F95 := 3.35;
              28: F95 := 3.34;
              29: F95 := 3.33;
              30: F95 := 3.32;
            END
          ELSE
            IF I <= 40 THEN
              F95 := 3.32 - ( I - 30 ) / 10 * 0.09
            ELSE
              IF I <= 60 THEN
                F95 := 3.23 - ( I - 40 ) / 20 * 0.08
              ELSE
                IF I <= 120 THEN
                  F95 := 3.15 - ( I - 60 ) / 60 * 0.08
                ELSE
                  IF I <= 240 THEN
                    F95 := 3.07 - ( I - 120) / 120 * 0.07
                  ELSE
                    F95 := 3.0;

        END;  { F95 FUNCTION }

      PROCEDURE CONSTRUCT_ELLIPSE;

        VAR
          I   : INTEGER;

        BEGIN { CONSTRUCT_ELLIPSE }

          WRITELN;
          WRITELN('Constructing the 95% ellipse');

          QB         := -VARX - VARY;
          QC         := VARX*VARY - COVXY*COVXY;
          QD         := SQRT(QB*QB - 4*QC);
          LAMBDA1    := (-QB + QD) / 2;
          LAMBDA2    := (-QB - QD) / 2;
          THETA      := ARCTAN(( LAMBDA1 - VARX) / COVXY);
          SIN_THETA  := SIN(THETA);
          COS_THETA  := COS(THETA);
          SEMI_MAJOR := SQRT(2*F95(N)*LAMBDA1);
          SEMI_MINOR := SQRT(2*F95(N)*LAMBDA2);
          STEP       := 2 * PI / 40;

          FOR I := 0 TO 40 DO
            BEGIN
              ALFA := STEP * I;
              TX   := SEMI_MAJOR * COS(ALFA);
              TY   := SEMI_MINOR * SIN(ALFA);
              VX   := (TX * COS_THETA - TY * SIN_THETA) + XBAR;
              VY   := (TX * SIN_THETA + TY * COS_THETA) + YBAR;

              NEW(NEW_DATA);
              NEW_DATA^.X := VX;
              NEW_DATA^.Y := VY;
              IF FIRST_DATA = NIL
                THEN FIRST_DATA      := NEW_DATA
                ELSE LAST_DATA^.NEXT := NEW_DATA;
              LAST_DATA       := NEW_DATA;
              LAST_DATA^.NEXT := NIL;

            END;  { FOR I = 0 TO 40 }

        END;  { CONSTRUCT_ELLIPSE PROCEDURE }

      BEGIN  { CALC_ELLIPSE PROCEDURE }
        XY_STATS;
        CONSTRUCT_ELLIPSE;
        AREA := 2 * PI * F95(N) * SQRT(LAMBDA1 * LAMBDA2);

      END;  { CALC_ELLIPSE PROCEDURE }


    BEGIN  { ELLIPSE PROCEDURE }

      { OPEN THE FILES }

      ASSIGN (FILEVAR2,FILEOUT);
      RESET  (FILEVAR2);          { POSITION POINTER TO BEGINNING OF FILE }

      MARK (HEAP_TOP);
      FIRST_DATA := NIL;

      CALC_ELLIPSE;


      AREA := AREA * METER_VALUE * METER_VALUE;
      AREAK := AREA / 1000;
      AREAK := AREAK / 1000;

      WRITELN;
      IF AREA < 10000 THEN
        WRITELN('Ellipse Area: ',AREA:8:4,' square meters.')
      ELSE
        WRITELN('Ellipse Area: ',AREAK:8:4,'  square kilometers.');

      KEYBOARD_PAUSE;

      KEYVALUE := 'R';

      { PLOTTING THE ELIPSE }

      IF DRAWCHAR = 'Y' THEN
        BEGIN

          IF STUDYFILE <> '' THEN
            BEGIN
              ASSIGN(FILEVAR3,STUDYFILE);
              RESET (FILEVAR3);
              STUDYOPEN := TRUE;
            END;

          HIRES;
          HIRESCOLOR(YELLOW);

          LINE_OUT(1,1,' 95% Ellipse');

          { GET GRID SPAN AND THE LOW AN HIGH POINTS }

          NPOINTS := 1;

          NEW_DATA := FIRST_DATA;
          WHILE NEW_DATA <> NIL DO
            WITH NEW_DATA^ DO
              BEGIN
                IF (NPOINTS = 1) OR ( X < XLOW)  THEN XLOW  := X;
                IF (NPOINTS = 1) OR ( X > XHIGH) THEN XHIGH := X;
                IF (NPOINTS = 1) OR ( Y < YLOW)  THEN YLOW  := Y;
                IF (NPOINTS = 1) OR ( Y > YHIGH) THEN YHIGH := Y;
                NPOINTS := NPOINTS + 1;
                NEW_DATA := NEXT;
              END;

          GRID_CALCULATIONS;

          NEW_DATA := FIRST_DATA;

          X1       := NEW_DATA^.X;
          Y1       := NEW_DATA^.Y;
          NEW_DATA := NEW_DATA^.NEXT;

          WHILE NEW_DATA <> NIL DO
            WITH NEW_DATA^ DO
              BEGIN
                X2 := X;
                Y2 := Y;
                HIRES_VECTOR(X1,Y1,X2,Y2,XOFFSET,YOFFSET,GRIDFACTOR);
                X1 := X2;
                Y1 := Y2;
                NEW_DATA := NEXT;
              END;  { WITH NEW_DATA^ DO }

          { WRITE OUT THE FILE INFORMATION }

          LINE_OUT(60,4,'Data file:');
          LINE_OUT(64,5,FILEOUT);

          IF STUDYFILE <> '' THEN
            BEGIN
              LINE_OUT(60,7,'Map file:');
              LINE_OUT(64,8,STUDYFILE);
            END;

          IF REPLAYFILE <> '' THEN
            BEGIN
              LINE_OUT(60,10,'Replay file:');
              LINE_OUT(64,11,REPLAYFILE);
            END;

          LINE_OUT(62,13,'AREA:');
          GOTOXY(62,14);
          IF AREA <= 10000 THEN
            BEGIN
              WRITE (AREA:8:4);
              LINE_OUT(62,15,'Sq. meters.');
            END
          ELSE
            BEGIN
              WRITE (AREAK:8:4);
              LINE_OUT(62,15,'Sq. kilometers.');
            END;

          IF STUDYFILE <> '' THEN
            BEGIN
              LINE_OUT(1,25,SPACE79);
              LINE_OUT(1,25,'Draw the study file area overlay? (Y|N) ');

              YES_NO(STUDYDRAWN);

              LINE_OUT(1,25,SPACE79);

              IF STUDYDRAWN = 'Y' THEN
                BEGIN                            { DRAW THE STUDY AREA }

                  HIRES;
                  HIRESCOLOR(YELLOW);

                  { SAVE THE MIN AND MAX VALUES }

                  SXLOW := XLOW;
                  SYLOW := YLOW;
                  SZLOW := ZLOW;
                  SXHIGH := XHIGH;
                  SYHIGH := YHIGH;
                  SZHIGH := ZHIGH;

                  SEEK (FILEVAR3,1);             { MIN AND MAX FOR STUDY AREA }
                  READ (FILEVAR3,FILE3REC);

                  XLOW := MIN_VAL(FILE3REC.X1,XLOW);
                  YLOW := MIN_VAL(FILE3REC.Y1,YLOW);
                  ZLOW := MIN_VAL(FILE3REC.Z1,ZLOW);
                  XHIGH := MAX_VAL(FILE3REC.X2,XHIGH);
                  YHIGH := MAX_VAL(FILE3REC.Y2,YHIGH);
                  ZHIGH := MAX_VAL(FILE3REC.Z2,ZHIGH);

                  GRID_CALCULATIONS;

                  { REDRAW THE ELLIPSE AND THE STUDY AREA }

                  LINE_OUT(1,1,' 95% Ellipse');

                  NEW_DATA := FIRST_DATA;

                  X1       := NEW_DATA^.X;
                  Y1       := NEW_DATA^.Y;
                  NEW_DATA := NEW_DATA^.NEXT;

                  WHILE NEW_DATA <> NIL DO
                    WITH NEW_DATA^ DO
                      BEGIN
                        X2 := X;
                        Y2 := Y;
                        HIRES_VECTOR(X1,Y1,X2,Y2,XOFFSET,YOFFSET,GRIDFACTOR);
                        X1 := X2;
                        Y1 := Y2;
                        NEW_DATA := NEXT;
                      END;  { WITH NEW_DATA^ DO }

                  SEEK (FILEVAR3,2);        { DATA BEGINS AT THE THIRD RECORD }

                  WHILE NOT EOF(FILEVAR3) DO
                    BEGIN
                      READ(FILEVAR3,FILE3REC);
                      WITH FILE3REC DO
                        HIRES_VECTOR(X1,Y1,X2,Y2,XOFFSET,YOFFSET,GRIDFACTOR);
                    END;

                  { WRITE OUT THE FILE INFORMATION }

                  LINE_OUT(60,4,'Data file:');
                  LINE_OUT(64,5,FILEOUT);


                  IF STUDYFILE <> '' THEN
                    BEGIN
                      LINE_OUT(60,7,'Map file:');
                      LINE_OUT(64,8,STUDYFILE);
                    END;

                  IF REPLAYFILE <> '' THEN
                    BEGIN
                      LINE_OUT(60,10,'Replay file:');
                      LINE_OUT(64,11,REPLAYFILE);
                    END;

                  LINE_OUT(62,13,'AREA:');
                  GOTOXY(62,14);
                  IF AREA <= 10000 THEN
                    BEGIN
                      WRITE (AREA:8:4);
                      LINE_OUT(62,15,'Sq. meters.');
                    END
                  ELSE
                    BEGIN
                      WRITE (AREAK:8:4);
                      LINE_OUT(62,15,'Sq. kilometers.');
                    END;

                END;  { IF STUDYDRAWN = Y }

            END;  { IF STUDYFILE <> '' }

          IF REPLAYFILE <> '' THEN
            BEGIN
              LINE_OUT(1,25,SPACE79);
              LINE_OUT(1,25,'Do you want to add this graph to the replay file? (Y|N); ');

              YES_NO(KEYVALUE);

              IF KEYVALUE = 'Y' THEN
                BEGIN

                  IF NOT EXIST(REPLAYFILE) THEN INIT_REPLAY_FILE;

                  ASSIGN (FILEVAR4,REPLAYFILE);
                  RESET  (FILEVAR4);
                  REPLAYOPEN := TRUE;

                  { WRITE OUT THIS PLOT. }

                  IF STUDYDRAWN = 'Y' THEN
                    IF NOT STUDY_IN_REPLAY THEN
                      ADD_GRAPH('STUDYFILE');

                  SEEK (FILEVAR4,1);             { WHOLE FILE MIN AND MAX }
                  READ (FILEVAR4,FILE4REC);

                  FILE4REC.X1 := MIN_VAL(FILE4REC.X1,SXLOW);
                  FILE4REC.Y1 := MIN_VAL(FILE4REC.Y1,SYLOW);
                  FILE4REC.Z1 := MIN_VAL(FILE4REC.Z1,SZLOW);
                  FILE4REC.X2 := MAX_VAL(FILE4REC.X2,SXHIGH);
                  FILE4REC.Y2 := MAX_VAL(FILE4REC.Y2,SYHIGH);
                  FILE4REC.Z2 := MAX_VAL(FILE4REC.Z2,SZHIGH);
                  FILE4REC.LINE_TYPE := FILE4REC.LINE_TYPE + 40;

                  SEEK (FILEVAR4,1);
                  WRITE(FILEVAR4,FILE4REC);      { WRITE RECORD NUMBER 1 }
                  READ (FILEVAR4,FILE4REC);      { READ RECORD NUMBER 3 }

                  FILE4REC.X2 := FILE4REC.X2 + 1; { NUMBER OF GRAPHS IN FILE }
                  SEEK (FILEVAR4,2);
                  WRITE(FILEVAR4,FILE4REC);

                  SEEK (FILEVAR4,FILESIZE(FILEVAR4)-1); { LAST RECORD IN THE FILE }
                  READ (FILEVAR4,FILE4REC);

                  FILE4REC.X1 := -5;             { BEGIN ELLIPSE DATA }
                  FILE4REC.Y1 := -10;
                  FILE4REC.X2 := -10;
                  FILE4REC.Y2 := -10;

                  SEEK (FILEVAR4,FILESIZE(FILEVAR4)-1);
                  WRITE(FILEVAR4,FILE4REC);

                  FILE4REC.X1 := SXLOW;          { BUILD SECOND GRAPH HEADER }
                  FILE4REC.Y1 := SYLOW;
                  FILE4REC.Z1 := SZLOW;
                  FILE4REC.X2 := SXHIGH;
                  FILE4REC.Y2 := SYHIGH;
                  FILE4REC.Z2 := SZHIGH;
                  FILE4REC.LINE_TYPE := 40;
                  WRITE(FILEVAR4,FILE4REC);

                  { WRITE OUT THE ELLIPSE VECTORS }

                  NEW_DATA := FIRST_DATA;

                  FILE4REC.X1 := NEW_DATA^.X;
                  FILE4REC.Y1 := NEW_DATA^.Y;
                  FILE4REC.Z1 := 0.0;
                  FILE4REC.Z2 := 0.0;
                  FILE4REC.LINE_TYPE := 1;
                  NEW_DATA := NEW_DATA^.NEXT;

                  WHILE NEW_DATA <> NIL DO
                    WITH NEW_DATA^ DO
                      BEGIN
                        FILE4REC.X2 := X;
                        FILE4REC.Y2 := Y;
                        WRITE(FILEVAR4,FILE4REC);
                        FILE4REC.X1 := FILE4REC.X2;
                        FILE4REC.Y1 := FILE4REC.Y2;
                        NEW_DATA := NEXT;
                      END;

                  { WRITE OUT THE TRAILING RECORD }

                  FILE4REC.X1 := 0.0;
                  FILE4REC.Y1 := 0.0;
                  FILE4REC.Z1 := 0.0;
                  FILE4REC.X2 := 0.0;
                  FILE4REC.Y2 := 0.0;
                  FILE4REC.Z2 := 0.0;
                  FILE4REC.LINE_TYPE := 0;
                  WRITE(FILEVAR4,FILE4REC);

                END;  { IF KEYVALUE = Y }

            END;  { IF REPLAYFILE <> '' };

          IF STUDYOPEN  THEN CLOSE (FILEVAR3);
          IF REPLAYOPEN THEN CLOSE (FILEVAR4);

          KEYBOARD_PAUSE;

        END;  { DRAWCHAR = Y }

      RELEASE (HEAP_TOP);

      CLOSE (FILEVAR2);

      KEYVALUE := 'R';

    END;  { ELLIPSE PROCEDURE }

  BEGIN  { ELLIPSE_MENU }

    KEYVALUE := 'R';

    WHILE KEYVALUE = 'R' DO
    BEGIN

    CLRSCR;
    DISPLAY_COLOR(CYAN);

    LINE_OUT(30,2,'(8) Ellipse Algorithm');
    LINE_OUT(10,4,'1  Data file:');
    LINE_OUT(10,6,'2  Study area file:');
    LINE_OUT(10,8,'3  Plot replay file:');
    LINE_OUT(10,10,'4  Text output displayed on:');
    LINE_OUT(10,12,'5  Graphics displayed on screen (Y|N):');
    LINE_OUT(10,14,'6  ');
    LINE_OUT(10,16,'7  ');
    LINE_OUT(10,18,'8  Scale of your map as meters between adjacent coordinates: ');

    TEXTCOLOR(YELLOW);
    LINE_OUT(24,4,FILEOUT);
    LINE_OUT(30,6,STUDYFILE);
    LINE_OUT(31,8,REPLAYFILE);

    CASE UPCASE(PRINTCHAR) OF
      'D' : PRINTSTR := 'DISPLAY ONLY';
      'P' : PRINTSTR := 'PRINTER ONLY';
      'B' : PRINTSTR := 'BOTH DISPLAY AND PRINTER';
    END;

    LINE_OUT(39,10,PRINTSTR);

    IF DRAWCHAR = 'N'
      THEN DRAWSTR := 'NO'
      ELSE DRAWSTR := 'YES';

    LINE_OUT (49,12,DRAWSTR);

    GOTOXY(71,18);
    WRITE (METER_VALUE:8:4);

    DISPLAY_COLOR(RED);

    LINE_OUT(7,21,'P  Process Data');
    LINE_OUT(37,21,'E  Exit to Main Menu');
    TEXTCOLOR(YELLOW);
    GOTOXY(1,25);

    KEYVALUE := ' ';

    WHILE NOT (UPCASE(KEYVALUE) IN ['E','R']) DO
      BEGIN

        KEYVALUE := ' ';
        WHILE NOT (UPCASE(KEYVALUE) IN ['1'..'5','8','E','P']) DO
          READ    (KBD,KEYVALUE);
        KEYVALUE := UPCASE(KEYVALUE);

        GOTOXY(1,23);
        DELLINE;
        DELLINE;

        CASE KEYVALUE OF
          '1': MENU_CALL(1);
          '2': MENU_CALL(2);
          '3': MENU_CALL(3);
          '4': MENU_CALL(4);
          '5': MENU_CALL(5);
          '8': MENU_CALL(8);
          'P': BEGIN
               KEEP_GOING := TRUE;
               STUDYOPEN := FALSE;
               REPLAYOPEN := FALSE;

               PROCESSING_VERIFY;

               IF (KEEP_GOING) AND (METER_VALUE <= 0) THEN
                 BEGIN
                   LINE_OUT(1,23,'The distance between adjacent coordinates must be entered.');
                   KEEP_GOING := FALSE;
                 END;

               IF KEEP_GOING THEN
                 BEGIN
                   CLRSCR;
                   ELLIPSE_RUN;
                 END;
               END;  { CASE P }

        END;  { CASE KEYVALUE OF }

        GOTOXY(1,23);

      END;  { WHILE NOT (KEYVALUE IN ['E','R']) }

    END;  { WHILE KEYVALUE = 'R' }

    KEYVALUE := ' ';

  END;   { ELLIPSE_MENU PROCEDURE }

