OVERLAY PROCEDURE CONCAVE_HULL_MENU;


  { Generates a home range area about the minimum and maximum Y values
    along an X axis. The X axis is divided into n arbitrary points giving
    a delta X. A min and max value is saved for each range of delta X }

    VAR
      GRID_NUM : INTEGER;

  PROCEDURE CONCAVE_HULL;

    { This is a home grown procedure to connect the external points along
      a given home range area. A delta X is given to determine the
      resolution of the 'grid' width. The smaller the delta x, the
      slower the program runs. }

      VAR

        CURVE_HIGH : ARRAY[1..2,1..500] OF REAL;
                     { X AND Y POINTS OF THE UPPER CURVE }
        CURVE_LOW  : ARRAY[1..2,1..500] OF REAL;
                     { X AND Y POINTS OF THE LOWER CURVE }
        XHPOINTS   : ARRAY [1..500] OF REAL;  { POINTS TO CALCULATE AREA }
        YHPOINTS   : ARRAY [1..500] OF REAL;  { POINTS TO CALCULATE AREA }
        XLPOINTS   : ARRAY [1..500] OF REAL;
        YLPOINTS   : ARRAY [1..500] OF REAL;

        I          : INTEGER; { A WORK VARIABLE }
        JH         : INTEGER; { A WORK VARIABLE }
        JL         : INTEGER; { A WORK VARIABLE }
        MAXINDEX   : INTEGER; { LARGES INDEX USED IN GETTING THE POINTS }
        NPOINTS    : INTEGER; { NUMBER OF POINTS IN THE DATA FILE }
        NUM_EMPTY  : INTEGER; { PARTIAL NUMBER OF SECTION WITH NO POINTS }
        SCREENCT   : INTEGER; { NUMBER OF LINES PRINTED TO THE SCREEN }
        TOTAL_POINTS : INTEGER; { TOTAL NUMBER OF PLOTTED POINTS - VERTICIES }
        XINDEX     : INTEGER; { INDEX INTO THE TWO CURVE ARRAYS }
        X1I        : INTEGER;
        X2I        : INTEGER;
        Y1I        : INTEGER;
        Y2I        : INTEGER;

        AREAI      : REAL;   { TOTAL AREA OF THE HOME RANGE BY INTEGRATION }
        AREAIK     : REAL;   { INTEGRATED AREA IN SQUARE KILOMETERS }
        AREAG      : REAL;   { TOTAL AREA OF THE HOME RANGE BY GRID COUNT }
        AREAGK     : REAL;   { GRID COUNT AREA IN SQUARE KILOMETERS }
        AREA1      : REAL;   { INCREMENTAL AREA OF THE HOME RANGE }
        TOTAL_METERS  : REAL; { TOTAL METERS OF ENTIRE X RANGE }
        XSECTIONS  : REAL;   { THE NUMBER OF X SECTIONS }
        XVALUE     : REAL;   { CURRENT X CO-ORDINATE }
        YSECTIONS  : REAL;   { NUMBER OF Y SECTIONS }
        YFIRST     : REAL;   { FIRST Y VALUE IN INTERPOLATION }
        YLAST      : REAL;   { LAST Y VALUE IN INTERPOLATION }
        YMEAN      : REAL;   { AVERAGE OF YLAST + YFIRST }


    BEGIN  { CONCAVE_HULL }

      { OPEN THE FILES  }

      ASSIGN (FILEVAR2,FILEOUT);
      RESET  (FILEVAR2);               { POSITION POINTER TO BEGIN OF INPUT FILE }

      STUDYOPEN := FALSE;
      REPLAYOPEN := FALSE;
      { FIRST , LOAD THE MIN AND MAX VALUES FROM THE DATA FILE }

      WRITELN (OUTPUT,' ');
      WRITELN (OUTPUT,'Loading extreme limits of the data file.');

      SEEK (FILEVAR2,1);
      READ (FILEVAR2,FILE2REC);

      XLOW  := FILE2REC.X;
      YLOW  := FILE2REC.Y;
      ZLOW  := FILE2REC.Z;
      NPOINTS := FILE2REC.RECORD_NO;

      READ (FILEVAR2,FILE2REC);

      XHIGH := FILE2REC.X;
      YHIGH := FILE2REC.Y;
      ZHIGH := FILE2REC.Z;

      { SET UP DIVISION POINTS }

      XDELTA := XHIGH - XLOW;
      YDELTA := YHIGH - YLOW;

      { SET UP USER REQUESTED GRID SQUARE SIZE }

      TOTAL_METERS := METER_VALUE * XDELTA;
      XSECTIONS    := TOTAL_METERS / SECTION_VALUE;
      XGRID_NUM    := ROUND(INT(XSECTIONS));
      IF FRAC(XSECTIONS) > 0 THEN XGRID_NUM := XGRID_NUM + 1;
      XDELTA       := XGRID_NUM * SECTION_VALUE / METER_VALUE;
      XHIGH        := XDELTA + XLOW;

      { DO THE SAME FOR THE Y VALUES }

      TOTAL_METERS := METER_VALUE * YDELTA;
      YSECTIONS    := TOTAL_METERS / SECTION_VALUE;
      YGRID_NUM    := ROUND(INT(YSECTIONS));
      IF FRAC(YSECTIONS) > 0 THEN YGRID_NUM := YGRID_NUM + 1;
      YDELTA       := YGRID_NUM * SECTION_VALUE / METER_VALUE;
      YHIGH        := YDELTA + YLOW;

      IF XDELTA > YDELTA THEN
        BEGIN
          GRID_NUM := XGRID_NUM;
          GRID_SPAN := XDELTA;
          GRIDLOW   := XLOW;
          GRIDHIGH  := XHIGH;
        END
      ELSE
        BEGIN
          GRID_NUM  := YGRID_NUM;
          GRID_SPAN := YDELTA;
          GRIDLOW   := YLOW;
          GRIDHIGH  := YHIGH;
        END;

      { INITIALIZE THE CURVES ARRAYS }

      FOR I := 1 TO GRID_NUM DO
        BEGIN
          CURVE_HIGH[1,I] := XLOW -1;
          CURVE_HIGH[2,I] := YLOW -1;
          CURVE_LOW[1,I]  := XHIGH + 1;
          CURVE_LOW[2,I]  := YHIGH + 1;
        END;  { FOR I = 1 TO GRID_NUM }

      MAXINDEX := 0;

      { SECOND PASS, GETTING THE MIN AND MAX Y VALUES FOR EACH X DIVISION }

      WRITELN (OUTPUT,' ');
      WRITELN (OUTPUT,'Second pass, creating the CONCAVE polygon.');

      RESET (FILEVAR2);
      SEEK  (FILEVAR2,3);              { POSITION BEYOND FILE HEADERS }

      WHILE NOT EOF(FILEVAR2) DO
        BEGIN
          READ (FILEVAR2,FILE2REC);
          WITH FILE2REC DO
            BEGIN
              XVALUE := ( X - XLOW) * GRID_NUM / XDELTA;
              XINDEX := TRUNC(XVALUE) + 1;
              IF XINDEX > GRID_NUM THEN XINDEX := GRID_NUM;
              IF XINDEX < 1        THEN XINDEX := 1;
              IF XINDEX > MAXINDEX THEN MAXINDEX := XINDEX;

              { HAVE THE INDEX, NOW SEE IF Y IS A MIN OR MAX }

              IF Y > CURVE_HIGH[2,XINDEX] THEN
                BEGIN
                  CURVE_HIGH[1,XINDEX] := X;
                  CURVE_HIGH[2,XINDEX] := Y;
                END;

              IF Y < CURVE_LOW[2,XINDEX] THEN
                BEGIN
                  CURVE_LOW[1,XINDEX] := X;
                  CURVE_LOW[2,XINDEX] := Y;
                END;

            END;  { WITH FILE2REC }

        END;  { WHILE NOT EOF(FILEVAR2) }

      { THE TWO CURVE ARRAYS HAVE THE UPPER AND LOWER CURVE OF THE HOME RANGE
        CALCULATE THE AREA OF THE HOME RANGE }

  { ************************************************************************ }
  { *************** AREA BY INTEGRATION ************************************ }

      { This is always done as the graph is done with these values }

      AREAI := 0.0;
      METER_SQUARE := METER_VALUE * METER_VALUE;

      WRITELN;
      WRITELN('Isolating the polygon verticies.');

      JH := 0;

      { SEE WHICH END POINT TO USE }

      IF CURVE_LOW[1,1] < CURVE_HIGH[1,1] THEN
        BEGIN
          JH := JH + 1;
          XHPOINTS[JH] := CURVE_LOW[1,1];
          YHPOINTS[JH] := CURVE_LOW[2,1];
        END;

      { GET MAX POINTS FROM ALL GRID SECTIONS. IF THE X VALUE IS STILL XLOW-1,
        THEN THAT GRID SECTION HAD NO POINT IN IT. }

      FOR I := 1 TO MAXINDEX DO
        IF CURVE_HIGH[1,I] > XLOW-1 THEN
          BEGIN
            JH := JH + 1;
            XHPOINTS[JH] := CURVE_HIGH[1,I];
            YHPOINTS[JH] := CURVE_HIGH[2,I];
          END;  { IF CURVE_HIGH[1,I] > XLOW-1 }

      WRITELN;
      IF PRECISION = 'I'
        THEN WRITELN('Calculating the area of the polygon by integration.')
        ELSE WRITELN('Calculating the area of the polygon by grid cell count.');

      { NOW GET THE HIGH END POINT }

      IF CURVE_LOW[1,MAXINDEX] > CURVE_HIGH[1,MAXINDEX] THEN
        BEGIN
          JH := JH + 1;
          XHPOINTS[JH] := CURVE_LOW[1,MAXINDEX];
          YHPOINTS[JH] := CURVE_LOW[2,MAXINDEX];
        END;

      { CALCULATE AREA UNDER THE HIGH CURVE }

      FOR I := 1 TO JH-1 DO
        BEGIN
          CURVE_AREA(XHPOINTS[I],YHPOINTS[I],XHPOINTS[I+1],YHPOINTS[I+1],AREA1);
          AREAI := AREAI + AREA1;
        END;

      { REPEAT THE PROCEDURE FOR THE LOWER CURVE }

      JL := 0;

      IF CURVE_HIGH[1,1] <= CURVE_LOW[1,1] THEN
        BEGIN
          JL := JL + 1;
          XLPOINTS[JL] := CURVE_HIGH[1,1];
          YLPOINTS[JL] := CURVE_HIGH[2,1];
        END;

      FOR I := 1 TO MAXINDEX DO
        IF CURVE_LOW[1,I] < XHIGH + 1 THEN
          BEGIN
            JL := JL + 1;
            XLPOINTS[JL] := CURVE_LOW[1,I];
            YLPOINTS[JL] := CURVE_LOW[2,I];
          END;

      { NOW GET THE HIGH END POINT }

      IF CURVE_HIGH[1,MAXINDEX] >= CURVE_LOW[1,MAXINDEX] THEN
        BEGIN
          JL := JL + 1;
          XLPOINTS[JL] := CURVE_HIGH[1,MAXINDEX];
          YLPOINTS[JL] := CURVE_HIGH[2,MAXINDEX];
        END;

      { SUBTRACT AREA UNDER THE LOW CURVE FROM THE AREA UNDER THE HIGH CURVE }

      FOR I := 1 TO JL -1 DO
        BEGIN
          CURVE_AREA(XLPOINTS[I],YLPOINTS[I],XLPOINTS[I+1],YLPOINTS[I+1],AREA1);
          AREAI := AREAI - AREA1;
        END;

      AREAI := AREAI * METER_SQUARE;
      AREAIK := AREAI / 1000;
      AREAIK := AREAIK / 1000;

  { ************************************************************************ }
  { *************** AREA BY GRID SQUARE ************************************ }

      AREAG     := 0;
      YFIRST    := -100;
      NUM_EMPTY := 0;
      XGRID_NUM := 0;  { XGRID_NUM WILL HOLD THE AREA IN GRID SQUARE NUMBERS }
      YGRID_NUM := 0;  { YGRID_NUM WILL BE A WORK VARIABLE }

      FOR I := 1 TO MAXINDEX DO
        IF CURVE_HIGH[1,I] > XLOW-1 THEN
          BEGIN
            IF NUM_EMPTY > 0 THEN
              BEGIN
                YLAST     := CURVE_HIGH[2,I];
                YMEAN     := (YFIRST + YLAST) / 2;
                YGRID_NUM := ROUND(INT(YMEAN * METER_VALUE / SECTION_VALUE));

                IF FRAC(YMEAN * METER_VALUE / SECTION_VALUE) > 0
                  THEN YGRID_NUM := YGRID_NUM + 1;

                XGRID_NUM := XGRID_NUM + YGRID_NUM * NUM_EMPTY;
                NUM_EMPTY := 0;
              END;

            YFIRST    := CURVE_HIGH[2,I];
            YGRID_NUM := ROUND(INT(CURVE_HIGH[2,I] * METER_VALUE / SECTION_VALUE));
            IF FRAC(CURVE_HIGH[2,I] * METER_VALUE / SECTION_VALUE) > 0
              THEN YGRID_NUM := YGRID_NUM +1;
            XGRID_NUM := XGRID_NUM + YGRID_NUM;
          END
        ELSE
          BEGIN                { SETUP FOR INTERPOLATION }
            NUM_EMPTY := NUM_EMPTY + 1;
          END;


      { The lower curve is subtracted from the upper to give area }

      FOR I := 1 TO MAXINDEX DO
        IF CURVE_LOW[1,I] < XHIGH + 1 THEN
          BEGIN
            IF NUM_EMPTY > 0 THEN
              BEGIN
                YLAST     := CURVE_LOW[2,I];
                YMEAN     := (YFIRST + YLAST) / 2;
                YGRID_NUM := ROUND(INT(YMEAN * METER_VALUE / SECTION_VALUE));

                IF FRAC(YMEAN * METER_VALUE / SECTION_VALUE) > 0
                  THEN YGRID_NUM := YGRID_NUM - 1;

                XGRID_NUM := XGRID_NUM - YGRID_NUM * NUM_EMPTY;
                NUM_EMPTY := 0;
              END;

            YFIRST    := CURVE_LOW[2,I];
            YGRID_NUM := ROUND(INT(CURVE_LOW[2,I] * METER_VALUE / SECTION_VALUE));

            IF FRAC(CURVE_LOW[2,I] * METER_VALUE / SECTION_VALUE) > 0
              THEN YGRID_NUM := YGRID_NUM - 1;

            XGRID_NUM := XGRID_NUM - YGRID_NUM;
          END
        ELSE
          BEGIN                { SETUP FOR INTERPOLATION }
            NUM_EMPTY := NUM_EMPTY + 1;
          END;


      AREAG := XGRID_NUM * SECTION_VALUE * SECTION_VALUE;
      AREAGK := AREAG / 1000;
      AREAGK := AREAGK / 1000;



  { ************************************************************************ }
  { ************************************************************************ }

      TOTAL_POINTS := JL + JH - 3;

      CLRSCR;

      WRITELN;
      WRITELN('The home range ploygon has ',TOTAL_POINTS,' verticies.');
      WRITELN;

      IF PRECISION = 'I' THEN
        BEGIN
          IF AREAI > 10000 THEN
            WRITELN('The area of the polygon is ',AREAIK:12:7,'  square kilometers.')
          ELSE
            WRITELN('The area of the polygon is ',AREAI:12:7,' square meters.');

          WRITELN;
          WRITELN ('The area is calculated with High accuracy integration.');
        END
      ELSE         { GRID COUNT ACCURACY }
        BEGIN
          IF AREAG > 10000 THEN
            WRITELN('The area of the polygon is ',AREAGK:12:7,' square kilometers.')
          ELSE
            WRITELN ('The area of the polygon is ',AREAG:12:7,'  square meters.');

          WRITELN;
          WRITELN ('The area is calculated with Low accuracy grid cell counts.');
        END;

      WRITELN;
      WRITELN ('A grid of ',grid_num,' cells wide is used to cover the home range.');

      LINE_OUT(1,25,SPACE79);
      LINE_OUT(1,25,'Do you want the vertices displayed and/or printed? (Y|N) ');

      YES_NO(KEYVALUE);

      IF KEYVALUE = 'Y' THEN
      BEGIN

        CLRSCR;
        SCREENCT := 0;

        FOR I := 1 TO JH DO
          BEGIN
            IF ( PRINTCHAR IN ['D','B'] ) AND ( KEYVALUE <> 'Q' ) THEN
              BEGIN
                SCREENCT := SCREENCT + 1;
                WRITELN (XHPOINTS[I]:10:5,'  ',YHPOINTS[I]:10:5);

                IF SCREENCT >= 22 THEN
                  BEGIN
                    LINE_OUT(1,25,'Press any key to continue, Q to Quit.');
                    READ    (KBD,KEYVALUE);
                    SCREENCT := 0;
                    DELLINE;
                    WRITELN;
                    WRITELN;
                  END;  { IF SCREENCT >= 22 }
              END;  { IF PRINTCHAR = D OR B AND KEYVALUE <> Q }

            IF ( PRINTCHAR IN ['P','B'] ) AND ( KEYVALUE <> 'Q' ) THEN
              WRITELN (LST,XHPOINTS[I]:10:5,'  ',YHPOINTS[I]:10:5);

            IF KEYPRESSED THEN
              BEGIN
                WRITELN ('A key was entered, press any key to continue, Q to quit.');
                READ    (KBD,KEYVALUE);
                DELLINE;
              END;  { IF KEYPRESSED }

          END;  { FOR I = 1 TO JH }

        FOR I := 1 TO JL DO
          BEGIN
            IF ( PRINTCHAR IN ['D','B'] ) AND ( KEYVALUE <> 'Q' ) THEN
              BEGIN
                SCREENCT := SCREENCT + 1;
                WRITELN (XLPOINTS[I]:10:5,'  ',YLPOINTS[I]:10:5);

                IF SCREENCT >= 22 THEN
                  BEGIN
                    LINE_OUT(1,25,'Press any key to continue, Q to Quit.');
                    READ    (KBD,KEYVALUE);
                    SCREENCT := 0;
                    DELLINE;
                    WRITELN;
                    WRITELN;
                  END;  { IF SCREENCT >= 22 }
              END;  { IF PRINTCHAR = D OR B AND KEYVALUE <> Q }

            IF ( PRINTCHAR IN ['P','B'] ) AND ( KEYVALUE <> 'Q' ) THEN
              WRITELN (LST,XLPOINTS[I]:10:5,'  ',YLPOINTS[I]:10:5);

            IF KEYPRESSED THEN
              BEGIN
                WRITELN ('A key was entered, press any key to continue, Q to quit.');
                READ    (KBD,KEYVALUE);
                DELLINE;
              END;  { IF KEYPRESSED }

          END;  { FOR I = 1 TO JL }

        IF PRINTCHAR IN ['D','B'] THEN
          IF PRECISION = 'I' THEN
          BEGIN
            IF AREAI > 10000
              THEN WRITELN('Number of verticies: ',TOTAL_POINTS,'   Area: ',
                            AREAIK:12:7,' Square kilometers.')
              ELSE WRITELN('Number of verticies: ',TOTAL_POINTS,'   Area: ',
                            AREAI:12:7,'  Square meters.');
            WRITELN;
          END
          ELSE
          BEGIN
            IF AREAG > 10000
              THEN WRITELN('Number of verticies: ',TOTAL_POINTS,'   Area: ',
                            AREAGK:12:7,'  Square kilometers.')
              ELSE WRITELN('Number of verticies: ',TOTAL_POINTS,'   Area: ',
                            AREAG:12:7,'  Square meters.');
            WRITELN;
          END;

        IF PRINTCHAR IN ['P','B'] THEN
          IF PRECISION = 'I' THEN
          BEGIN
            IF AREAI > 10000
              THEN WRITELN(LST,'Number of verticies: ',TOTAL_POINTS,'   Area: ',
                            AREAIK:12:7,' Square kilometers.')
              ELSE WRITELN(LST,'Number of verticies: ',TOTAL_POINTS,'   Area: ',
                            AREAI:12:7,'  Square meters.');
            WRITELN;
          END
          ELSE
            IF AREAG > 10000
              THEN WRITELN(LST,'Number of verticies: ',TOTAL_POINTS,'   Area: ',
                            AREAGK:12:7,'  Square kilometers.')
              ELSE WRITELN(LST,'Number of verticies: ',TOTAL_POINTS,'   Area: ',
                            AREAG:12:7,'  Square meters.');

        KEYBOARD_PAUSE;

      END;  { IF KEYVALUE = 'Y' }

      KEYVALUE := 'R';

      IF DRAWCHAR = 'Y' THEN
        BEGIN

          { SAVE THE MIN AND MAX VALUES }

          SXLOW := XLOW;
          SYLOW := YLOW;
          SZLOW := ZLOW;
          SXHIGH := XHIGH;
          SYHIGH := YHIGH;
          SZHIGH := ZHIGH;

          { DRAW THE POINTS IN THE HIGH CURVE AND THE LOW CURVE }

        IF STUDYFILE <> '' THEN
          BEGIN
            ASSIGN(FILEVAR3,STUDYFILE);
            RESET(FILEVAR3);
            STUDYOPEN := TRUE;
          END;

        IF (REPLAYFILE <> '') AND (EXIST(REPLAYFILE)) THEN
          BEGIN
            ASSIGN(FILEVAR4,REPLAYFILE);
            RESET(FILEVAR4);
            REPLAYOPEN := TRUE;
          END;

        { MIN AND MAX VALUES WERE CALCULATED HIGHER IN THE PROGRAM }

        GRID_CALCULATIONS;

        HIRES;
        HIRESCOLOR(YELLOW);

        LINE_OUT(2,1,'Concave Polygon');

        FOR I := 1 TO JH-1 DO
          HIRES_VECTOR(XHPOINTS[I],YHPOINTS[I],XHPOINTS[I+1],YHPOINTS[I+1],
                       XOFFSET,YOFFSET,GRIDFACTOR);

        FOR I := 1 TO JL-1 DO
         HIRES_VECTOR(XLPOINTS[I],YLPOINTS[I],XLPOINTS[I+1],YLPOINTS[I+1],
                      XOFFSET,YOFFSET,GRIDFACTOR);

        { 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 PRECISION = 'I' THEN
          IF AREAI > 10000 THEN
            BEGIN
              WRITE(AREAIK:12:7);
              LINE_OUT(62,15,'Sq. kilometers.');
            END
          ELSE
            BEGIN
              WRITE(AREAI:12:7);
              LINE_OUT(62,15,'Sq. meters.');
            END
        ELSE
          IF AREAG > 10000 THEN
            BEGIN
              WRITE(AREAGK:12:7);
              LINE_OUT(62,15,'Sq. kilometers.');
            END
          ELSE
            BEGIN
              WRITE(AREAG:12:7,' Square meters.');
              LINE_OUT(62,15,'Sq. meters.');
            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);


                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.X2,XHIGH);

                GRID_CALCULATIONS;

                LINE_OUT(2,1,'Concave Polygon');

                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;

                { REDRAW THE CONCAVE POLYGON }

                FOR I := 1 TO JH-1 DO
                  HIRES_VECTOR(XHPOINTS[I],YHPOINTS[I],XHPOINTS[I+1],YHPOINTS[I+1],
                               XOFFSET,YOFFSET,GRIDFACTOR);

                FOR I := 1 TO JL-1 DO
                  HIRES_VECTOR(XLPOINTS[I],YLPOINTS[I],XLPOINTS[I+1],YLPOINTS[I+1],
                               XOFFSET,YOFFSET,GRIDFACTOR);

                { 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 PRECISION = 'I' THEN
                  IF AREAI > 10000 THEN
                    BEGIN
                      WRITE(AREAIK:12:7);
                      LINE_OUT(62,15,'Sq. kilometers.');
                    END
                  ELSE
                    BEGIN
                      WRITE(AREAI:12:7);
                      LINE_OUT(62,15,'Sq. meters.');
                    END
                ELSE
                  IF AREAG > 10000 THEN
                    BEGIN
                      WRITE(AREAGK:12:7);
                      LINE_OUT(62,15,'Sq. kilometers.');
                    END
                  ELSE
                    BEGIN
                      WRITE(AREAG:12:7,' Square meters.');
                      LINE_OUT(62,15,'Sq. meters.');
                    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
                  BEGIN
                    INIT_REPLAY_FILE;
                    ASSIGN(FILEVAR4,REPLAYFILE);
                    RESET (FILEVAR4);
                    REPLAYOPEN := TRUE;
                  END;

                { 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 := MIN_VAL(FILE4REC.X2,SXHIGH);
                FILE4REC.Y2 := MIN_VAL(FILE4REC.Y2,SYHIGH);
                FILE4REC.Z2 := MIN_VAL(FILE4REC.Z2,SZHIGH);
                FILE4REC.LINE_TYPE := FILE4REC.LINE_TYPE + TOTAL_POINTS;

                SEEK (FILEVAR4,1);
                WRITE(FILEVAR4,FILE4REC);
                READ (FILEVAR4,FILE4REC);

                FILE4REC.X2 := FILE4REC.X2 + 1;
                SEEK (FILEVAR4,2);
                WRITE(FILEVAR4,FILE4REC);

                SEEK (FILEVAR4,FILESIZE(FILEVAR4)-1); { LAST RECORD IN FILE }
                READ (FILEVAR4,FILE4REC);

                FILE4REC.X1 := -4;               { BEGIN CONCAVE GRAPH }
                FILE4REC.Y1 := -10;
                FILE4REC.X2 := -10;
                FILE4REC.Y2 := -10;

                SEEK (FILEVAR4,FILESIZE(FILEVAR4)-1);
                WRITE(FILEVAR4,FILE4REC);

                FILE4REC.X1 := SXLOW;            { BUILD SECOND HEADER }
                FILE4REC.Y1 := SYLOW;
                FILE4REC.Z1 := SZLOW;
                FILE4REC.X2 := SXHIGH;
                FILE4REC.Y2 := SYHIGH;
                FILE4REC.Z2 := SZHIGH;
                FILE4REC.LINE_TYPE := TOTAL_POINTS;
                WRITE(FILEVAR4,FILE4REC);

                { WRITE OUT THE CONCAVE POLYGON VECTORS }

                FILE4REC.Z1 := 0.0;
                FILE4REC.Z2 := 0.0;
                FILE4REC.LINE_TYPE := 1;

                FOR I := 1 TO JH-1 DO
                  BEGIN
                    FILE4REC.X1 := XHPOINTS[I];
                    FILE4REC.Y1 := YHPOINTS[I];
                    FILE4REC.X2 := XHPOINTS[I+1];
                    FILE4REC.Y2 := YHPOINTS[I+1];
                    WRITE(FILEVAR4,FILE4REC);
                  END;


               FOR I := 1 TO JL-1 DO
                 BEGIN
                   FILE4REC.X1 := XLPOINTS[I];
                   FILE4REC.Y1 := YLPOINTS[I];
                   FILE4REC.X2 := XLPOINTS[I+1];
                   FILE4REC.Y2 := YLPOINTS[I+1];
                   WRITE(FILEVAR4,FILE4REC);
                 END;

               { WRITE OUT THE TRAILING RECORD }

               FILE4REC.X1 := 0.0;
               FILE4REC.Y1 := 0.0;
               FILE4REC.X2 := 0.0;
               FILE4REC.Y2 := 0.0;
               FILE4REC.LINE_TYPE := 0;
               WRITE(FILEVAR4,FILE4REC);

              END;  { IF KEYVALUE := Y }

          END;  { IF REPLAYFILE <> '' };

        KEYBOARD_PAUSE;

        KEYVALUE := 'R';
        TEXTMODE;

        IF STUDYOPEN THEN CLOSE(FILEVAR3);
        IF REPLAYOPEN THEN CLOSE(FILEVAR4);

        END;  { IF DRAWCHAR = Y }

      CLOSE (FILEVAR2);

    END;  { CONCAVE_HULL PROCEDURE }

  BEGIN  { CONCAVE_HULL_MENU PROCEDURE }

    { Display the options menu for the Concave Hull procedure }

    GRID_NUM := 20;

    KEYVALUE := 'R';

    WHILE KEYVALUE = 'R' DO
    BEGIN

    CLRSCR;
    DISPLAY_COLOR(CYAN);

    LINE_OUT(28,2,'(7) Concave Polygon 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  Area accuracy method (I|G):');
    LINE_OUT(10,16,'7  Width of a grid cell in meters:');
    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);

    IF PRECISION = 'I'
      THEN LINE_OUT(41,14,'INTEGRATION')
      ELSE LINE_OUT(41,14,'GRID CELL COUNT');

    GOTOXY(45,16);
    WRITE (SECTION_VALUE:8:4);

    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,24);

    KEYVALUE := ' ';

    WHILE NOT (UPCASE(KEYVALUE) IN [ 'E','R']) DO
      BEGIN

        KEYVALUE := ' ';
        WHILE NOT (UPCASE(KEYVALUE) IN ['1'..'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);
          '6': MENU_CALL(6);
          '7': MENU_CALL(7);
          '8': MENU_CALL(8);
          'P': BEGIN
               KEEP_GOING := TRUE;

               PROCESSING_VERIFY;

               IF (KEEP_GOING) AND (SECTION_VALUE <= 0) THEN
                 BEGIN
                   LINE_OUT(1,23,'A grid cell value greater than 0 must be given.');
                   KEEP_GOING := FALSE;
                 END;

               IF (KEEP_GOING) AND (METER_VALUE <=0) THEN
                 BEGIN
                   LINE_OUT(1,23,'The distance from 1.0 to 2.0 must be given.');
                   KEEP_GOING := FALSE;
                 END;

               IF KEEP_GOING THEN
                 BEGIN
                   CLRSCR;
                   CONCAVE_HULL;
                 END

               END;  { CASE P }

          END;  { CASE KEYVALUE OF }

          GOTOXY(1,25);

      END;  { WHILE NOT (KEYVALUE IN ['E','R']) }

    END;  { WHILE KEYVALUE = 'R' }

    KEYVALUE := ' '

    END;  { CONCAVE_HULL_MENU  }

