#!/usr/bin/perl
#
# r.tile_merge.pl  
#-------------------------------------------------------------------------------------
# Version 1.0 (r.tile_merge.pl)
#     Merges tiled source raster files into larger raster file for full image views.
#     Has limited cropping ability, depending on direction.
#     Can run GRASS r.in.bn import command on finished merged tiles.
#     Use r.tile_merg.pl -help -brief for more info and tips.
# 
# Originating Author: Kevin Cross 
# Contributing Authors
# Copyright March 2001, Kevin Cross
# Distributed "AS IS and without warranty of any kind" under the GNU General Publc License.
# See http://www.gnu.org/copyleft/gpl.html for License Terms
#
#
# Copyright (C) 2001  Kevin Cross (kevin-cross@msn.com)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
#
# Current Project Author: Kevin Cross
# Contributing Authors: 
#
# Created for use with perl 5.6.0 under Linux i86 platforms running the GRASS GIS.
# Should be compatable with most other platforms.
#


#--- Initialize Variables
$n=0;
$Direction="";
$Data="";
$OutFile="";
$bytes=2;
$Img_Info="";
$ImgFile="";
$ImgRows="";
$ImgCols="";
$Num_Of_Tiles=0;
$File_Offset=0;
$Map_Data="";
$Start=0;
$Collect=0;
$GRASS=0;
$GLOBE=0;
$FirstImgHdrFile="";
$LastImgHdrFile="";
$N_Corner=0;
$S_Corner=0;
$W_Corner=0;
$E_Corner=0;
$NS_Span=0;
$EW_Span=0;
$Proj=3;
$Zone=0;
$NS_Res="0:00:30";
$EW_Res="0:00:30";
$Format=3;
$Compressed=0;
$SignedData=0;
$Info=0;
$ByteSwap=0;
$FloatData=0;
$Help=0;
$Brief=0;
$G_Location=$ENV{'LOCATION'};
$RmvCell=0;
$Compress=0;

#-- Collect command line data
  while ($ARGV[$n] ne ""){

    $t=index($ARGV[$n],"-GRASS");
    if ($t == $[ ){
      $GRASS=1 ;
      if ($G_Location eq "") {
        print "The \"LOCATION\" environment variable for GRASS is not set.\r\nCannot continue with \"-GRASS\" option!\r\n";
        exit (-1);
        }
      }

    $t=index($ARGV[$n],"-GLOBE");
    $GLOBE=1 if ($t == $[ );

    $t=index($ARGV[$n],"-d=");
    $Direction=substr $ARGV[$n],$[+3  if ($t == $[ );

    $t=index($ARGV[$n],"-img=");
    $Data=substr $ARGV[$n],$[+5  if ($t == $[ );

    $t=index($ARGV[$n],"-of=");
    if ($t == $[ ) {
      $OutFile=substr $ARGV[$n],$[+4 ;
      $OutFileHdr=$OutFile . ".hdr";
      $P_Outfile=$OutFile;
      $P_OutFileHdr=$OutFileHdr;
      if ($G_Location ne "") { #----- Grass environent present. Place output to cell directory.
        $P_OutFile=$G_Location . "/cell/$OutFile" ;
        $P_OutFileHdr=$G_Location . "/cellhd/$OutFile"
        }
      }

    $t=index($ARGV[$n],"-b=");
    $bytes=substr $ARGV[$n],$[+3  if ($t == $[ );

    $t=index($ARGV[$n],"-start=");
    $Start=substr $ARGV[$n],$[+7  if ($t == $[ );
    $Start=int($Start);

    $t=index($ARGV[$n],"-collect=");
    $Collect=substr $ARGV[$n],$[+9  if ($t == $[ );
    $Collect=int($Collect);

    $t=index($ARGV[$n],"-signed");
    $SignedData=1 if ($t == $[ );

    $t=index($ARGV[$n],"-info");
    $Info=1 if ($t == $[ );

    $t=index($ARGV[$n],"-swap");
    $ByteSwap=1 if ($t == $[ );

    $t=index($ARGV[$n],"-float");
    $Float=1 if ($t == $[ );

    $t=index($ARGV[$n],"-help");
    $Help=1 if ($t == $[ );

    $t=index($ARGV[$n],"-brief");
    $Brief=1 if ($t == $[ );

   $n++;
  }  


if ($Brief) {
print "-------------------------------------------------------------------------------------\r\n";
print " BRIEF on r.tile_merge.pl \r\n\r\n";

print "  Copyright (C) 2001  Kevin Cross (kevin-cross\@msn.com)\r\n\r\n";

print "  See http://www.gnu.org/copyleft/gpl.html for License Terms\r\n\r\n";

print "  This program is free software; you can redistribute it and/or\r\n";
print "  modify it under the terms of the GNU General Public License\r\n";
print "  as published by the Free Software Foundation; either version 2\r\n";
print "  of the License, or (at your option) any later version.\r\n";

print "  This program is distributed in the hope that it will be useful,\r\n";
print "  but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n";
print "  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n";
print "  GNU General Public License for more details.\r\n\r\n";

print "  Current Project Author: Kevin Cross\r\n";
print "  Contributing Authors: \r\n\r\n";

print "  Created for use with perl 5.6.0 under Linux i86 platforms running the GRASS GIS.\r\n";
print "  Should be compatable with most other platforms.\r\n";
print "-------------------------------------------------------------------------------------\r\n\r\n";

print " This utility merges uncompressed raster image tiles. It was\r\n";
print " designed primarily for the GLOBE DEM image set, but there is no\r\n";
print " reason I know of that it cannot be used on gtopo30 data or\r\n";
print " other uncompressed raster data tiles.  \r\n\r\n";

print " Things to keep in mind when using this utility.\r\n";
print " 1. The first and last images listed need GRASS header files and have the same\r\n";
print "    /path/name as the image file with a \".hdr\" extension. (case sensitve in unix).\r\n";
print "    A header file can be created manually provided the information is known.\r\n";
print "    A sample file is below.\r\n\r\n";

print "proj:       3\r\n";
print "zone:       0\r\n";
print "north:      90N\r\n";
print "south:      50N\r\n";
print "east:       90W\r\n";
print "west:       180W\r\n";
print "cols:       10800\r\n";
print "rows:       4800\r\n";
print "e-w resol:  0:00:30\r\n";
print "n-s resol:  0:00:30\r\n";
print "format:     3\r\n";
print "compressed: 1\r\n\r\n";

print " 2. The first image's header file define:\r\n";
print "    A. The northern and western most data pixels.\r\n";
print "    B. The format type.\r\n";
print "    C. The n-s and e-w resolutions\r\n\r\n";

print " 3. The last image's header files define:\r\n";
print "    A. The southern and eastern most data pixels.\r\n";
print "    B. In the case of cropped/truncated data, the row and colomun count \r\n";
print "       are used in combination with the header file to determine new \r\n";
print "       East/West/North/South boundaries.\r\n\r\n";

print " 4. On horizontal and vertical merges the northern and western edges respectively \r\n";
print "    are presumed to line up.\r\n\r\n";

print " 5. On all merges the row and column values given on the command line and \r\n";
print "    in the headers MUST BE CORRECT to properly parse raster images for merging.\r\n\r\n";

print " 6. On horizontal (e-w) merges:\r\n";
print "    USE the \"-start\" option to crop original images to a new northern border.\r\n";
print "    USE the \"-collect\" option to crop the southern border.\r\n\r\n";
print "    Use the \"-info\" command option to run the program without creating the new \r\n";
print "    image files. It will determine the adjusted N/S/E/W boundaries and file dimensions.\r\n\r\n";

print " 7. On vertical (n-s) merges:\r\n";
print "    USE the \"-start\" option to crop original images to a new western border.\r\n";
print "    USE the \"-collect\" option to crop the eastern border.\r\n\r\n";
print "    Use the \"-info\" command option to run the program without creating the new \r\n";
print "    image files. It will determine the adjusted N/S/E/W boundaries and file dimensions.\r\n\r\n";

print " 8. Using the -GRASS switch will:\r\n";
print "    A. Presume data are GLOBE compatable raster image files.\r\n";
print "    B. Create the merged image file and headers.\r\n";
print "    C. Presume you have used this utility from with the GRASS environment.\r\n";
print "    D. Initiate the GRASS command r.in.bin with the proper command switches.\r\n\r\n";

print " 9. Using the -GLOBE switch will:\r\n";
print "    A. Presume data are GLOBE raster image files.\r\n";
print "    B. Run an additional \"r.mapcalc\" step to adjust some GLOBE DEM values.\r\n";
print "    C. Presume you have used this utility from with the GRASS environment.\r\n\r\n";

print "-------------------------------------------------------------------------------------\r\n";
print " RESEARCH NOTES and PROGRAM DESCRIPTION\r\n\r\n";

print " This utility merges binary DEM GIS files from the\r\n";
print " Global Land One-Km Base Elevation (GLOBE) project and\r\n";
print " formats the output in a GRASS importable format.\r\n";
print " (See www.ngdc.noaa.gov/seg/topo/globeget.shtml\r\n";
print " Binaries must be merged in a horizontal or vertical \r\n";
print " direction.  Multiple merges can combine prior horizontal\r\n";
print " or vertical merges to generate larger bin images.\r\n";

print " The raw GLOBE DEM file data are massaged during the import.\r\n";
print " Specifically, according to GLOBE DEM documentation, the multi\r\n";
print " byte format that GRASS Uses differs from traditional 16 bit\r\n";
print " integer formats found in the GLOBE DEM binaries.  The final \r\n";
print " merged product outputs to a file without these adjustments \r\n";
print " so you need to use mapcalc to make these corrections.\r\n";

print " The specific test for file integer conversion is given on\r\n";
print " NGDC site documentation as \r\n";
print " If a 2 byte integer-32768 test as follows the transformation is:\r\n";
print "         int-65536 if(int-32768) > 0\r\n";
print "         int if(int-32768) = 0\r\n";
print "         int if(int-32768) < 0\r\n";

print " The equivalent r.mapcalc function is:\r\n";
print "  r.mapcalc 'outfile=if(infile-32768,infile-65536,infile,infile)'\r\n";


print " DEM files from FTP.NGDC.NOAA.GOV are in little-endian format and ready\r\n";
print " for intel machine imports.  Big-endian machines, (Real dedicated UNIX boxes), \r\n";
print " need to byteswap data. This is done on all image files BEFORE the merge \r\n";
print " process, or on the final image file AFTER th merge.\r\n"; 

print " Byteswapping can be done by the unix command:\r\n";
print "   dd if=\"infile\" of=\"outfile\" conv=swap.  \r\n";
print " Replace the terms in qoutes with the proper file names.\r\n";

print "-------------------------------------------------------------------------------------\r\n";
print "-------------------------------------------------------------------------------------\r\n\r\n";
exit(0);
}

  if (($ARGV[2] eq "") || $Help) {

    print "\r\n\r\nUSAGE:\r\n";
    print " merge_globe.pl -d=[h|v] [-b=bytes] -img=file1,r1,c1-file2,r2,c2[-...-file_n,r_n,c_n]  -of=outfile [-start=#] [-collect=#] [-float] [-signed] [-swap] [-GRASS] [-GLOBE] [-info]\r\n";
    print " where:\r\n";
    print "   -d=[h|v] Choose one! These are horizontal/vertical merges respectively.\r\n";
    print "       Merges will append files in the order listed. If the number of rows/cols\r\n";
    print "       are not the same in all images, the image which contains the smallest\r\n";
    print "       row/col count is used for the final row/col dimension. Final row/col \r\n";
    print "       dimensions are dependent on the \"r#/c#\" and \"-start & -collect\" option values.\r\n\r\n";

    print "   -b=bytes is the number of bytes used per pixel. Defaults to 2. \r\n\r\n";       
    print "   -img=file1,r1,c1-file2,r2,c2[-...-file_n,r_n,c_n]";
    print "        are the images to be merged in the order of the merge. \r\n";
    print "        file# is the path/name of the input file\r\n";
    print "        r# are the number of rows for the input file\r\n";
    print "        c# are the number of columns for the input file.\r\n";
    print "        Additionally; the files \"file1.hdr and file_n.hdr\" are presumed to exist at the same\r\n";
    print "        /path as \"file1 and file_n\". These are used for -GRASS commands.\r\n\r\n";
  
    print "   -of=OutputFile is the name of the output file.\r\n\r\n";

    print "   -start=#  # is the row or column number of the images to begin your new image at.\r\n";
    print "        This allows you to crop or truncate northern or western edges.\r\n";
    print "        To crop an eastern or southern edge, use the \"-collect\" option to \r\n";
    print "        indicate the eastern/southern extent of your new image. The last \"file_n,r_n,c_n\"\r\n";
    print "        dimensions are used in preliminary calculations and must be accurate. You\r\n";
    print "        can use the \"-info\" option to calculate your north/south/east/west values\r\n";
    print "        with different settings before you actually perform a merge process.\r\n\r\n";

    print "   -collect=#  # determines the number of rows/cols to include in the image. It must \r\n";
    print "        be smaller than any row/col listed on the command line.  It will be adjusted down\r\n";
    print "        if the residual number of columns remaining after the \"-start\" value is subtracted\r\n";
    print "        is lower than the \"-collect\" value. \r\n\r\n";

    print "   -info   This flag stops the file merge process after dimensions are calculated\r\n";
    print "        and displayed. This allows you to adjust cropping parameters and view final\r\n";
    print "        image size before actually performing the file merges.\r\n\r\n";

    print "   -GRASS  Lets r.tile_merge.pl know if you are running from a grass enivironment.\r\n";
    print "        If you are then it will perform additional command for \"r.in.bin\" and \"g.region.sh\"\r\n\r\n";

    print "   -signed Works only with the -GRASS option and sets the signed \"-s\" flag for \"r.in.bin\".\r\n\r\n";

    print "   -float Works only with the -GRASS option and sets the float \"-f\" flag for \"r.in.bin\".\r\n\r\n";

    print "   -swap Works only with the -GRASS option and sets the byteswap \"-b\" flag for \"r.in.bin\".\r\n\r\n";

    print "   -GLOBE  Lets r.tile_merge.pl know if you are merging GLOBE tiles. This option only works\r\n";
    print "           with the -GRASS option and initiates an additional r.mapcalc command to convert\r\n";
    print "           GLOBE data tiles into proper GRASS DEM images.\r\n\r\n";

    exit(0);
    }

#-----  Split Img Data into arrays, then these into img data arrays
  @Img_Info = split(/-/,$Data);
  $n=0;
  while ($Img_Info[$n]) {
    ($ImgFile[$n],$ImgRows[$n],$ImgCols[$n])=split(/,/,$Img_Info[$n]);
    $T_Handle[$n]="T_Handle_$n";
    $n++;
    }
  $bytes=int($bytes);
  $Num_Of_Tiles=$n;
  $Offset=0;


#-- Info Printout
  $n=0;
  print "\r\n\r\n------------------------\r\n";
  print "\r\nProcessing\r\n";
  while ($n<$Num_Of_Tiles){
    print "\r\nImgFile=$ImgFile[$n] Contains $ImgRows[$n] Rows and $ImgCols[$n] columns.";
    $n++;
    }
  print"\r\n================\r\n";  

#----- Open all input files for binary reading
  $n=0;
  while($n < $Num_Of_Tiles) {
    $test= open($T_Handle[$n],"< $ImgFile[$n]");
    if(! $test) {
      print "\r\n<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>" ;
      print "\r\n<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>" ;
      print "\r\n<><><> WARNING: $ImgFile[$n] not found or error trying to open!" ;
      print "\r\n<><><> PROCESSING STOPPED !"; 
      print "\r\n<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>" ;
      print "\r\n<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>\r\n" ;
      close;
      exit(-1);
      }
    binmode($T_Handle[$n]);
    $n++;
    }

  #----NOTE: Improve program by chacking for existence of header files
  $FirstImgHdrFile=$ImgFile[0].".hdr";
  $LastImgHdrFile=$ImgFile[$n-1].".hdr";
  open(HDR_FILE1,"< $FirstImgHdrFile") || die "$FirstImgHdrFile not found";
  print "\r\nFirstImgHdrFile $FirstImgHdrFile\r\n";

  open(HDR_FILE2,"< $LastImgHdrFile") || die "$LastImgHdrFile not found";
  print "LastImgHdrFile $LastImgHdrFile\r\n";


#<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
#<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
#<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>

#-----<><><><> HORIZONTAL MERGING <><><><>-----

#<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
#<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
#<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>

#----- Proceedure if tiles are merged Horizontally
  if ($Direction eq "h") {
    #----- Calculate Max Rows and Cols header file
    $MaxRows=0;
    $MaxCols=0;
    #----- Determine Maximum Rows for horizontal merges
    $n=0;
    $MaxRows=int($ImgRows[$n]);
    while($n<$Num_Of_Tiles-1){
      $MaxRows=int($ImgRows[$n+1]) if($ImgRows[$n+1] < $MaxRows);
      $n++;
      }

    #----- Do a validity check on $Start and $MaxRow relationships
    if($Start > int($ImgRows[$Num_Of_Tiles-1])){
      $Start=0;
      }

    if(($Start+$MaxRows) > int($ImgRows[$Num_Of_Tiles-1])){
      $MaxRows=$ImgRows[$Num_Of_Tiles-1]-$Start;
      }

    if(($Start + $MaxRows) > int($ImgRows[$Num_Of_Tiles-1])){
      $Start=$ImgRows[$Num_Of_Tiles-1]-$Start;
      }

    $Collect=$MaxRows if ($Collect > $MaxRows);
    $Collect=$MaxRows if ($Collect == 0);

#----- Add Cols to Determine Total Vertical Cols spliced together
    $n=0;
    $MaxCols=$ImgCols[0];
    while ($n<$Num_Of_Tiles){
      $n++;
      $MaxCols=$MaxCols + $ImgCols[$n] ;
      }  
#----- Collect header info and Calculate offsets and new N-S-E-W coordinates of image.

#----- First Header File Settings

  while (<HDR_FILE1>){
    $t=index($_,"proj:");
    $Proj=substr $_,$[+6  if ($t == $[ );
    $Proj=int($Proj);

    $t=index($_,"zone:");
    $Zone=substr $_,$[+6  if ($t == $[ );
    $Zone=int($Zone);

    $t=index($_,"north:");
    $N_Corner=substr $_,$[+7  if ($t == $[ );
      $t=index($N_Corner,"N");
      $N_Corner=int($N_Corner) if ($t>$[); 
      $t=index($N_Corner,"S");
      $N_Corner=-int($N_Corner) if ($t>$[); 
      $N_Corner=int($N_Corner); #---- In case value is plain numeric.

    $t=index($_,"west:");
    $W_Corner=substr $_,$[+6  if ($t == $[ );
      $t=index($W_Corner,"E");
      $W_Corner=int($W_Corner) if ($t>$[); 
      $t=index($W_Corner,"W");
      $W_Corner=-int($W_Corner) if ($t>$[); 
      $W_Corner=int($W_Corner); #---- In case value is plain numeric.

    $t=index($_,"e-w resol:");
    $EW_Res=substr $_,$[+11  if ($t == $[ );

    $t=index($_,"n-s_resol:");
    $NS_Res=substr $_,$[+11  if ($t == $[ );

    $t=index($_,"format:");
    $Format=substr $_,$[+8  if ($t == $[ );
    $Format=int($Format);

  }  
  close(HDR_FILE1);

#----- Second Header File Settings
  while (<HDR_FILE2>){
    $t=index($_,"south:");
    $S_Corner=substr $_,$[+7  if ($t == $[ );
      $t=index($S_Corner,"N");
      $S_Corner=int($S_Corner) if ($t>$[); 
      $t=index($S_Corner,"S");
      $S_Corner=-int($S_Corner) if ($t>$[); 
      $S_Corner=int($S_Corner); #---- In case value is plain numeric.

    $t=index($_,"east:");
    $E_Corner=substr $_,$[+6  if ($t == $[ );
      $t=index($E_Corner,"E");
      $E_Corner=int($E_Corner) if ($t>$[); 
      $t=index($E_Corner,"W");
      $E_Corner=-int($E_Corner) if ($t>$[); 
      $E_Corner=int($E_Corner); #---- In case value is plain numeric.

    $t=index($_,"cols:");
    $Cols=substr $_,$[+6  if ($t == $[ );
    $t=index($_,"rows:");
    $Rows=substr $_,$[+6  if ($t == $[ );
  }  
  close(HDR_FILE2);

  $N_S_DegreeRes=($N_Corner-$S_Corner)/$Rows;
    $N_S_DegreeRes=-$N_S_DegreeRes if($N_S_DegreeRes < 0);
  $EW_Span=$W_Corner-$E_Corner;
  $EW_Span=$EW_Span+180 if ($EW_Span > 0);
  $EW_Span=360 if ($EW_Span == 0);
  $E_W_DegreeRes=($EW_Span)/$MaxCols;
    $E_W_DegreeRes=-$E_W_DegreeRes if($E_W_DegreeRes < 0);

  if ($Start > 0) {#----- Adjust Northern Edge
    $N_Corner=$N_Corner-($Start*$N_S_DegreeRes);
    }
  if ($MaxRows < $Rows) {
    $S_Corner=$N_Corner-($Collect*$N_S_DegreeRes);
    }

#----- Print Info to screen
    print "\r\nFinal Image created from $Num_Of_Tiles Tiles:\r\n  Final Image Dimensions are:\r\n  ";
    print "FileSize " . $Collect*$MaxCols*$bytes . "\r\n\r\n";
    print "proj:		$Proj\r\n";
    print "zone:		$Zone\r\n";
    print "north:		$N_Corner\r\nsouth:		$S_Corner\r\n";
    print "east:		$E_Corner\r\nwest:		$W_Corner\r\n";
    print "e-w resol:	$E_W_DegreeRes \r\nn-s resol:	$N_S_DegreeRes\r\n";
    print "cols:		$MaxCols \r\nrows:		$Collect \r\nformat:		$Format\r\n";
    print "compressed:	0\r\n";

exit(0) if($Info); #----- Print info only so user can adjust parameters.

#----- Open output file for binary write
  open(OUT_FILE,"> $OutFile");
  binmode(OUT_FILE);

#----- Now for the real work!! Read image row from each file and output.
#----- Max row dimension determined by image with minimum # of rows, or $Collect, and the value of $Start
    $row=$Start;
    while($row<($Collect + $Start)){ 
      $n=0 ;
      while($n<=$Num_Of_Tiles){
        $Offset=$row*$bytes*$ImgCols[$n];
        $len=$bytes*$ImgCols[$n];
        $Map_Data="";
        seek($T_Handle[$n],$Offset,0);
        read($T_Handle[$n],$Map_Data,$len);
        print OUT_FILE $Map_Data;
        $n++;
        }#--End While n<#Tiles

      $row++;
      $Percent=int(100*($row/($Start+$Collect)));
      print "\rProcessing Row=$row   $Percent % Done";
      }#-- End While Row<$ImgRows[0]
    }#-- Enf If Direction=h

#<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
#<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
#<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>

#-----<><><><> VERTICAL MERGING <><><><>-----

#<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
#<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
#<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>

#----- Proceedure if tiles are merged Vertically
  if ($Direction eq "v") {

    #----- Calculate Max Rows and Cols header file
    $MaxRows=0;
    $MaxCols=0;
    #----- Determine Maximum Cols for vertical merges
    $n=0;
    $MaxCols=int($ImgCols[$n]);
    while($n<$Num_Of_Tiles-1){
      $MaxCols=int($ImgCols[$n+1]) if($ImgCols[$n+1] < $MaxCols);
      $n++;
      }

    #----- Do a validity check on $Start and $MaxCols relationships
    if($Start > int($ImgCols[$Num_Of_Tiles-1])){
      $Start=0;
      }

    if(($Start+$MaxCols) > int($ImgCols[$Num_Of_Tiles-1])){
      $MaxCols=$ImgCols[$Num_Of_Tiles-1]-$Start;
      }

    if(($Start + $MaxCols) > int($ImgCols[$Num_Of_Tiles-1])){
      $Start=$ImgCols[$Num_Of_Tiles-1]-$Start;
      }

    $Collect=$MaxCols if($Collect > $MaxCols);
    $Collect=$MaxCols if($Collect == 0);
    

#----- Add Rows to Determine Total number of rows to merge
    $n=0;
    $MaxRows=$ImgRows[0];
    while ($n<$Num_Of_Tiles){
      $n++;
      $MaxRows=$MaxRows + $ImgRows[$n] ;
      }  

#----- First Header File Settings
  while (<HDR_FILE1>){
    $t=index($_,"proj:");
    $Proj=substr $_,$[+6  if ($t == $[ );
    $Proj=int($Proj);

    $t=index($_,"zone:");
    $Zone=substr $_,$[+6  if ($t == $[ );
    $Zone=int($Zone);

    $t=index($_,"north:");
    $N_Corner=substr $_,$[+7  if ($t == $[ );
      $t=index($N_Corner,"N");
      $N_Corner=int($N_Corner) if ($t>$[); 
      $t=index($N_Corner,"S");
      $N_Corner=-int($N_Corner) if ($t>$[); 
      $N_Corner=int($N_Corner); #---- In case value is plain numeric.

    $t=index($_,"west:");
    $W_Corner=substr $_,$[+6  if ($t == $[ );
      $t=index($W_Corner,"E");
      $W_Corner=int($W_Corner) if ($t>$[); 
      $t=index($W_Corner,"W");
      $W_Corner=-int($W_Corner) if ($t>$[); 
      $W_Corner=int($W_Corner); #---- In case value is plain numeric.

    $t=index($_,"e-w resol:");
    $EW_Res=substr $_,$[+11  if ($t == $[ );
    $EW_Res=int($EW_Res);

    $t=index($_,"n-s_resol:");
    $NS_Res=substr $_,$[+11  if ($t == $[ );
    $NS_Res=int($NS_Res);

    $t=index($_,"format:");
    $Format=substr $_,$[+8  if ($t == $[ );
    $Format=int($Format);
  }  
  close(HDR_FILE1);
#----- Second Header File Settings

  while (<HDR_FILE2>){
    $t=index($_,"south:");
    $S_Corner=substr $_,$[+7  if ($t == $[ );
      $t=index($S_Corner,"N");
      $S_Corner=int($S_Corner) if ($t>$[); 
      $t=index($S_Corner,"S");
      $S_Corner=-int($S_Corner) if ($t>$[); 
      $S_Corner=int($S_Corner); #---- In case value is plain numeric.

    $t=index($_,"east:");
    $E_Corner=substr $_,$[+6  if ($t == $[ );
      $t=index($E_Corner,"E");
      $E_Corner=int($E_Corner) if ($t>$[); 
      $t=index($E_Corner,"W");
      $E_Corner=-int($E_Corner) if ($t>$[); 
      $E_Corner=int($E_Corner); #---- In case value is plain numeric.


    $t=index($_,"cols:");
    $Cols=substr $_,$[+6  if ($t == $[ );
    $t=index($_,"rows:");
    $Rows=substr $_,$[+6  if ($t == $[ );

  }  

  close(HDR_FILE2);


  $N_S_DegreeRes=($N_Corner-$S_Corner)/$MaxRows;

  $EW_Span=$W_Corner-$E_Corner;
  $EW_Span=$EW_Span+180 if ($EW_Span > 0);
  $EW_Span=360 if ($EW_Span == 0);
  $E_W_DegreeRes=($EW_Span)/$ImgCols[$Num_Of_Tiles-1];
    $E_W_DegreeRes=-$E_W_DegreeRes if($E_W_DegreeRes < 0);


  if ($Start > 0) {#----- Adjust Western Edge
    
    $W_Corner=$W_Corner-($Start*$E_W_DegreeRes) if ($W_Corner < 0);
    if ($W_Corner > 0) {
      $W_Corner=$W_Corner+($Start*$E_W_DegreeRes);
      $W_Corner=$W_Corner-360 if ($W_Corner > 180);
      }
    }

  if ($MaxCols < $ImgCols[$Num_Of_Tiles-1]) {
    $EW_Span=$Collect*$E_W_DegreeRes;
    if ($W_Corner > 0 ){
      $E_Corner=$W_Corner+($EW_Span);
      if ($E_Corner > 180) {
        $E_Corner=$E_Corner-180;
        if ($E_Corner > 180) {
          $E_Corner=$E_Corner-180;
          }
        else { 
          $E_Corner=-$E_Corner;   
          }
        }
      }
    if ($W_Corner < 0 ){
      $E_Corner=$W_Corner-($EW_Span);
      if ($E_Corner < -180) {
        $E_Corner=-$E_Corner;
        $E_Corner=$E_Corner-180;
        }
      }
    }

  #---- Place these formulaes here past needed calculation areas.  Now needed only for display
  $N_S_DegreeRes=-$N_S_DegreeRes if($N_S_DegreeRes < 0);
  $E_W_DegreeRes=-$E_W_DegreeRes if($E_W_DegreeRes < 0);


#----- Print Info to screen
    $FileSize=$MaxRows*$MaxCols*$bytes;
    print "\r\nFinal Image created from $Num_Of_Tiles Tiles:\r\n  Final Image Dimensions are:\r\n  ";
    print "FileSize $FileSize \r\n\r\n";
    print "proj:		$Proj\r\n";
    print "zone:		$Zone\r\n";
    print "north:		$N_Corner \r\nsouth:		$S_Corner\r\n";
    print "east:		$E_Corner \r\nwest:		$W_Corner\r\n";
    print "e-w resol:	$E_W_DegreeRes \r\nn-s resol:	$N_S_DegreeRes\r\n";
    print "cols:		$MaxCols \r\nrows:		$MaxRows \r\nformat:		$Format\r\n";
    print "compressed:	0 \r\n\r\n";

exit(0) if($Info); #----- Print info only so user can adjust parameters.

#----- Open output file for binary write
  open(OUT_FILE,"> $OutFile");
  binmode(OUT_FILE);

#*****
    $n=0;
    $RowTotal=0;
    while($n<$Num_Of_Tiles){
    $row=0;
      while($row<$ImgRows[$n]){
        $len=$bytes*$Cols;
        $Offset=$row*$len;
        $Map_Data="";
        $In_Data="";
        seek($T_Handle[$n],$Offset,0);
        read($T_Handle[$n],$In_Data,$len);
        $offset=$start*$bytes;
        $len=$Collect*$bytes;
   print "\rProcessing Tile $ImgFile[$n] -- Row=$row: Total Progress is $Percent%  ";
        $Map_Data=substr($In_Data,$offset,$len);
        print OUT_FILE $Map_Data;
        $row++;
	$RowTotal++;
        $Percent=int(100*$RowTotal/$MaxRows);
        }
      $n++;
      }#-- End While n<#Tiles
    #----- Calculate a header file
    }#-- End If Direction=v

#----- Clean up open files for merges

  close(OUT_FILE);
  $n=0;
  while($n<$Num_Of_Tiles) {
    close($T_Handle[$n]);
    $n=$n+1;
    }


  #-- Print a header file for new image.
  print "\r\n\r\nA Header File $OutFileHdr contains the information above\r\n";
  open(HEADER,"> $OutFileHdr");
    print HEADER "proj:		$Proj\r\n";
    print HEADER "zone:		$Zone\r\n";
    print HEADER "north:		$N_Corner\r\nsouth:		$S_Corner\r\n";
    print HEADER "east:		$E_Corner\r\nwest:		$W_Corner\r\n";
    print HEADER "e-w resol:	$E_W_DegreeRes\r\nn-s resol:	$N_S_DegreeRes\r\n";
    print HEADER "cols:		$MaxCols\r\nrows:		$Collect \r\nformat:		$Format\r\n"   if ($Direction eq "h");
    print HEADER "cols:		$Collect\r\nrows:		$MaxRows \r\nformat:		$Format\r\n"   if ($Direction eq "v");
    print HEADER "compressed:	0\r\n";
  close(HEADER);

  if ($GRASS) { #----- Execute the Grass r.in.bin command for importing image into GRASS GIS.
    $cmnd="mv $OutFile $P_OutFile; mv $OutFileHdr $P_OutFileHdr";
    system("$cmnd");
    if($GLOBE){ #----- Run r.mapcalc to account for the peculiarities of the GLOBE dataset.
      $cmnd="r.mapcalc 'RASTER.TMP=if($OutFile-32768,$OutFile-65536,$OutFile,$OutFile)'";
      print "\r\nExecuting $cmnd to adjust GLOBE DEM values. \r\nNOTE: Execution of this command will only work if the GRASS Environment is running!\r\n\r\n";
      system("$cmnd");
      system("mv RASTER.TMP $P_OutFile");
      }
   
    $cmnd="r.in.bin bytes=$bytes input=$OutFile output=$OutFile ";
    $cmnd=$cmnd . "-s " if ($SignedData);
    $cmnd=$cmnd . "-b " if ($ByteSwap);
    $cmnd=$cmnd . "-f " if ($FloatData);
    if ($Direction eq "h") {
        $cmnd=$cmnd . "title=Digital_Elevation_Map north=$N_Corner south=$S_Corner east=$E_Corner west=$W_Corner r=$Collect c=$MaxCols";
        }
    if ($Direction eq "v") {
        $cmnd=$cmnd . "title=Digital_Elevation_Map north=$N_Corner south=$S_Corner east=$E_Corner west=$W_Corner r=$MaxRows c=$Collect";
        }
    print "\r\nExecuting $cmnd\r\nNOTE: Execution of this command will only work if the GRASS Environment is running!\r\n\r\n";
    system("$cmnd");

    $cmnd="g.region.sh raster=$OutFile";
    print "\r\nExecuting $cmnd to set new display region based on new raster. \r\nNOTE: Execution of this command will only work if the GRASS Environment is running!\r\n\r\n";
    system("$cmnd");

    }

exit(0);
