BathyPlot (neumonic for bp) was developed because the process of producing a surface plot from xyz data tables using GMT is often an iterative and delicate operation involving the use many commands with a great number of command line arguments. The GMT examples are writen using UNIX shell (command line) scripts with the implication that modifications and tuning requires editing these scripts.

Perl is found on more platforms than UNIX command line interpretors, is more flexible, includes most of the UNIX utilities, and can be structured. Then why not write a single large generic interface for GMT's use as tool for generating bathymetric plots from xyz data. Unfortunately, the bpscript now has as many options arguments as a GMT command.

The bp script does simplify things by maintaining a configuration/settings file based on the previous use of the program. (see the -s | --settings argument for specifying what that file name might be.)

Use the -v | --verbose option to see what is going on.

By default, the intermediate files are deleted, but you can maintain them to see the results of each step by using the -k | --keep and -T | --text options.

Usage

usage: bp [ <args> ] [<inputfile> <outputfile>]
 
  args: (THE FOLLOWING OPTIONS REQUIRE ARGUMENTS)
        -i | --input <inputFile> 
	-f | --fields <inputFields>    default is 1,2,3,	
        -o | --output <outputfile>
        -g | --gridsize <gridsize>     default is  meters
        -s | --settings <settingsFile> default is 
        -t | --surfTension <0 - 1.0>   default is 0.8
	-p | --path [line]         plot the position of the soundings
	     --minLong <longitude>     define a subregion
	     --maxLong <longitude>     define a subregion
	     --minLat <latitude>       define a subregion
	     --maxLat <latitude>       define a subregion
	     --ticks <tick_spacing>    in seconds of lat/long
        -n | --netcdf <filename>       specify a netcdf file output
             --nc <filename>           same as netcdf

	(THE FOLLOWING OPTIONS DO NOT HAVE ARGUMENTS)
	-b | --binary                 use binary intermediate files
	-T | --text                   use text intermediate files
        -v | --verbose                be verbose: 
                                      display commands and progress
	-e | --eps                    generate encapsulate PostScript
                                          rather than postscript
	-z | --negateZ                reverse sign of z-values
	-c | --clean                  clean up (remove) intermediate files
	-k | --keep                   save intermediate files
        -S | --scale                  show color and distance scales
	-L | --linesOnly              draw only the contour lines
        -m | --mask
	     --median                 apply median grid filter 
                                          rather than mean
             --mean                   apply mean grid filter 
                                          rather than median
             --surface                use surface to generate the grid
             --nearneighbor           use nearneighbor to generate the grid
	     --triangulate            use triangulate to generate the grid
             --nocontours
             --noimage
             --noframe
	-h | --help                   help: this display

The script

#!/usr/bin/perl
# bp - a Bathymetric Plotting Program - an interface to many GMT programs 
# Ben Smith, S/V Mother of Perl, 2006
# $Id: bp,v 1.6 2006/03/21 19:44:21 ben Exp ben $
####################################################################
use strict;
use warnings;

#use Carp;
use Getopt::Long;
# use Pod::Usage;
use Data::Dumper;

# set up object for control of GMT and filter, etc.
my $plot = GMT->new();

################ command line argument handling ####################

my @inputFiles = ();
my $outputFile = '';
my $settingsFile = "BathyPlot.set";
my $help = 0;

if(-r $settingsFile) {
    # read in previous settings
    if(open SETTINGS, "<$settingsFile") {
	my @settings = <SETTINGS>;
	eval @settings;
    }
}

my $opts = GetOptions (
		       # help
		       'help|?|h' => \$help,

		       # options with arguments
		       "input|source|i=s" => \@inputFiles,
		       "output|ps|postscript|o=s" => \$outputFile,
		       "gridsize|g=s" =>   sub { $plot->gridSizeM($_[1]); },
		       "fields|f=s" =>     sub { $plot->inputFields($_[1]); },
		       "surfTension|t=s" =>sub { $plot->surfTension($_[1]); },
		       "settings|s=s" =>   sub { $plot->settingsFile($_[1]); },
		       "minLong|minX=s" => sub { $plot->sminLong($_[1]); },
		       "maxLong|maxX=s" => sub { $plot->smaxLong($_[1]); },
		       "minLat|minY=s" =>  sub { $plot->sminLat($_[1]); },
		       "maxLat|maxY=s" =>  sub { $plot->smaxLat($_[1]); },
		       "netcdf|n=s"    =>  sub { $plot->netcdf($_[1]); },
		       "cpt=s" => sub { $plot->cptTable("$_[1]"); },
		       "revcpt=s" => sub { $plot->cptTable("-$_[1]"); }, 
		       "symbol=s" => sub { $plot->symcptTable($_[1]); },
		       "interval|contour=s"=>  sub { $plot->contourIntv($_[1]); },
		       "annotate=s"    =>  sub { $plot->contourAnnt($_[1]); },
		       "ticks|crosses=s" => sub { $plot->ticks($_[1]);}, 
		       "path|p:s" =>    sub {  if ($_[1]) {
			   $plot->showPath($_[1]) 
			   }else{
			       $plot->showPath('dot');
			   }
					   },

		       # flag type options
		       "smoothsheet" =>    sub { $plot->smoothsheet($_[1]); },
		       "nocontour|C" =>    sub { $plot->contour(0); },
		       "linesOnly|L" =>    sub { $plot->linesOnly(1); },
		       "binary|b" =>       sub { $plot->useBinary(1); },
		       "text|nobinary|T" =>sub { $plot->useBinary(0); },
		       "verbose|v" =>      sub { $plot->verbose($_[1]); },
		       "negateZ|z" =>      sub { $plot->negateZ($_[1]); },
		       "eps|e" =>          sub { $plot->eps($_[1]); },
		       "mask|m" =>         sub { $plot->mask($_[1]); },
		       "clean|c" =>        sub { $plot->clean(1); },
		       "keep|unclean|save|k" => sub { $plot->clean(0); },
		       "scale|S" =>    sub { $plot->showscale($_[1]); },
		       "median" =>         sub { 
			                         $plot->gridFilter('median'); 
					     },
		       "mean" =>           sub { $plot->gridFilter('mean'); },
		       "surface" =>        sub { 
			                         $plot->gridMethod('surface'); 
					     },
		       "nearneighbor" =>   sub { 
			                     $plot->gridMethod('nearneighbor'); 
					 },
		       "triangulate" =>    sub { 
			                     $plot->gridMethod('triangulate'); 
					 },
		       );

if((! scalar @inputFiles) && (scalar @ARGV)) {
    @inputFiles = @ARGV;
}


if(! scalar  @inputFiles || $help) { # user needs help
    print STDERR <<"EOT";
usage: BathPlot.PL [ <args> ] [<inputfile> <outputfile>]
 
  args: (THE FOLLOWING OPTIONS REQUIRE ARGUMENTS)
        -i | --input <inputFile> 
	-f | --fields <inputFields>    default is $plot->{inputFields}
        -o | --output <outputfile>
        -g | --gridsize <gridsize>     default is $plot->{gridsizeM} meters
        -s | --settings <settingsFile> default is $plot->{settingsFile}
        -t | --surfTension <0 - 1.0>   default is $plot->{surfTension}
	-p | --path [line]         plot the position of the soundings
	     --minLong <longitude>     define a subregion
	     --maxLong <longitude>     define a subregion
	     --minLat <latitude>       define a subregion
	     --maxLat <latitude>       define a subregion
	     --ticks <tick_spacing>    in seconds of lat/long
        -n | --netcdf <filename>       specify a netcdf file output
             --nc <filename>           same as netcdf

	(THE FOLLOWING OPTIONS DO NOT HAVE ARGUMENTS)
	-b | --binary                 use binary intermediate files
	-T | --text                   use text intermediate files
        -v | --verbose                be verbose: 
                                      display commands and progress
	-e | --eps                    generate encapsulate PostScript
                                          rather than postscript
	-z | --negateZ                reverse sign of z-values
	-c | --clean                  clean up (remove) intermediate files
	-k | --keep                   save intermediate files
        -S | --scale                  show color and distance scales
	-L | --linesOnly              draw only the contour lines
        -m | --mask
	     --median                 apply median grid filter 
                                          rather than mean
             --mean                   apply mean grid filter 
                                          rather than median
             --surface                use surface to generate the grid
             --nearneighbor           use nearneighbor to generate the grid
	     --triangulate            use triangulate to generate the grid
             --nocontours
             --noimage
             --noframe
	-h | --help                   help: this display
EOT
exit;
}

############### end of command line argument handling ###########

if( ! $outputFile) { # be sure we have someplace to put the output
                     # if not defined, in the same directory as the source
    $outputFile = MakeName($inputFiles[0],$inputFiles[0],'ps');
}

###### set up rest of command line controls

$plot->inputFiles(@inputFiles);
$plot->psFile($outputFile);
$plot->tempFiles(
		 xyzFile => MakeName($inputFiles[0],$outputFile,'bxyz'),
		 maskFile => MakeName($inputFiles[0],$outputFile,'mask'),
		 resultgridFile =>MakeName($inputFiles[0],$outputFile,'rgrid'),
		 blockFile => MakeName($inputFiles[0],$outputFile,'blk'),
		 pstextFile => MakeName($inputFiles[0],$outputFile,'pst'),
		 osGridFile => MakeName($inputFiles[0],$outputFile,'osgrid'),
		 gridFile => MakeName($inputFiles[0],$outputFile,'grid'),
		 surfaceFile => MakeName($inputFiles[0],$outputFile,'srf'),
		 contourFile => MakeName($inputFiles[0],$outputFile,'cntr'),
		 intensityFile => MakeName($inputFiles[0],$outputFile,'ints'),
		 textFile => MakeName($inputFiles[0],$outputFile,'tmp'),
		 );
# save existing settings

if(open SETTINGS, ">$settingsFile") {
    $Data::Dumper::Sortkeys = 1;
    print SETTINGS Data::Dumper->Dump([$plot]);
    close SETTINGS;
}

############# end of parameter setting

############# begin processing

# read source table into an xyz file
$plot->table2xyz($plot->inputFiles,$plot->Name('xyzFile'));

# source table statistics are used to set plot parameter
$plot->baseStats($plot->Name('xyzFile'));
$plot->setGeoArea($plot->Value('minLong','maxLong','minLat','maxLat'));
$plot->gridFilter($plot->Value('gridFilter'));
$plot->PrintValues if $plot->verbose; # show values

# create block file (bin file) using median or mean of values 
if($plot->gridFilter eq 'median') {
    $plot->blockmedian($plot->Name('xyzFile','blockFile'));
} else {
    $plot->blockmean($plot->Name('xyzFile','blockFile'));
}

# create a grid 
if($plot->gridMethod eq 'nearneighbor') {
    $plot->nearneighbor($plot->Name('blockFile','gridFile'));
} elsif($plot->gridMethod eq 'triangulate') {
    $plot->triangulate($plot->Name('blockFile','gridFile'));
}else { #default
    $plot->surface($plot->Name('blockFile','osGridFile'));
    $plot->grdcut($plot->Name('osGridFile','gridFile'));
}

if($plot->netcdf()) {
    $plot->grid2netcdf();
}


#$plot->maskgrid if $plot->mask;

################# generate PostScript

$plot->plotconfig(); # set up various plot parameters

# plot surface
if(not $plot->linesOnly) {
    $plot->psFirst->grdview($plot->Name('gridFile','psFile'));
} else { # linesOnly
    $plot->psFirst($plot->Name('psFile'));
}
# plot survey path
$plot->psxy($plot->Name('xyzFile','psFile')) if $plot->showPath;

if($plot->smoothsheet) {
    $plot->PlotSmoothsheet($plot->Name('gridFile','psFile'));
}

# basemap frames
#$plot->psgridlines('psFile');

$plot->psscale($plot->Name('psFile')) if $plot->showscale;


# create contour lines
if($plot->contour || $plot->linesOnly) {
    if($plot->mask) {
	$plot->maskcontour($plot->Name('psFile'));
    } else {
	$plot->grdcontour($plot->Name('gridFile','psFile'));
    }
} else { # no contour lines
    ;
}
$plot->psLast->psbasemap($plot->Name('psFile'));

if ($plot->clean) {
    foreach my $file ($plot->Name()) {
	unlink $file;
    }
}

exit;

############# subroutines ################
sub MakeName { # generate a file name (and path) from input, output, and extn
    my($inputFile,$outputFile,$extension) = @_;
    my $result;

    #take the only the filename (without extension) from the inputFile
    # (note that the regexpression parts are delimited by , instead of /)
    $inputFile =~ s,^.*\/,,g;
    $inputFile =~ s,\.[A-Za-z0-9]*$,,;
    
    #take only the path from the outputFile
    $outputFile =~ s,[^/]+$,,;
    return("${outputFile}${inputFile}.${extension}");
}





####################################################################
################ PACKAGE GMT #######################################
####################################################################

package GMT;
use Geo::Coordinates::UTM;
our $AUTOLOAD;

sub new {
    my $invoc = shift;
    my %values = @_;
    my $self = {};


    # object creation
    my $class = ref($invoc) || $invoc;
    bless($self,$class);

    # update with arguments and default values
    %$self = (
	      smoothsheet => 0,
	      Region => undef, # -R option for gridding
	      SubRegion => undef, # -R option for plotting 
	      gradAz => 300,
	      over => 1.25,   # make the image * survey size
	      mask => 0,
	      cptTable => 'shallowWater',
	      cptFile => 'shallowWater.cpt',
	      revcptTable => undef,
	      symcptTable => 'bright',
	      gradNorm => 't.65',
	      useBinary => 1,
	      showscale => 0,
	      inputFiles => [],
	      verbose => 0,
	      negateZ => 1,
	      inputFields => "1,2,3,\t",
	      gridSizeM => 15, # grid size in Meters
	      gridSize => ".5c",
	      minLong => undef,
	      linesOnly => 0,
	      maxLong => undef,
	      minLat => undef,
	      maxLat => undef,
	      minZ => undef,
	      maxZ => undef,
	      sminLong => undef,
	      smaxLong => undef,
	      sminLat => undef,
	      smaxLat => undef,
	      oversize => 0, # oversized grid Region % that will be cut
	      gridFilter => 'median',
	      gridMethod => 'surface',
	      filter1Dtype => 'median',
	      filter1Dwidth => 3,
	      surfConvergance => 0.25,
	      surfTension => 0.8,
	      showscale => 0,
	      ticks => 0,
	      eps => 0,
	      contour => 1, # flag for drawing contour lines
	      contourIntv => 1,
	      contourAnnt => 5,
	      showPath => 0,
	      mask => 0,
	      clean => 1,
	      pageX => 8.5, # assuming A4 paper -- inches
	      pageY => 11,
	      projection => 'M7i',
	      pscoastBaseArgs => [-Df,-U],
	      psFile => 'out.ps',
	      netcdf => undef,
	      landClr => 'white',
	      BACKGROUNDClr => '128/128/255',
	      portrait => 1,
	      makecptSet => {
		  continuous => 0,
	      },
	      grdviewSet => {
		  azimuth => 180,
		  elevation => 90,
		  smoothing => 1,
	      },
	      smoothparamsSet => {
		  size => 8,
		  angle => 45,
		  fontno => 1,
		  justify => 'CM',
	      },
	      psbasemapSet => {
		  primaryFrame => 'f1cg1ca10cWSne',
		  secondaryFrame => 'f10c',
	      },
	      psxySet => {
		  symbol => 'c4p',
                  line => "thinner,255/0/0",
	      },
	      psscaleSet => {
		  xpos => '2i', 
		  ypos => '10i',
		  length => '4i',
		  width => '.25i',
	      },
	      pscontourSet => {
		  smoothfactor     => 2,
		  linespec            => '+k255/255/255+c5+jCB',
		  contourInt          => '1', # -C
		  contourAnnt         => '5', # -A
		  cpt              => 'bright.cpt',
		  a_pen             => "1p255/100/100",
		  c_pen            => "0.25p0/128/128",
	      },
	      surfaceSet => {
		  convergence        => 0.5,
		  iterations         => 50,
		  formatting          => 'g', # geographic formating
	      },
	      nearneighborSet => {
		  searchradius => '1c',
		  formatting => 'x,y,f',
	      },
              triangulateSet => {
              },
	      blockmedianSet => {
		  formatting => 'g', # geographic
	      },
	      blockmeanSet => {
		  formatting => 'g', # geographic
	      },
              grdgradientSet => {
                  direction => 280,
              },
	      gmtDefaults => {
		  PAPER_MEDIA        => 'A3',
		  D_FORMAT           => '%12lg',
		  BASEMAP_TYPE => 'fancy+',
		  ANNOT_FONT_SIZE_PRIMARY    => '10p',
		  ANNOT_FONT_SIZE_SECONDARY    => '12p',
		  LABEL_OFFSET => '0p',
		  PLOT_DEGREE_FORMAT => 'ddd.mmF',
		  GRID_CROSS_SIZE_PRIMARY => '4p',
		  GRID_CROSS_SIZE_SECONDARY => '4p',
		  GRID_PEN_PRIMARY => 'thin,white',
		  TICK_LENGTH => '0p',
		  COLOR_NAN => '0/0/0',
		  ELLIPSOID => 'WGS-84',

	      },
	      DESTROY => undef,
    );

    my @keys = grep !/Set/, keys(%{$self}) ; # a list of the key w/o 'Set'
    # make a hash for quick search
    $self->{_permitted} = { map { $_, 1 } @keys };

    for my $key(keys %values){
	$self->{$key} = $values{$key};
    }
    return $self;
}

sub AUTOLOAD {
    my ($self) = shift(@_);
    my ($type) = ref($self) || warn "$self is not an object\n";
    my ($name) = $AUTOLOAD;

    $name =~ s/.*://; # strip away fully qualified portion
    unless (exists $self->{_permitted}->{$name}) {
	warn "Can't access \"$name\" field in object of class $type\n";
    }
    if (@_) { # argument list contains something
	return $self->{$name} = shift(@_);
    } else { # just return value
	return $self->{$name};
    }
}

sub DESTROY {
    ;
}

sub inputFiles { # set or retrieve list of input files
    my $self = shift;
    if(scalar @_) {
	$self->{inputFiles} = [@_];
    }
    return $self->{inputFiles};
}

sub tempFiles { # set temporary file values
    my $self = shift;
    my %values = @_;

    for my $key(keys %values) {
	$self->{tempFiles}{$key} = $values{$key};
    }
    return $self;
}

sub Name { # return filenames of temporary files
    my $self = shift;
    my @keys = @_;
    my @results = ();

    if(@keys) { 
	foreach my $key (@keys) {
	    push(@results,${$self->{tempFiles}}{$key});
	}
    } else { # all of them
	@results = values %{$self->{tempFiles}};
    }
    return(@results);
}

sub Value { # return a list of the values corresponding to the keys in args
    my $self = shift(@_);
    my @keys = @_;
    my @results = ();
    if(@keys) {
	foreach my $key (@keys) {
	    push(@results,$self->{$key});
	}
    } else { # return them all
	@results = values(%$self);
    }
    return(@results);
}
    


sub FileReplace { # replace the value of one file type with another 
    my $self = shift;
    my $type = shift;
    my $newtype = shift;

    ${$self->{tempfiles}}{$type} = ${$self->{tempfiles}}{$newtype};
    return ${$self->{tempFiles}}{$type};
}



sub SubRegion {
    my $self = shift;
    if(defined $self->sminLong 
       && defined $self->smaxLong 
       && defined $self->sminLat 
       && defined $self->smaxLat) {
	$self->{SubRegion} = $self->h2f($self->sminLong) . 
	    '/' . $self->h2f($self->smaxLong) .
	    '/' . $self->h2f($self->sminLat) . 
	    '/' . $self->h2f($self->smaxLat);
    } 
    return $self->{SubRegion}
}

sub plotconfig {
    my $self = shift;

    # configure basemap gradicule 
    if($self->ticks) {
	$self->{psbasemap}{primaryFrame} = 'f1cg'
	    . $self->ticks
	    . 'ca10cWSne';
	$self->{psbasemap}{secondaryFrame} = 'f10c';
    } else {
	$self->{psbasemap}{primaryFrame} = 'f1ca10cWSne';
	$self->{psbasemap}{secondaryFrame} = 'f10c';
    }
    
    # configure contour specs
    if ($self->{contourIntv}) {
	$self->{pscontourSet}->{contour} = $self->{contourIntv} .
	    $self->{pscontourSet}->{linespec};
    }else{ # make from gmtDefaults
	$self->{pscontourSet}->{contour} = 
	    $self->{pscontourSet}->{contourIntv} .
	    $self->{pscontourSet}->{linespec};
    }
    if ($self->{contourAnnt}) {
	$self->{pscontourSet}->{annotation} = $self->{contourAnnt} .
	    $self->{pscontourSet}->{linespec};
    }else{ # make from gmtDefaults
	$self->{pscontourSet}->{contour} = 
	    $self->{pscontourSet}->{contourAnnt} .
	    $self->{pscontourSet}->{linespec};
    }
    $self->{pscontourSet}->{annotation} = $self->{contourAnnt} .
	'+k128/50/50+c5+jCB'if $self->{contourAnnt};

    # cpt file setup
    # create cpt files if they don't already exist
    $self->createCPTs($self->cptTable,$self->symcptTable);

}

################### statistics #################################

sub baseStats {
    my $self = shift;
    my $file = shift || $self->Name('xyz');

    ($self->{minLong},
     $self->{maxLong},
     $self->{minLat},
     $self->{maxLat},
     $self->{minZ},
     $self->{maxZ}) = $self->minmax($file);


    # a little help with the debuging
    print STDERR join(" ", "minmax:",
		      $self->{minLong},
		      $self->{maxLong},
		      $self->{minLat},
		      $self->{maxLat},
		      $self->{minZ},
		      $self->{maxZ},
		      "\n") if $self->{verbose};
}


######## getLimits
sub getLimits {
    my $self = shift;
    return ($self->d2h($self->{over}*$self->{minLong},1),
	    $self->d2h($self->{over}*$self->{maxLong},1),
	    $self->d2h($self->{over}*$self->{minLat},1),
	    $self->d2h($self->{over}*$self->{maxLat},1)
	    );
}

######### h2f - converts from dd::mm:ss.ss to dd.ddddd
sub h2f {
    my $self = shift;
    my $hstring = shift;
    my($h,$m,$s) = split(/:/,$hstring);
    my($sign) = ($h > 0) ? 1 : -1;
    return sprintf("%.5f",$h + ($sign * $m/60) + ($sign * $s/3600));
}
	

########## d2h
sub d2h { # converts from decimal to dd:mm:ss.ss notation
    my $self = shift;
    my $decVal = shift;
    my $secPts = shift; # the number of decimal points in seconds, default all

    my $sign = ( $decVal > 0 ) ? 1 : -1;
    $decVal *= $sign; # absolute value
    my $deg = int($decVal);
    my $tmp = 60*($decVal - $deg);
    my $min = int($tmp);
    my $sec = 60*($tmp - $min);

    if(defined $secPts) { # format for precision
	$sec = sprintf("%.${secPts}f",$sec);
    }

    $deg *= $sign; # reinsert sign

    return("$deg:$min:$sec");
}

############################ color tables #################################
sub createCPTs {
    my $self = shift;

    my $cptTable = shift(@_) || $self->cptTable;
    my $symcptTable = shift(@_) || $self->symcptTable;

    my @cptTable;
    my $entry;

    if($cptTable ne "shallowWater") {
	$self->makecpt($cptTable,
		$self->minZ,$self->maxZ,($self->maxZ - $self->minZ)/20);
    }else{
	if(! -e "shallowWater.cpt") {
	    @cptTable = (   
                        [qw( -30    0    0     64   -20    20    20   200)],
			[qw( -20    0    0    255   -10    64    64   200)],
			[qw( -10   20   20    200    -5    50    100  200)],
			[qw(  -5   50  100    200    -1   200    255  255)],
			[qw(  -1   100 255    100     0   225    255  255)],
			[qw(   0  200    0      0     5   255    255    0)]
			    );
	
	    open(CPT,">shallowWater.cpt") || die "cannot open cpt file: $?\n";
	    foreach $entry (@cptTable) {
		print CPT join("\t",@$entry),"\n";
	    }
	    close CPT;
	}
    }

    if($symcptTable ne "bright") {
	$self->makecpt($cptTable,
		$self->minZ,$self->maxZ,($self->maxZ - $self->minZ)/20);
    }else{
	if(! -e "bright.cpt") {
	    @cptTable = (   
			[qw( -200 128  128   128     -20  255  255  255)],
			[qw(  -20 255  255   255      -5  255  255  000)],
			[qw(   -5 255  255   000       0  200  000  000)]
			    );
	
	    open(CPT,">bright.cpt") || die "cannot open cpt file: $?\n";
	    foreach $entry (@cptTable) {
		print CPT join("\t",@$entry),"\n";
	    }
	    close CPT;
	}
    }
    return $self;
}

#################### geographic area subroutines ################

sub setGeoArea { # assumes that the values in the proper order
    my $self = shift;
    my @args = @_;



    if((scalar @args) < 4) {
	# use the max and mins
	@args = ($self->{minLong},
		 $self->{maxLong},
		 $self->{minLat},
		 $self->{maxLat});
    }
    
    my ($gridXdim,$gridYdim);

    # do a little UTM math to see sizes in meters
    my($minZone,$minEasting,$minNorthing) =
	latlon_to_utm('WGS84',$self->{minLat},$self->{minLong});
    my($maxZone,$maxEasting,$maxNorthing) =
	latlon_to_utm('WGS84',$self->{maxLat},$self->{maxLong});
    $self->{xMeters} = sprintf("%.1f",$maxEasting - $minEasting);
    $self->{yMeters} = sprintf("%.1f",$maxNorthing - $minNorthing);


    if ($self->{yMeters} > $self->{xMeters}) {
	$self->{portrait} = 1;
	$self->{projection} = 'M7i';
    } else {
	$self->{portrait} = 0;
	$self->{projection} = 'M9i';
    }

    ($self->{gridSize},$gridXdim,$gridYdim)
	= $self->setGridSize(@args);
    $self->{Region} = join('/',@args);

    # oversize calcs

    # use the max and mins and apply ovesize
    my $longMean = ($self->{maxLong} + $self->{minLong}) / 2;
    my $longDiff = ($self->{maxLong} - $self->{minLong}) / 2;
    my $latMean = ($self->{maxLat} + $self->{minLat}) / 2;
    my $latDiff = ($self->{maxLat} - $self->{minLat}) / 2;

    if($self->{oversize}) {
	my $osFactor = $self->{oversize}/100 + 1;
	my @osArgs = (
		      ($longMean - $osFactor * $longDiff),
		      ($longMean + $osFactor * $longDiff),
		      ($latMean - $osFactor * $latDiff),
		      ($latMean + $osFactor * $latDiff)
		      );

	($self->{osGridSize},$gridXdim,$gridYdim)
	    = $self->setGridSize(@osArgs);    
	$self->{osRegion} = join('/',@osArgs);
	
	# now we need to adjust the original region for clipping
	$self->{newRegion} =
	    join('/',$self->setRegion($gridXdim,$gridYdim,@args));
    }

    return $self;
}

###### setRegion -- find a region near that specified and that works with
# the specified gridsize

sub setRegion {
    # takes a grid size and proposed Region matrix (list) and returns
    # Region that is close to the proposed but uses exactly the grid
    # (sort of the inverse of setGridSize) 
    # assumes grid is in seconds arc and Region in decimal degrees

    my $self = shift(@_);
    my ($gridX,$gridY,$minLong,$maxLong,$minLat,$maxLat) = @_;

    my $meanLong = ($maxLong + $minLong) / 2;
    my $meanLat = ($maxLat + $minLat) / 2;
    my $xWidth = ($maxLong - $minLong);
    my $yWidth = ($maxLat - $minLat);

    my $xCells = sprintf("%.0f",$xWidth * 3600 / $gridX); # rounded
    my $yCells = sprintf("%.0f",$yWidth * 3600 / $gridY); # rounded

    my $newMinLong = 
	sprintf("%.5f", $meanLong - ($xCells * $gridX) / 7200); # centered
    my $newMaxLong = 
	sprintf("%.5f", $meanLong + ($xCells * $gridX) / 7200); # centered
    my $newMinLat = 
	sprintf("%.5f", $meanLat - ($yCells * $gridY) / 7200); # centered
    my $newMaxLat = 
	sprintf("%.5f", $meanLat + ($yCells * $gridY) / 7200); # centered

    return($newMinLong,$newMaxLong,$newMinLat,$newMaxLat);
}


###### setGridSize
sub setGridSize { # uses a meter designation to set grid (in degrees)
    my $self = shift;
    my ($minLong,$maxLong,$minLat,$maxLat) = @_;

    my $gridSize = undef;
    my $estimate = $self->{gridSizeM}/31; # first we do an estimate

    # now adjust for maxLong - minLong to make grid fit region
    my $xDelta = ($maxLong - $minLong) * 3600;
    my $xcells = sprintf("%.0f",$xDelta/$estimate);
    my $gridXdim = sprintf("%.9f",$xDelta/$xcells); 

    # now adjust for maxLat - minLat to make grid fit region
    my $yDelta = ($maxLat - $minLat) * 3600;
    my $ycells = sprintf("%.0f",$yDelta/$estimate);
    my $gridYdim = sprintf("%.9f",$yDelta/$ycells); 

    $gridSize = "${gridXdim}c/${gridYdim}c";

    return ($gridSize,$gridXdim,$gridYdim);
}


###### pStre2dec
sub pStr2dec { # generate a signed decimal value from a coord string
    my $self = shift;
    my $string = shift;
    my $sign = 1;
    my $value = 0;

    # figure the sign from the hemisphere
    if($string =~ s/\s*([nesw])//ig) {
	$sign = ($1 =~ /[sw]/i) ? -1 : 1;
    }
    my @pieces = split(/:/,$string); # separate into degree,minute,seconds
    while(@pieces) { # calculate from right to left
	$value = pop(@pieces) + $value/60;
    }
    return sprintf("%15.12f",$value * $sign);
}

######## Check -- check that we have all necessary values defined

sub Check {
    my $self = shift;
    my $result = 1;
    my $key;
    foreach $key (keys %$self) {
	if(not $self->{$key}) {
	    print STDERR "$key missing a value\n";
	    $result = 0;
	}
    }
    return $result;
}

######### PrintValues -- print all the object values to STDERR
sub PrintValues {
    my $self = shift;
    my $key;
    print STDERR "Values:\n";
    foreach $key (sort keys %$self) {
	if($self->{$key} && (not ref($self->{$key}))) {
	    print STDERR "\t$key => $self->{$key}\n";
	}
    }
    print STDERR "\n";
    return 1;
}

sub maskgrid {
    my $self = shift;
    return $self unless $self->mask;
    $self->xyz2grd;
    $self->grdmathmask;
    return $self;
}

sub maskcontour {
    my $self = shift;
    # use blockmedian to generate mask
    if($self->setGridFilter eq 'mean') {
	$self->blockmedian($self->Name('xyz'),$self->Name('maskFile'));
	$self->psmaskstart($self->Name('mask'),$self->psFile);
    } else { # use what we got
	$self->psmaskStart($self->Name('block'),$self->psFile);
    }
    $self->grdcontour;
    $self->psmaskStop;
    return $self;
}

############################# smooth sheet plotting ######################

sub PlotSmoothsheet {
    my ($self) = shift(@_);
    my ($source) = shift || $self->Name('gridFile');
    my ($destination) = shift || $self->psFile;
    my ($pstextFile) =  $self->Name('pstextFile');
    
    # don't allow contours to conflict 
    #    $self->contour(0);

    my $p = $self->{smoothparamsSet};

#    if(! $self->useBinary) { # just a text file
#	if(! open(BLOCKFILE,"<$source")) {
#	    warn("can not read block file \"$source\": $!\n");
#	    return;
#	}
#    } else { # binary file
	if(! open(BLOCKFILE,"grd2xyz $source |")) {
	    warn("can not run grd2xyz on block file \"$source\": $!\n");
	    return;
	}
#    }

    # open the intermediate text file for writing pstext
    if(! open(PSTEXT,">$pstextFile")) {
	close BLOCKFILE;
	warn("can not open \"$pstextFile\" for writing pstext commands: $!\n");
	return;
    }
    
    # read each line and generate a corresponding pstext line
    while(my $line = <BLOCKFILE>) {
	chomp($line);
	my($x,$y,$z) = split(/\s+/,$line);
	if($z ne 'NaN' ) {
	    print(PSTEXT join(" ",
			      $x,
			      $y,
			      $p->{size},
			      $p->{angle},
			      $p->{fontno},
			      $p->{justify},
			      sprintf("%.0f",$z) .
			        '@-' .
			        sprintf("%.0f",10*(abs($z)-int(abs($z)))) .
			        '@-' ,
			      "\n") );
	}
    }
    close BLOCKFILE;
    close PSTEXT;

    $self->pstext($pstextFile,$self->psFile);
    return $self;
}

############################# masking with NaN cells in grid #############

sub grdmathmask {
    my $self = shift;


    my $source1 = shift || $self->Name('gridFile');
    my $source2 = shift || $self->Name('maskFile');
    my $destination = shift || $self->Name('resultgrid');

    my @args = ('grdmath',
		$source1,
		$source2,
		'OR',
		'=',
		$destination,
		);

    print(STDERR "\! @args\n") if $self->{verbose};
    system(@args) == 0 ||
	die "@args failed: $?";
    return $self;
    }



############################# GMT programs interfaces #################### 

################## makecpt
sub makecpt {
    my $self = shift;
    my $cptTable = shift || $self->cptTable;
    my($minZ,$maxZ,$incr) = @_;

    my $inverse = 0;
    my $destFile = "${cptTable}.cpt";
    my $tempFile = "${cptTable}.tmp";

    # set up for inverse cpt tables if required
    if ($cptTable =~ s/^i[a-zA-Z]*-//) { # dash prefix indicates inverse table
	$inverse = 1;
	$destFile = "invr-${cptTable}.cpt";
	$tempFile = "invr-${cptTable}.tmp";
    }

    my($p) = $self->{makecptSet};

    $minZ = sprintf("%.0f",$minZ) - 1;
    $maxZ = sprintf("%.0f",$maxZ) + 1;
    $incr = sprintf("%.0f",$incr);


    my @args = (      "makecpt",
		      "-C".$cptTable,
		      );
    push(@args,"-I") if $inverse;
    push(@args,"-Z") if $p->{continuous};

    if($minZ && $maxZ && $incr) {
	push(@args,"-T${minZ}/${maxZ}/${incr}");
    }

    print(STDERR "\! @args >$destFile\n") if $self->{verbose};
    open(STDOUT,">$tempFile") || 
	die "makecpts cannot open temp file \"$tempFile\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
    rename($tempFile,$destFile);

    $self->cptFile($destFile);
}
		     
#################### xyz2grd
sub xyz2grd {
    my $self = shift;
    my $source = shift || $self->Name('xyzFile');
    my $destination = shift || $self->Name('maskFile');

    my @args = (      "xyz2grd",
		      $source,
		      "-R".$self->Region,
		      "-I".$self->gridSize,
		      "-G$destination");
    push(@args,$self->GMTenv());
    push(@args,'-bi3') if $self->{useBinary};

    print(STDERR "\! @args\n") if $self->{verbose};
    system(@args) == 0 ||
	die "@args failed: $?";
}
		     


sub grdcut {
    my $self = shift;
    my $source = shift || $self->Name('osGridFile');
    my $destination = shift || $self->Name('gridFile');

    my @args = (      "grdcut",
		      $source,
		      "-R".$self->{Region},
		      "-G$destination");
    push(@args,$self->GMTenv());

    print(STDERR "\! @args\n") if $self->{verbose};
    system(@args) == 0 ||
	die "@args failed: $?";
}
		     


########### grdmath -- do math on the grid values
sub grdmath {
    my $self = shift;
    my $math = shift;


    my $source1 = $self->Name('gridFile');
    my $source2 = $self->Name('maskFile');
    my $destination = shift;

    #clean math string
    $math =~ s/^\s+//;
    $math =~ s/\s+$//;

    my @args = ('grdmath',
		$source1,
		$source2,
		split(/\s+/,$math),
		'=',
		$destination,
		);

    push(@args,$self->GMTenv());
    push(@args,'-bi3') if $self->{useBinary};

    print(STDERR "\! @args\n") if $self->{verbose};
    system(@args) == 0 ||
	die "@args failed: $?";
    return $self;
    }


######### GMTenv -- make command line arguments for internal
#                             'default' settings - these will be used
#                             on each GMT command if needed
sub GMTenv {
    my $self = shift;
    my @results;

    # ensure eps flag exists
    if ($self->{eps}) {
	$self->{gmtDefaults}->{PAPER_MEDIA} =~ s/$/+/;
	$self->{gmtDefaults}->{PAPER_MEDIA} =~ s/\+\+/+/;
    } else {
	$self->{gmtDefaults}->{PAPER_MEDIA} =~ s/\++$//;
    }

    foreach my $key(sort keys %{$self->{gmtDefaults}}) {
	my $value = ${$self->{gmtDefaults}}{$key};
	push(@results,"--${key}=${value}");
    }
    return @results;

}


############ minmax -- basic statistics on tables and grids
sub minmax {
    my $self = shift;
    my $filename = shift;
    my @args = ( "minmax",
		 $filename,
		 "-C");

    my $argStr = "@args";

    print(STDERR "\! @args\n") if $self->{verbose};
    my $result = `$argStr`;
    if ($?) {
	die "@args failed: $?";
    } else {

	# remove leading and trailing whitespace
	$result =~ s/^\s+//;
	$result =~ s/\s+$//;

	my(@values) = split(/\s+/,$result);
	return(@values);
    }
}

############ grdinfo
sub grdinfo {
    my $self = shift;
    my $filename = shift || ($self->mask) ?
	$self->Name('resultgrid') : $self->Name('grid');

    my @args = ( "grdinfo",
		 $filename,
		 "-C");

    my $argStr = "@args";

    print(STDERR "\$ @args\n") if $self->{verbose};
    my $result = `$argStr`;
    if ($?) {
	die "@args failed: $?";
    } else {
	return split(/\t/,$result);
    }
}

############### surface

sub surface {
    my $self = shift;
    my $source = shift || $self->Name('blockFile');
    my $destination = shift || $self->Name('gridFile');

    my $p = $self->{surfaceSet};

    my @args = (      "surface",
		      $source,
		      "-T".$self->surfTension,
		      "-C".$p->{convergence},
		      "-N".$p->{iterations},
		      "-f".$p->{formatting},
		      "-G".$destination);
    if($self->{oversize}) {
	push(@args, 
	     "-R".$self->osRegion,
	     "-I".$self->osGridSize);
    } else {
	push(@args, 
	     "-R".$self->Region,
	     "-I".$self->gridSize);
    }

    push(@args,'-bi3') if $self->{useBinary};

    print(STDERR "\! @args\n") if $self->{verbose};
    system(@args) == 0 ||
	die "@args failed: $?";
}
		     

############### triangulate

sub triangulate {
    my $self = shift;
    my $source = shift || $self->Name('blockFile');
    my $destination = shift || $self->Name('gridFile');

    my $p = $self->{triangulateSet};

    my @args = (      "triangulate",
		      $source,
		      "-R".$self->Region,
		      "-I".$self->gridSize,
		      "-G".$destination,
		      );
    push(@args,'-bi3') if $self->{useBinary};

    print(STDERR "\! @args\n") if $self->{verbose};
    system(@args) == 0 ||
	die "@args failed: $?";
}
		     

############### nearneighbor
sub nearneighbor {
    my $self = shift;
    my $source = shift || $self->Name('blockFile');
    my $destination = shift || $self->Name('gridFile');
    my $p = $self->{nearneighborSet};

    my @args = (      "nearneighbor",
		      $source,
		      "-R".$self->Region,
		      "-I".$self->gridSize,
		      "-S".$p->{searchradius},
		      "-G$destination",
		      );
    push(@args,'-V') if $self->{verbose};
    push(@args,'-bi3') if $self->{useBinary};

    print(STDERR "\! @args\n") if $self->{verbose};
    system(@args) == 0 ||
	die "@args failed: $?";
}

########################## create a separte netcdf file from grid

sub grid2netcdf {
    my $self = shift;
    my ($gridFile) = $self->Name('gridFile');
    my ($netcdfFile) = $self->netcdf();

    # first try a link
    if(link($gridFile,$netcdfFile) ) {
	print STDERR "linked $gridFile to $netcdfFile\n";
    } else {	# else, copy it
	if( open(INPUT, "<$gridFile") ) {
	    if( open(OUTPUT, ">$netcdfFile") ) {
		my $buffer;
		while(sysread(INPUT,$buffer,10000)) {
		    syswrite(OUTPUT,$buffer,10000);
		}
	    }
	print STDERR "copied $gridFile to $netcdfFile\n";
	}
    } # if link
}


############## blockmedian
sub blockmedian {
    my $self = shift;
    my $source = shift || $self->Name('xyzFile');
    my $destination = shift || $self->Name('blockFile');
    my $p = $self->{blockmedianSet};

    my @args = (      "blockmedian",
		      $source,
		      "-I".$self->gridSize,
		      "-R".$self->Region,
                     "-f".$p->{formatting},
		      "-C",
		      );
    push(@args,'-bo3') if $self->{useBinary};

    print(STDERR "\! @args >$destination\n") if $self->{verbose};
    open(STDOUT,">$destination") || 
	die "pscoast cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}

############## blockmean
sub blockmean {
    my $self = shift;
    my $source = shift || $self->Name('xyzFile');
    my $destination = shift || $self->Name('blockFile') ;
    my $p = $self->{blockmeanSet};

    my @args = (      "blockmean",
		      $source,
		      "-I".$self->gridSize,
		      "-R".$self->Region,
		      "-f".$p->{formatting},
		      "-C",
		      );
    push(@args,'-bo') if $self->{useBinary};

    print(STDERR "\! @args >$destination\n") if $self->verbose;
    open(STDOUT,">$destination") || 
	die "pscoast cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}

################## gmtset
sub gmtset { # send the gmtDefaults to the local gmtDefaults file
    my $self = shift;
    $self->{gmtDefaults} = {@_};

    my @args = ("gmtset");
    for my $key(keys %{$self->{gmtset}}) {
	my $value = ${$self->{gmtset}}{$key};
	push(@args,$key);
	if($value =~ /^\[$%]/) {
	    push(@args,"\\$value");
	} else {
	    push(@args,$value);
	}
    }

    print(STDERR "\! @args\n") if $self->{verbose};
    system(@args) == 0 ||
	die "@args failed: $?";
}

############ table2xy --- read in a table to an xyz file
sub table2xy {
    my $self = shift;
    my $sourcePtr = shift || $self->inputFiles;
    my @sources = @{$sourcePtr};
    my $destination = shift || $self->Name('xyzFile');
    my $xcol = shift; $xcol -= 1;
    my $ycol = shift; $ycol -= 1;
    my $seprtr = shift;

    open (DEST, ">$destination") ||
	die "table2xy cannot open \"$destination\" for writing: $!\n";

    foreach my $source (@sources) {
	open (SOURCE, "<$source") || 
	    die "table2xy cannot open \"$source\" for reading: $!\n";
	while(<SOURCE>) {
	    chomp;
	    my(@fields) = split($seprtr,$_);
	    print DEST 
		join("\t",$fields[$xcol],$fields[$ycol]),1.00000,"\n";
	}
	close SOURCE;
    }

    close DEST;

    print STDERR "table2xy wrote to \"$destination\"\n" if $self->{verbose};
}

############ table2xyz
sub table2xyz {
    my $self = shift(@_);
    my $inputPtr = shift(@_) || $self->inputFiles;
    my @inputFiles = @{$inputPtr};
    my $destination = shift || $self->Name('xyzFile');
    my @inputFields = split(/[,:\/]/,$self->inputFields);
    my $xcol = shift || $inputFields[0]; 
    $xcol -= 1;
    my $ycol = shift || $inputFields[1]; 
    $ycol -= 1;
    my $zcol = shift || $inputFields[2]; 
    $zcol -= 1;
    my $seprtr = shift || $inputFields[3]; 

    open (DEST, ">$destination") ||
	die "table2xyz cannot open \"$destination\" for writing: $!\n";

    foreach my $source (@inputFiles) {
	open (SOURCE, "<$source") || 
	    die "table2xyz cannot open \"$source\" for reading: $!\n";
	while(<SOURCE>) {
	    chomp;
	    my(@fields) = split(/$seprtr/,$_);
	    if($self->{negateZ}) {
		print DEST 
		    join("\t",$fields[$xcol],$fields[$ycol],-1*$fields[$zcol]),
		    "\n";
	    } else {
		print DEST 
		    join("\t",$fields[$xcol],$fields[$ycol],$fields[$zcol]),
		    "\n";
	    }
	}
	close SOURCE;
    }
    close DEST;

    print STDERR "table2xyz wrote to \"$destination\"\n" if $self->{verbose};
}

######### grdgradient

sub grdgradient {
    my $self = shift;
    my $source = shift;
    $source = ($self->mask) ?
	$self->Name('resultgridFile') : $self->Name('gridFile') unless $source;

    my $destination = shift || $self->Name('intensityFile');
    my $p = $self->{grdgradientSet};

    my @args = ("grdgradient",
		$source,
		"-G".$destination,
		"-A".$p->{direction},
		);
    push(@args,"-A$self->{gradAz}") if $self->{gradAz};
    push(@args,"-N$self->{gradNorm}") if $self->{gradNorm};
    push(@args,'-V') if $self->{verbose};

    print(STDERR "\! @args >>$destination\n") if $self->{verbose};

    system(@args) == 0 ||
	die "@args failed: $?";
}


################## postscript generators ########################

############### psFirst
sub psFirst { # begin a ps file
    my $self = shift;
    my $destination = shift || $self->psFile;

    unlink($destination) if $destination; # start fresh
    $self->{first} = 1;
    return $self;
}

############### psLast
sub psLast {
    my $self = shift;
    $self->{last} = 1;
    return $self;
}

############# SetFlags 
sub SetFlags {
    my $self = shift;
    my @args;

    if($self->{first} && $self->{last}) {
	@args = (); # nothing set
	$self->{first} = 0;
	$self->{last} = 0;
    } elsif ($self->{last}) {
	@args = ('-O');
	$self->{last} = 0;
    } elsif ($self->{first}) {
	@args = ('-K');
	$self->{first} = 0;
    } else {
	@args = ('-O','-K');
    }
    push(@args,'-P') if $self->portrait;
    push(@args,'-V') if $self->verbose;
    return @args;
}

############### pstext
sub pstext { 
    my $self = shift;
    my $source = shift || $self->Name('textFile');
    my $destination = shift || $self->psFile;
    my $Region = $self->SubRegion || $self->Region;

    $source = '/dev/null' unless $source;

    my $p = $self->{pstextSet};

    my @args = (      "pstext",
		      $source,
		      "-R$Region",
		      "-J$self->{projection}",
		      );
    push(@args,$self->SetFlags);
    push(@args,$self->GMTenv());

    print(STDERR "\! @args >>$destination\n") if $self->{verbose};
    open(STDOUT,">>$destination") || 
	die "pscoast cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}

############### psscale
sub psscale { 
    my $self = shift;
    my $source = shift || $self->cptFile;
    my $destination = shift || $self->psFile;

    my $p = $self->{psscaleSet};

    my @args = (      "psscale",
		      "-C".$source,
		      );
    if($self->portrait) {
	push(@args, "-D".$p->{xpos}."/".$p->{ypos}.
		      "/".$p->{length}."/".$p->{width},
		      );
    } else { #landscape
	push(@args, "-D".$p->{ypos}."/".$p->{xpos}.
		      "/".$p->{length}."/".$p->{width},
		      );
    }
    push(@args,$self->SetFlags);
    push(@args,$self->GMTenv());

    print(STDERR "\! @args >>$destination\n") if $self->{verbose};
    open(STDOUT,">>$destination") || 
	die "psscale cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}

############# psgridlines
sub psgridlines {
    my $self = shift;
    my $destination = shift || $self->psFile;
    my $Region = $self->SubRegion || $self->Region;
    my $p = $self->{psbasemapSet};

    my @args = (      "psbasemap",
		      "-R$Region",
		      "-J$self->{projection}",
		      "-Bp$p->{gridFrame}",
		      );
    push(@args,'-W0p,white,-'),
    push(@args,$self->SetFlags);
    push(@args,$self->GMTenv());

    print(STDERR "\! @args >$destination\n") if $self->{verbose};
    open(STDOUT,">>$destination") || 
	die "psbasemap cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}

sub psbasemap { 
    my $self = shift;
    my $destination = shift || $self->psFile;
    my $Region = $self->SubRegion || $self->Region;

    my $p = $self->{psbasemapSet};

    my @args = (      "psbasemap",
		      "-R$Region",
		      "-J$self->{projection}",
		      "-Bp$self->{psbasemap}->{primaryFrame}",
		      "-Bs$self->{psbasemap}->{secondaryFrame}",
		      );
#    push(@args,'-L100m');
    push(@args,$self->SetFlags);
    push(@args,$self->GMTenv());

    print(STDERR "\! @args >> $destination\n") if $self->{verbose};
    open(STDOUT,">>$destination") || 
	die "psbasemap cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}

########### pscoast		
sub pscoast {
    my $self = shift;
    my $destination = shift || $self->psFile;
    my $Region = $self->SubRegion || $self->Region;

    my $p = $self->{pscoastSet};

    my @args = (      "pscoast",
		      @{$self->{pscoastBaseArgs}},
		      "-R$Region",
		      "-S$self->{BACKGROUNDClr}",
		      "-J$self->{projection}",
		      "-Bp$self->{primaryFrame}",
		      "-Bs$self->{secondaryFrame}",
		      "-G$self->{landClr}");
    push(@args,$self->SetFlags);
    push(@args,$self->GMTenv());

    print(STDERR "\$ @args\n") if $self->{verbose};
    open(STDOUT,">>$destination") || 
	die "pscoast cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}

######### grdcontour

sub grdcontour {
    my $self = shift;
    my $source = shift || $self->Name('gridFile');
#    $source = ($self->mask) ?
#	$self->Name('resultgridFile') : $self->Name('gridFile') unless $source;

    my $destination = shift || $self->psFile;

    $destination = $self->{psFile} unless $destination;
    my $Region = $self->SubRegion || $self->Region;

    my $p = $self->{pscontourSet};

    my @args = ("grdcontour",
		$source,
		"-A".$p->{annotation},
		"-C".$p->{contour},
		"-S".$p->{smoothfactor},
		"-R".$Region,
		"-J".$self->{projection},
		"-Wa".$p->{a_pen},
		"-Wc".$p->{c_pen},
		);
    push(@args,$self->SetFlags);
    push(@args,$self->GMTenv());

    print(STDERR "\! @args >>$destination\n") if $self->{verbose};
    open(STDOUT,">>$destination") ||
	die "grdcontour cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}

######### grdview
sub grdview {
    my $self = shift;
    my $source = shift || $self->Name('gridFile');

#    $source = ($self->mask) ?
#	$self->Name('resultgridFile') : $self->Name('gridFile') unless $source;

    my $destination = shift || $self->psFile;
    my $Region = $self->SubRegion || $self->Region;

    my $intensityFile = $self->Name('intensityFile');

    my $p = $self->{grdviewSet};

    $self->grdgradient($source,$intensityFile);
    
    my @args = ("grdview",
		$source,
		"-N-1/white",
		"-R$Region",
		"-J".$self->projection,
		"-C".$self->cptFile,
		"-E".$p->{azimuth}."/".$p->{elevation},
		"-Qs",
		"-I$intensityFile",
		);
    push(@args,"-S") if $p->{smoothing};
    push(@args,$self->SetFlags);
    push(@args,$self->GMTenv());

    print(STDERR "\! @args >>$destination\n") if $self->{verbose};
    open(STDOUT,">>$destination") ||
	die "grdview cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}

########## psmaskStart
sub psmaskStart {
    my $self = shift;
    my $source = shift || $self->Name('xyzFile');
    my $destination = shift || $self->psFile;
    my $Region = $self->SubRegion || $self->Region;

    my $p = $self->{psxySet};


    my @args = ( "psmask",
		 $source,
		 "-R$Region",
		 "-J$self->{projection}",
		 "-I".$self->gridSize,
		 "-T",
		 "-G128/128/128",
		 );
    push(@args,$self->SetFlags);
    push(@args,'-bi3') if $self->{useBinary};
    push(@args,$self->GMTenv());

    print(STDERR "\! @args >>$destination\n") if $self->{verbose};
    open(STDOUT,">>$destination") ||
	die "psmask cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}

########## psmaskStop
sub psmaskStop {

    my $self = shift;
    my $source = shift || $self->Name('xyzFile');
    my $destination = shift || $self->psFile;

    my $p = $self->{psxySet};

    my @args = ( "psmask",
		 "-C",
		 );
    push(@args,$self->SetFlags);
    push(@args,$self->GMTenv());

    print(STDERR "\! @args >>$destination\n") if $self->{verbose};
    open(STDOUT,">>$destination") ||
	die "psmask cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}

########## psxy
sub psxy {
    my $self = shift;
    my $source = shift || $self->Name('xyzFile');
    my $destination = shift || $self->psFile;
    my $Region = $self->SubRegion || $self->Region;
    my($show) = $self->showPath;

    my $p = $self->{psxySet};

    my @args = ( "psxy",
		 $source,
		 "-R$Region",
		 "-J$self->{projection}",
		 );
    
    if($show =~  /^L/i){ # line specified
	push(@args,"-W".$p->{line});
    } else { # use symbol
	push(@args,"-S".$p->{symbol});
	push(@args, "-C".$self->{symcptFile}.".cpt");
    }
    push(@args,$self->SetFlags);
    push(@args,$self->GMTenv());

    print(STDERR "\! @args >>$destination\n") if $self->{verbose};
    open(STDOUT,">>$destination") ||
	die "psxy cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}

########## psxyz
sub psxyz {
    my $self = shift;
    my $source = shift || $self->Name('pointsFile');
    my $destination = shift || $self->psFile;
    my $Region = $self->SubRegion || $self->Region;
    
    my $p = $self->{psxyzSet};

    my @args = ( "psxyz",
		 $source,
		 "-R$Region",
		 "-J$self->{projection}",
		 "-Cbright.cpt",
		 "-G",
		 "-Sc10p",
		 );
    push(@args,'-bi3') if $self->{useBinary};
    push(@args,$self->SetFlags);
    push(@args,$self->GMTenv());

    print(STDERR "\! @args >>$destination\n") if $self->{verbose};
    open(STDOUT,">>$destination") ||
	die "grdcontour cannot open \"$destination\" for output\n";
    system(@args) == 0 ||
	die "@args failed: $?";
    close(STDOUT);
}



Home
 Art
 Boat
 Photos
 Videos
 Mapping
   nmea2xyzt
   NMEAfields
   Datalogger
  Cleaning
  Analysis
  GridPlot
   bp
 SAACalendar