mirror of
https://github.com/Xastir/Xastir
synced 2026-08-13 17:46:16 -04:00
Wheen I replaced the non-portable "#!/usr/bin/perl" with the portable "#!/usr/bin/env perl" I neglected the fact that some scripts have a -w or -W argument after the command. This can't work with env, and the correct approach is to put "use warnings;" in the script instead.
2462 lines
68 KiB
Perl
2462 lines
68 KiB
Perl
#!/usr/bin/env perl
|
|
use warnings;
|
|
|
|
#
|
|
# Coordinate.pm: Perl module for:
|
|
#
|
|
# 1) Creating and manipulating Coordinate objects,
|
|
# 2) Translating coordinates between UTM and Latitude/Longitude,
|
|
# 3) Translating coordinates between ~231 different datums,
|
|
# 4) Formatting coordinates into decimal degrees, degrees/minutes,
|
|
# and degrees/minutes/seconds.
|
|
#
|
|
# Copyright (C) 2000-2012 Curt Mills, WE7U
|
|
#
|
|
# 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.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
#
|
|
|
|
|
|
#
|
|
# Reference ellipsoids derived from Peter H. Dana's website-
|
|
# New: http://www.Colorado.EDU/geography/gcraft/notes/datum/elist.html
|
|
#
|
|
# Old: http://www.utexas.edu/depts/grg/gcraft/notes/datum/elist.html
|
|
# Department of Geography, University of Texas at Austin
|
|
# Internet: pdana@mail.utexas.edu
|
|
# 3/22/95
|
|
#
|
|
#
|
|
# Reference datums derived from Peter H. Dana's website-
|
|
# http://www.Colorado.EDU/geography/gcraft/notes/datum/datum.html#GeoDat
|
|
#
|
|
#
|
|
# UTM<->LAT/LON translations were originally written in C++ by
|
|
# Chuck Gantz- chuck.gantz@globalstar.com. Permission received
|
|
# by Chuck Gantz via e-mail to release it under the GPL license.
|
|
# Re-coded into Perl by Curt Mills.
|
|
#
|
|
# Datum translations were originally written in C by
|
|
# John F. Waers - jfwaers@csn.net. His code was released to
|
|
# the public domain. Re-coded into Perl by Curt Mills.
|
|
#
|
|
#
|
|
# TODO:
|
|
# -----
|
|
# Please note that I didn't pay a lot of attention to
|
|
# keeping the "double" notation in the form of higher
|
|
# precision floating point routines. This means that
|
|
# the Perl5 code won't be as accurate as the original
|
|
# C-code. It doesn't matter for my purposes. If
|
|
# anyone converts to Math::BigFloat for higher precision,
|
|
# please send me the changes. As it is I did a
|
|
# quick check and found a difference of only 1.4 meters
|
|
# between my Perl results and the results from a web-based
|
|
# datum-shift calculator on the 'net. -- Curt.
|
|
#
|
|
# Should probably add return values for each method. Check
|
|
# for error conditions and return 0 if problem.
|
|
#
|
|
# Add method to tell distance in meters of datum shift (verbose flag?)
|
|
#
|
|
# Get rid of print statements unless verbose or debug mode.
|
|
#
|
|
# POD documentation.
|
|
#
|
|
|
|
|
|
#------------------------------------------------------------------------------------------------
|
|
|
|
|
|
package CoordinateFormat;
|
|
|
|
|
|
$VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
|
|
|
|
|
|
#
|
|
# Conversions between decimal degrees, degrees/decimal minutes, and
|
|
# degrees/minutes/seconds. These are methods which all work on
|
|
# "CoordinateFormat" objects.
|
|
#
|
|
# These routines probably need a bit of work yet. It'd be nice
|
|
# to be able to specify field widths.
|
|
#
|
|
|
|
|
|
sub new
|
|
{
|
|
my $class = shift; # What class are we constructing?
|
|
my $self = { }; # Allocate new memory
|
|
bless $self, $class; # Mark it of the right type
|
|
$self->_init(@_); # Call _init with remaining args
|
|
return $self;
|
|
}
|
|
|
|
|
|
sub _init
|
|
{
|
|
my $self = shift;
|
|
$self->{RAW} = shift if @_; # Input string
|
|
$self->{FORMATTED} = shift if @_; # Output string, formatted
|
|
}
|
|
|
|
|
|
sub raw # Set'er/Get'er for input string
|
|
{
|
|
my $self = shift;
|
|
$self->{RAW} = shift if @_;
|
|
return $self->{RAW};
|
|
}
|
|
|
|
|
|
sub formatted # Set'er/Get'er for formatted string
|
|
{
|
|
my $self = shift;
|
|
$self->{FORMATTED} = shift if @_;
|
|
return $self->{FORMATTED};
|
|
}
|
|
|
|
|
|
#
|
|
# Returns the version number (RCS version tag) of this module.
|
|
#
|
|
sub version
|
|
{
|
|
return $VERSION;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Degrees and Decimal Minutes
|
|
#
|
|
# Fills in the FORMATTED variable in the object and also returns
|
|
# the string. If unsuccessful, returns an empty string.
|
|
#
|
|
sub degrees_minutes
|
|
{
|
|
my $self = shift; # Get the object to work on
|
|
my $input = $self->raw();
|
|
|
|
my ($degrees, $minutes, $seconds);
|
|
|
|
if ( $input =~ /\d+\s+\d+\s+\d+\.*\d*/ ) # Input is in "DD MM SS.SS" format
|
|
{
|
|
$degrees = $minutes = $seconds = $input;
|
|
$degrees =~ s/(\d+)\s+\d+\s+\d+\.*\d*/$1/;
|
|
$minutes =~ s/\d+\s+(\d+)\s+\d+\.*\d*/$1/;
|
|
$seconds =~ s/\d+\s+\d+\s+(\d+\.*\d*)/$1/;
|
|
$minutes = $minutes + ($seconds / 60.0);
|
|
$self->formatted( sprintf( "%02d %02.8f", $degrees, abs($minutes) ) );
|
|
return( $self->formatted() );
|
|
}
|
|
elsif ( $input =~ /\d+\s+\d+\.*\d*/ ) # Input is in "DD MM.MM" format
|
|
{
|
|
$self->formatted( $input ); # No translation necessary
|
|
return( $self->formatted() );
|
|
}
|
|
elsif ( $input =~ /\d+\.*\d*/ ) # Input is in "DD.DDDD" format
|
|
{
|
|
$degrees = int ($input);
|
|
$minutes = ($input - $degrees) * 60.0;
|
|
$self->formatted( sprintf( "%02d %02.8f", $degrees, abs($minutes) ) );
|
|
return( $self->formatted() );
|
|
}
|
|
else
|
|
{
|
|
print "degrees_minutes() method: Input format not recognized: $input\n";
|
|
$self->formatted( "" );
|
|
return( "" ); # Should I die here instead?
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Degrees/Minutes/Seconds
|
|
#
|
|
# Fills in the FORMATTED variable in the object and also returns
|
|
# the string. If unsuccessful, returns an empty string.
|
|
#
|
|
sub degrees_minutes_seconds
|
|
{
|
|
my $self = shift; # Get the object to work on
|
|
my $input = $self->raw();
|
|
|
|
my ($degrees, $minutes, $seconds);
|
|
|
|
if ( $input =~ /\d+\s+\d+\s+\d+\.*\d*/ ) # Input is in "DD MM SS.SS" format
|
|
{
|
|
$self->formatted( $input ); # No translation necessary
|
|
return( $self->formatted() );
|
|
}
|
|
elsif ( $input =~ /\d+\s+\d+\.*\d*/ ) # Input is in "DD MM.MM" format
|
|
{
|
|
$degrees = $minutes = $input;
|
|
$degrees =~ s/(\d+)\s+\d+\.*\d*/$1/;
|
|
$minutes =~ s/\d+\s+(\d+\.*\d*)/$1/;
|
|
$seconds = $minutes;
|
|
$minutes = int ($minutes);
|
|
$seconds = ($seconds - $minutes) * 60.0;
|
|
$self->formatted( sprintf( "%02d %02d %02.8f", $degrees, abs($minutes), abs($seconds) ) );
|
|
return( $self->formatted() );
|
|
}
|
|
elsif ( $input =~ /\d+\.*\d*/ ) # Input is in "DD.DDDD" format
|
|
{
|
|
$degrees = int ($input);
|
|
$minutes = int ( ($input - $degrees) * 60.0 );
|
|
$seconds = ( ( ($input - $degrees) * 60.0) - $minutes) * 60.0;
|
|
$self->formatted( sprintf( "%02d %02d %02.8f", $degrees, abs($minutes), abs($seconds) ) );
|
|
return( $self->formatted() );
|
|
}
|
|
else
|
|
{
|
|
print "degrees_minutes_seconds() method: Input format not recognized: $input\n";
|
|
$self->formatted( "" );
|
|
return( "" ); # Should I die here instead?
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Decimal Degrees
|
|
#
|
|
# Fills in the FORMATTED variable in the object and also returns
|
|
# the string. If unsuccessful, returns an empty string.
|
|
#
|
|
sub decimal_degrees
|
|
{
|
|
my $self = shift; # Get the object to work on
|
|
my $input = $self->raw();
|
|
|
|
my ($degrees, $minutes, $seconds);
|
|
|
|
if ( $input =~ /\d+\s+\d+\s+\d+\.*\d*/ ) # Input is in "DD MM SS.SS" format
|
|
{
|
|
$degrees = $minutes = $seconds = $input;
|
|
$degrees =~ s/(\d+)\s+\d+\s+\d+\.*\d*/$1/;
|
|
$minutes =~ s/\d+\s+(\d+)\s+\d+\.*\d*/$1/;
|
|
$seconds =~ s/\d+\s+\d+\s+(\d+\.*\d*)/$1/;
|
|
$self->formatted( sprintf( "%02.8f", $degrees + ($minutes/60.0) + ($seconds/(60.0 * 60.0) ) ) );
|
|
return( $self->formatted() );
|
|
}
|
|
elsif ( $input =~ /\d+\s+\d+\.*\d*/ ) # Input is in "DD MM.MM" format
|
|
{
|
|
$degrees = $minutes = $input;
|
|
$degrees =~ s/(\d+)\s+\d+\.*\d*/$1/;
|
|
$minutes =~ s/\d+\s+(\d+\.*\d*)/$1/;
|
|
$self->formatted( sprintf( "%02.8f", $degrees + ($minutes / 60.0) ) );
|
|
return( $self->formatted() );
|
|
}
|
|
elsif ( $input =~ /\d+\.*\d*/ ) # Input is in "DD.DDDD" format
|
|
{
|
|
$self->formatted( $input ); # No translation necessary
|
|
return( $self->formatted() );
|
|
}
|
|
else
|
|
{
|
|
print "decimal_degrees() method: Input format not recognized: $input\n";
|
|
$self->formatted( "" );
|
|
return( "" ); # Should I die here instead?
|
|
}
|
|
}
|
|
|
|
|
|
#------------------------------------------------------------------------------------------------
|
|
|
|
|
|
package Ellipsoid;
|
|
|
|
|
|
$VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
|
|
|
|
|
|
#
|
|
# Ellipsoid: Equatorial_Radius is the ellipsoid semimajor axis (a)
|
|
# Polar_Radius is the ellipsoid semiminor axis (b).
|
|
# First_Ecc_Squared is the first eccentricity squared, defined as: 2f - (f^2)
|
|
# Inverse_flattening (1/f) is the inverse of ellipsoid flattening 'f'
|
|
# Flattening (f) is defined as: (a-b)/a.
|
|
#
|
|
# This object is used to create the Ellipsoid_Table object below,
|
|
# containing all of the parameters to describe the various
|
|
# ellipsoids that we need for datum and UTM<->Lat/Lon translations.
|
|
#
|
|
# Equatorial_Radius and First_Ecc_Squared are used by the UTM<->Lat/Lon code.
|
|
# Equatorial_Radius and Inverse_flattening are used by the datum_shift code.
|
|
#
|
|
|
|
|
|
sub new
|
|
{
|
|
my $class = shift; # What class are we constructing?
|
|
my $self = { }; # Allocate new memory
|
|
bless $self, $class; # Mark it of the right type
|
|
$self->_init(@_); # Call _init with remaining args
|
|
return $self;
|
|
}
|
|
|
|
|
|
#
|
|
# Notice that we compute first_ecc_squared, flattening, and polar_radius
|
|
# from the other parameters.
|
|
#
|
|
sub _init
|
|
{
|
|
my $self = shift;
|
|
my $f;
|
|
my $b;
|
|
my $inverse_f;
|
|
|
|
$self->{NAME} = shift if @_; # Name of ellipsoid
|
|
$a = $self->{EQUATORIAL_RADIUS} = shift if @_; # Semi-major axis, meters
|
|
$inverse_f = $self->{INVERSE_FLATTENING} = shift if @_; # Inverse of the ellipsoid flattening 'f'
|
|
|
|
if ($inverse_f)
|
|
{
|
|
$f = 1.0 / $inverse_f;
|
|
$self->{FLATTENING} = $f; # Store the flattening value as well
|
|
$self->{FIRST_ECC_SQUARED} = (2 * $f) - ($f**2); # Compute First Eccentricity Squared from 'f'
|
|
|
|
if ($a)
|
|
{
|
|
# f = (a-b)/a
|
|
# f = a/a - b/a
|
|
# f = 1 - b/a
|
|
# b/a + f = 1
|
|
# b/a = 1 - f
|
|
# b = (1-f)a
|
|
#
|
|
$b = (1.0 - $f) * $a;
|
|
$self->{POLAR_RADIUS} = $b;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#
|
|
# Returns the version number (RCS version tag) of this module.
|
|
#
|
|
sub version
|
|
{
|
|
return $VERSION;
|
|
}
|
|
|
|
|
|
sub name
|
|
{
|
|
my $self = shift;
|
|
$self->{NAME} = shift if @_;
|
|
return $self->{NAME};
|
|
}
|
|
|
|
|
|
sub equatorial_radius
|
|
{
|
|
my $self = shift;
|
|
$self->{EQUATORIAL_RADIUS} = shift if @_;
|
|
return $self->{EQUATORIAL_RADIUS};
|
|
}
|
|
|
|
|
|
#
|
|
# Note that you can override the computed POLAR_RADIUS value
|
|
# by using this method to store a new value in the hash.
|
|
#
|
|
sub polar_radius
|
|
{
|
|
my $self = shift;
|
|
$self->{POLAR_RADIUS} = shift if @_;
|
|
return $self->{POLAR_RADIUS};
|
|
}
|
|
|
|
|
|
#
|
|
# Note that you can override the computed FIRST_ECC_SQUARED value
|
|
# by using this method to store a new value in the hash.
|
|
#
|
|
sub first_ecc_squared
|
|
{
|
|
my $self = shift;
|
|
$self->{FIRST_ECC_SQUARED} = shift if @_;
|
|
return $self->{FIRST_ECC_SQUARED};
|
|
}
|
|
|
|
|
|
#
|
|
# Note that you can override the computed FLATTENING value
|
|
# by using this method to store a new value in the hash.
|
|
#
|
|
sub flattening
|
|
{
|
|
my $self = shift;
|
|
$self->{FLATTENING} = shift if @_;
|
|
return $self->{FLATTENING};
|
|
}
|
|
|
|
|
|
sub inverse_flattening
|
|
{
|
|
my $self = shift;
|
|
$self->{INVERSE_FLATTENING} = shift if @_;
|
|
return $self->{INVERSE_FLATTENING};
|
|
}
|
|
|
|
|
|
#-----------------------------------------------------------------------------------------------
|
|
|
|
|
|
package EllipsoidTable;
|
|
|
|
|
|
$VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
|
|
|
|
|
|
#
|
|
# I could have created this table as a hash of anonymous arrays, which might have been
|
|
# faster/more efficient. Oh well.
|
|
#
|
|
# All of the methods here are class methods. There isn't even a way to make an
|
|
# EllipsoidTable object given here. This class is merely a large collection
|
|
# of Ellipsoid objects, collected in the %_ellipsoid hash.
|
|
#
|
|
|
|
|
|
my %_ellipsoid; # Class data
|
|
|
|
|
|
#
|
|
# Returns the version number (RCS version tag) of this module.
|
|
#
|
|
sub version
|
|
{
|
|
return $VERSION;
|
|
}
|
|
|
|
|
|
# Note that this method is really useless. The name is the same as the
|
|
# hash key used in the %_ellipsoid hash. Redundant.
|
|
#
|
|
sub name
|
|
{
|
|
shift; # Object reference (don't need it)
|
|
my $ellipsoid_name = shift;
|
|
|
|
return $_ellipsoid{$ellipsoid_name}->name();
|
|
}
|
|
|
|
|
|
sub equatorial_radius # (a)
|
|
{
|
|
shift; # Object reference (don't need it)
|
|
my $ellipsoid_name = shift;
|
|
|
|
return $_ellipsoid{$ellipsoid_name}->equatorial_radius();
|
|
}
|
|
|
|
|
|
sub polar_radius # (b)
|
|
{
|
|
shift; # Object reference (don't need it)
|
|
my $ellipsoid_name = shift;
|
|
|
|
return $_ellipsoid{$ellipsoid_name}->polar_radius();
|
|
}
|
|
|
|
|
|
sub first_ecc_squared # (ecc)
|
|
{
|
|
shift; # Object reference (don't need it)
|
|
my $ellipsoid_name = shift;
|
|
|
|
return $_ellipsoid{$ellipsoid_name}->first_ecc_squared();
|
|
}
|
|
|
|
|
|
sub flattening # (f)
|
|
{
|
|
shift; # Object reference (don't need it)
|
|
my $ellipsoid_name = shift;
|
|
|
|
return $_ellipsoid{$ellipsoid_name}->flattening();
|
|
}
|
|
|
|
|
|
sub inverse_flattening # (1/f)
|
|
{
|
|
shift; # Object reference (don't need it)
|
|
my $ellipsoid_name = shift;
|
|
|
|
return $_ellipsoid{$ellipsoid_name}->inverse_flattening();
|
|
}
|
|
|
|
|
|
#
|
|
# This method allows printing out each defined Ellipsoid.
|
|
#
|
|
sub enumerate
|
|
{
|
|
my $self = shift;
|
|
|
|
print "\nEllipsoid\t\tEquatorial Radius (a)\tPolar Radius (b)\tFirst Eccentricity^2\tFlattening (f)\t\t1/f\n";
|
|
print "---------\t\t---------------------\t----------------\t--------------------\t--------------\t\t---\n";
|
|
|
|
foreach my $key (sort keys %_ellipsoid)
|
|
{
|
|
printf("%23s,\t%s,\t%s,\t%s,\t%s,\t%s\n",
|
|
$key,
|
|
$self->equatorial_radius($key),
|
|
$self->polar_radius($key),
|
|
$self->first_ecc_squared($key),
|
|
$self->flattening($key),
|
|
$self->inverse_flattening($key) );
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Auto-run code
|
|
#
|
|
# Fill in the hash containing Ellipsoid objects (fill in the Class data)
|
|
#
|
|
# Name, Equatorial_Radius (a), Inverse_Flattening (1/f).
|
|
#
|
|
# Name: Reference Ellipsoid Name
|
|
# Equatorial_Radius: (a) = Semi-Major Axis (WGS-84 value = 6378137.0 meters)
|
|
# Polar_radius: (b) = Semi-Minor Axis (WGS-84 value = 6356752.3142 meters)
|
|
# Flattening: f = (a-b)/a (WGS-84 value = 0.00335281066475)
|
|
# First_Eccentricity_Squared: ecc = 2f - (f^2) (WGS-84 value = 0.00669437999013)
|
|
# Inverse_flattening: Reciprocal Flattening (1/f) (WGS-84 value = 298.257223563)
|
|
#
|
|
# We can calculate Polar_Radius (b), Flattening (f), and First_Eccentricity_Squared (ecc)
|
|
# from the values for Equatorial_Radius (a) and Inverse_flattening (1/f), so the table
|
|
# includes only the latter two parameters.
|
|
#
|
|
|
|
|
|
#print "Creating ellipsoid data\n";
|
|
# Equatorial
|
|
# Name Name Radius Inverse_flattening
|
|
$_ellipsoid{"Airy"} = Ellipsoid->new( "Airy", 6377563.396, 299.324964600 );
|
|
$_ellipsoid{"Modified Airy"} = Ellipsoid->new( "Modified Airy", 6377340.189, 299.324964600 );
|
|
$_ellipsoid{"Australian National"} = Ellipsoid->new( "Australian National", 6378160.000, 298.250000000 );
|
|
$_ellipsoid{"Bessel 1841"} = Ellipsoid->new( "Bessel 1841", 6377397.155, 299.152812800 );
|
|
$_ellipsoid{"Bessel 1841 (Namibia)"} = Ellipsoid->new( "Bessel 1841 (Namibia)", 6377483.865, 299.152812800 );
|
|
$_ellipsoid{"Clarke 1866"} = Ellipsoid->new( "Clarke 1866", 6378206.400, 294.978698200 );
|
|
$_ellipsoid{"Clarke 1880"} = Ellipsoid->new( "Clarke 1880", 6378249.145, 293.465000000 );
|
|
$_ellipsoid{"Everest (India 1830)"} = Ellipsoid->new( "Everest (India 1830)", 6377276.345, 300.801700000 );
|
|
$_ellipsoid{"Everest (Sabah Sarawak)"} = Ellipsoid->new( "Everest (Sabah Sarawak)",6377298.556, 300.801700000 );
|
|
$_ellipsoid{"Everest (India 1956)"} = Ellipsoid->new( "Everest (India 1956)", 6377301.243, 300.801700000 );
|
|
$_ellipsoid{"Everest (Malaysia 1969)"} = Ellipsoid->new( "Everest (Malaysia 1969)",6377295.664, 300.801700000 );
|
|
$_ellipsoid{"Everest (Malay. & Sing)"} = Ellipsoid->new( "Everest (Malay. & Sing)",6377304.063, 300.801700000 );
|
|
$_ellipsoid{"Everest 1948"} = Ellipsoid->new( "Everest 1948", 6377304.063, 300.801700000 );
|
|
$_ellipsoid{"Everest (Pakistan)"} = Ellipsoid->new( "Everest (Pakistan)", 6377309.613, 300.801700000 );
|
|
$_ellipsoid{"Fischer 1960 (Mercury)"} = Ellipsoid->new( "Fischer 1960 (Mercury)", 6378166.000, 298.300000000 );
|
|
$_ellipsoid{"Fischer 1968"} = Ellipsoid->new( "Fischer 1968", 6378150.000, 298.300000000 );
|
|
$_ellipsoid{"Modified Fischer 1960"} = Ellipsoid->new( "Modified Fischer 1960", 6378155.000, 298.300000000 );
|
|
$_ellipsoid{"GRS 1967"} = Ellipsoid->new( "GRS 1967", 6378160.000, 298.247167427 );
|
|
$_ellipsoid{"GRS 1980"} = Ellipsoid->new( "GRS 1980", 6378137.000, 298.257222101 );
|
|
$_ellipsoid{"Helmert 1906"} = Ellipsoid->new( "Helmert 1906", 6378200.000, 298.300000000 );
|
|
$_ellipsoid{"Hough 1960"} = Ellipsoid->new( "Hough 1960", 6378270.000, 297.000000000 );
|
|
$_ellipsoid{"Indonesian 1974"} = Ellipsoid->new( "Indonesian 1974", 6378160.000, 298.247000000 );
|
|
$_ellipsoid{"International 1924"} = Ellipsoid->new( "International 1924", 6378388.000, 297.000000000 );
|
|
$_ellipsoid{"Krassovsky 1940"} = Ellipsoid->new( "Krassovsky 1940", 6378245.000, 298.300000000 );
|
|
$_ellipsoid{"South American 1969"} = Ellipsoid->new( "South American 1969", 6378160.000, 298.250000000 );
|
|
$_ellipsoid{"WGS 60"} = Ellipsoid->new( "WGS 60", 6378165.000, 298.300000000 );
|
|
$_ellipsoid{"WGS 66"} = Ellipsoid->new( "WGS 66", 6378145.000, 298.250000000 );
|
|
$_ellipsoid{"WGS 72"} = Ellipsoid->new( "WGS 72", 6378135.000, 298.260000000 );
|
|
$_ellipsoid{"WGS 84"} = Ellipsoid->new( "WGS 84", 6378137.000, 298.257223563 );
|
|
|
|
|
|
#------------------------------------------------------------------------------------------------
|
|
|
|
|
|
package Datum;
|
|
|
|
|
|
$VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
|
|
|
|
|
|
#
|
|
# These are the objects and methods used to create the DatumTable in the next package.
|
|
#
|
|
|
|
|
|
sub new
|
|
{
|
|
my $class = shift; # What class are we constructing?
|
|
my $self = { }; # Allocate new memory
|
|
bless $self, $class; # Mark it of the right type
|
|
$self->_init(@_); # Call _init with remaining args
|
|
return $self;
|
|
}
|
|
|
|
|
|
sub _init
|
|
{
|
|
my $self = shift;
|
|
$self->{NAME} = shift if @_;
|
|
$self->{ELLIPSOID} = shift if @_;
|
|
$self->{DX} = shift if @_;
|
|
$self->{DY} = shift if @_;
|
|
$self->{DZ} = shift if @_;
|
|
}
|
|
|
|
|
|
#
|
|
# Returns the version number (RCS version tag) of this module.
|
|
#
|
|
sub version
|
|
{
|
|
return $VERSION;
|
|
}
|
|
|
|
|
|
#
|
|
# This is mostly a useless method. We store the name here, but it
|
|
# is also present as the hash key in the %_datum hash. Redundant.
|
|
#
|
|
sub name # Name of datum
|
|
{
|
|
my $self = shift;
|
|
$self->{NAME} = shift if @_;
|
|
return $self->{NAME};
|
|
}
|
|
|
|
|
|
sub ellipsoid # Name of ellipsoid used in datum
|
|
{
|
|
my $self = shift;
|
|
$self->{ELLIPSOID} = shift if @_;
|
|
return $self->{ELLIPSOID};
|
|
}
|
|
|
|
|
|
sub dx # X-offset from WGS84 ellipsoid center
|
|
{
|
|
my $self = shift;
|
|
$self->{DX} = shift if @_;
|
|
return $self->{DX};
|
|
}
|
|
|
|
|
|
sub dy # Y-offset from WGS84 ellipsoid center
|
|
{
|
|
my $self = shift;
|
|
$self->{DY} = shift if @_;
|
|
return $self->{DY};
|
|
}
|
|
|
|
|
|
sub dz # Z-offset from WGS84 ellipsoid center
|
|
{
|
|
my $self = shift;
|
|
$self->{DZ} = shift if @_;
|
|
return $self->{DZ};
|
|
}
|
|
|
|
|
|
#------------------------------------------------------------------------------------------------
|
|
|
|
|
|
package DatumTable;
|
|
|
|
|
|
$VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
|
|
|
|
|
|
#
|
|
# I could have created this table as a hash of anonymous arrays, which might have been
|
|
# faster/more efficient. Oh well.
|
|
#
|
|
# All of the methods here are class methods. There isn't even a way to make a
|
|
# DatumTable object given here. This class is merely a large collection
|
|
# of Datum objects, collected in the %_datum hash.
|
|
#
|
|
|
|
my %_datum; # Class data
|
|
|
|
|
|
#
|
|
# Returns the version number (RCS version tag) of this module.
|
|
#
|
|
sub version
|
|
{
|
|
return $VERSION;
|
|
}
|
|
|
|
|
|
sub name # Name of datum
|
|
{
|
|
shift; # Object reference (don't need it)
|
|
my $datum_name = shift;
|
|
|
|
return $_datum{$datum_name}->name();
|
|
}
|
|
|
|
|
|
sub ellipsoid # Name of ellipsoid used in datum
|
|
{
|
|
shift; # Object reference (don't need it)
|
|
my $datum_name = shift;
|
|
|
|
return $_datum{$datum_name}->ellipsoid();
|
|
}
|
|
|
|
|
|
sub dx # X-offset from WGS84 ellipsoid center
|
|
{
|
|
shift; # Object reference (don't need it)
|
|
my $datum_name = shift;
|
|
|
|
return $_datum{$datum_name}->dx();
|
|
}
|
|
|
|
|
|
sub dy # Y-offset from WGS84 ellipsoid center
|
|
{
|
|
shift; # Object reference (don't need it)
|
|
my $datum_name = shift;
|
|
|
|
return $_datum{$datum_name}->dy();
|
|
}
|
|
|
|
|
|
sub dz # Z-offset from WGS84 ellipsoid center
|
|
{
|
|
shift; # Object reference (don't need it)
|
|
my $datum_name = shift;
|
|
|
|
return $_datum{$datum_name}->dz();
|
|
}
|
|
|
|
|
|
#
|
|
# This method allows printing out each defined Datum.
|
|
#
|
|
sub enumerate
|
|
{
|
|
my $self = shift;
|
|
|
|
print "\nDatum\t\t\t\t\t\t\t\tEllipsoid\tDx\tDy\tDz\n";
|
|
print "-----\t\t\t\t\t\t\t\t---------\t--\t--\t--\n";
|
|
|
|
foreach my $key (sort keys %_datum)
|
|
{
|
|
printf("%s\n\t\t\t\t\t\t%23s,\t%s,\t%s,\t%s\n",
|
|
$key,
|
|
$self->ellipsoid($key),
|
|
$self->dx($key),
|
|
$self->dy($key),
|
|
$self->dz($key) );
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Auto-run code
|
|
#
|
|
# Fill in the Class data.
|
|
#
|
|
# This code fills in the %_datum hash which has entries consisting of Datum objects.
|
|
#
|
|
# From the original C code:
|
|
#
|
|
# "Dx, Dy, Dz: ellipsoid center with respect to WGS 84 ellipsoid center
|
|
# x axis is the prime meridian
|
|
# y axis is 90 degrees east longitude
|
|
# z axis is the axis of rotation of the ellipsoid"
|
|
#
|
|
# Most of the current data is from Peter Dana's website.
|
|
# This increased the number of datums to around 231. -- Curt.
|
|
#
|
|
#
|
|
# NOTE: Consider adding a field for "region of use".
|
|
#
|
|
#
|
|
# Name Name Ellipsoid Dx Dy Dz
|
|
$_datum{"Adindan (Burkina Faso)"}
|
|
= Datum->new( "Adindan (Burkina Faso)",
|
|
"Clarke 1880", -118, -14, 218 );
|
|
|
|
$_datum{"Adindan (Cameroon)"}
|
|
= Datum->new( "Adindan (Cameroon)",
|
|
"Clarke 1880", -134, -2, 210 );
|
|
|
|
$_datum{"Adindan (Ethiopia)"}
|
|
= Datum->new( "Adindan (Ethiopia)",
|
|
"Clarke 1880", -165, -11, 206 );
|
|
|
|
$_datum{"Adindan (Mali)"}
|
|
= Datum->new( "Adindan (Mali)",
|
|
"Clarke 1880", -123, -20, 220 );
|
|
|
|
$_datum{"Adindan (MEAN for Ethiopia/Sudan)"}
|
|
= Datum->new( "Adindan (MEAN for Ethiopia/Sudan)",
|
|
"Clarke 1880", -166, -15, 204 );
|
|
|
|
$_datum{"Adindan (Senegal)"}
|
|
= Datum->new( "Adindan (Senegal)",
|
|
"Clarke 1880", -128, -18, 224 );
|
|
|
|
$_datum{"Adindan (Sudan)"}
|
|
= Datum->new( "Adindan (Sudan)",
|
|
"Clarke 1880", -161, -14, 205 );
|
|
|
|
$_datum{"Afgooye"}
|
|
= Datum->new( "Afgooye",
|
|
"Krassovsky 1940", -43, -163, 45 );
|
|
|
|
$_datum{"Ain el Abd 1970 (Bahrain)"}
|
|
= Datum->new( "Ain el Abd 1970 (Bahrain)",
|
|
"International 1924", -150, -250, -1 );
|
|
|
|
$_datum{"Ain el Abd 1970 (Saudi Arabia)"}
|
|
= Datum->new( "Ain el Abd 1970 (Saudi Arabia)",
|
|
"International 1924", -143, -236, 7 );
|
|
|
|
$_datum{"American Samoa 1962"}
|
|
= Datum->new( "American Samoa 1962",
|
|
"Clarke 1866", -115, 118, 426 );
|
|
|
|
$_datum{"Anna 1 Astro 1965"}
|
|
= Datum->new( "Anna 1 Astro 1965",
|
|
"Australian National", -491, -22, 435 );
|
|
|
|
$_datum{"Antigua Island Astro 1943"}
|
|
= Datum->new( "Antigua Island Astro 1943",
|
|
"Clarke 1880", -270, 13, 62 );
|
|
|
|
$_datum{"Arc 1950 (Botswana)"}
|
|
= Datum->new( "Arc 1950 (Botswana)",
|
|
"Clarke 1880", -138, -105, -289 );
|
|
|
|
$_datum{"Arc 1950 (Burundi)"}
|
|
= Datum->new( "Arc 1950 (Burundi)",
|
|
"Clarke 1880", -153, -5, -292 );
|
|
|
|
$_datum{"Arc 1950 (Lesotho)"}
|
|
= Datum->new( "Arc 1950 (Lesotho)",
|
|
"Clarke 1880", -125, -108, -295 );
|
|
|
|
$_datum{"Arc 1950 (Malawi)"}
|
|
= Datum->new( "Arc 1950 (Malawi)",
|
|
"Clarke 1880", -161, -73, -317 );
|
|
|
|
$_datum{"Arc 1950 (MEAN)"}
|
|
= Datum->new( "Arc 1950 (MEAN)",
|
|
"Clarke 1880", -143, -90, -294 );
|
|
|
|
$_datum{"Arc 1950 (Swaziland)"}
|
|
= Datum->new( "Arc 1950",
|
|
"Clarke 1880", -134, -105, -295 );
|
|
|
|
$_datum{"Arc 1950 (Zaire)"}
|
|
= Datum->new( "Arc 1950",
|
|
"Clarke 1880", -169, -19, -278 );
|
|
|
|
$_datum{"Arc 1950 (Zambia)"}
|
|
= Datum->new( "Arc 1950",
|
|
"Clarke 1880", -147, -74, -283 );
|
|
|
|
$_datum{"Arc 1950 (Zimbabwe)"}
|
|
= Datum->new( "Arc 1950",
|
|
"Clarke 1880", -142, -96, -293 );
|
|
|
|
$_datum{"Arc 1960 (MEAN)"}
|
|
= Datum->new( "Arc 1960 (MEAN)",
|
|
"Clarke 1880", -160, -6, -302 );
|
|
|
|
$_datum{"Arc 1960 (Kenya)"}
|
|
= Datum->new( "Arc 1960 (Kenya)",
|
|
"Clarke 1880", -157, -2, -299 );
|
|
|
|
$_datum{"Arc 1960 (Tanzania)"}
|
|
= Datum->new( "Arc 1960 (Tanzania)",
|
|
"Clarke 1880", -175, -23, -303 );
|
|
|
|
$_datum{"Ascension Island 1958"}
|
|
= Datum->new( "Ascension Island 1958",
|
|
"International 1924", -205, 107, 53 );
|
|
|
|
$_datum{"Astro B4 Sorol Atoll"}
|
|
= Datum->new( "Astro B4 Sorol Atoll",
|
|
"International 1924", 114, -116, -333 );
|
|
|
|
$_datum{"Astro Beacon E 1945"}
|
|
= Datum->new( "Astro Beacon E 1945",
|
|
"International 1924", 145, 75, -272 );
|
|
|
|
$_datum{"Astro DOS 71/4"}
|
|
= Datum->new( "Astro DOS 71/4",
|
|
"International 1924", -320, 550, -494 );
|
|
|
|
$_datum{"Astro Tern Island (FRIG) 1961"}
|
|
= Datum->new( "Astro Tern Island (FRIG) 1961",
|
|
"International 1924", 114, -116, -333 );
|
|
|
|
$_datum{"Astronomical Station 1952"}
|
|
= Datum->new( "Astronomical Station 1952",
|
|
"International 1924", 124, -234, -25 );
|
|
|
|
$_datum{"Australian Geodetic 1966"}
|
|
= Datum->new( "Australian Geodetic 1966",
|
|
"Australian National", -133, -48, 148 );
|
|
|
|
$_datum{"Australian Geodetic 1984"}
|
|
= Datum->new( "Australian Geodetic 1984",
|
|
"Australian National", -134, -48, 149 );
|
|
|
|
$_datum{"Ayabelle Lighthouse"}
|
|
= Datum->new( "Ayabelle Lighthouse",
|
|
"Clarke 1880", -79, -129, 145 );
|
|
|
|
$_datum{"Bellevue (IGN)"}
|
|
= Datum->new( "Bellevue (IGN)",
|
|
"International 1924", -127, -769, 472 );
|
|
|
|
$_datum{"Bermuda 1957"}
|
|
= Datum->new( "Bermuda 1957",
|
|
"Clarke 1866", -73, 213, 296 );
|
|
|
|
$_datum{"Bogota Observatory"}
|
|
= Datum->new( "Bogota Observatory",
|
|
"International 1924", 307, 304, -318 );
|
|
|
|
$_datum{"Bukit Rimpah"}
|
|
= Datum->new( "Bukit Rimpah",
|
|
"Bessel 1841", -384, 664, -48 );
|
|
|
|
$_datum{"Camp Area Astro"}
|
|
= Datum->new( "Camp Area Astro",
|
|
"International 1924", -104, -129, 239 );
|
|
|
|
$_datum{"Campo Inchauspe"}
|
|
= Datum->new( "Campo Inchauspe",
|
|
"International 1924", -148, 136, 90 );
|
|
|
|
$_datum{"Canton Astro 1966"}
|
|
= Datum->new( "Canton Astro 1966",
|
|
"International 1924", 298, -304, -375 );
|
|
|
|
$_datum{"Cape"}
|
|
= Datum->new( "Cape",
|
|
"Clarke 1880", -136, -108, -292 );
|
|
|
|
$_datum{"Cape Canaveral"}
|
|
= Datum->new( "Cape Canaveral",
|
|
"Clarke 1866", -2, 151, 181 );
|
|
|
|
$_datum{"Carthage"}
|
|
= Datum->new( "Carthage",
|
|
"Clarke 1880", -263, 6, 431 );
|
|
|
|
$_datum{"CH-1903"}
|
|
= Datum->new( "CH-1903",
|
|
"Bessel 1841", 674, 15, 405);
|
|
|
|
$_datum{"Chatham Island Astro 1971"}
|
|
= Datum->new( "Chatham Island Astro 1971",
|
|
"International 1924", 175, -38, 113);
|
|
|
|
$_datum{"Chua Astro"}
|
|
= Datum->new( "Chua Astro",
|
|
"International 1924", -134, 229, -29 );
|
|
|
|
$_datum{"Corrego Alegre"}
|
|
= Datum->new( "Corrego Alegre",
|
|
"International 1924", -206, 172, -6 );
|
|
|
|
$_datum{"Dabola"}
|
|
= Datum->new( "Dabola",
|
|
"Clarke 1880", -83, 37, 124 );
|
|
|
|
$_datum{"Deception Island"}
|
|
= Datum->new( "Deception Island",
|
|
"Clarke 1880", 260, 12, -147 );
|
|
|
|
$_datum{"Djakarta (Batavia)"}
|
|
= Datum->new( "Djakarta (Batavia)",
|
|
"Bessel 1841", -377, 681, -50 );
|
|
|
|
$_datum{"DOS 1968"}
|
|
= Datum->new( "DOS 1968",
|
|
"International 1924", 230, -199, -752 );
|
|
|
|
$_datum{"Easter Island 1967"}
|
|
= Datum->new( "Easter Island 1967",
|
|
"International 1924", 211, 147, 111 );
|
|
|
|
$_datum{"Estonia 1937"}
|
|
= Datum->new( "Estonia 1937",
|
|
"Bessel 1841", 374, 150, 588 );
|
|
|
|
$_datum{"European 1950 (Cyprus)"}
|
|
= Datum->new( "European 1950 (Cyprus)",
|
|
"International 1924", -104, -101, -140 );
|
|
|
|
$_datum{"European 1950 (Egypt)"}
|
|
= Datum->new( "European 1950 (Egypt)",
|
|
"International 1924", -130, -117, -151 );
|
|
|
|
$_datum{"European 1950 (England/Channel Is/Scotland/Shetland Is)"}
|
|
= Datum->new( "European 1950 (England/Channel Is/Scotland/Shetland Is)",
|
|
"International 1924", -86, -96, -120 );
|
|
|
|
$_datum{"European 1950 (England/Ireland/Scotland/Shetland Is)"}
|
|
= Datum->new( "European 1950 (England/Ireland/Scotland/Shetland Is)",
|
|
"International 1924", -86, -96, -120 );
|
|
|
|
$_datum{"European 1950 (Finland/Norway)"}
|
|
= Datum->new( "European 1950 (Finland/Norway)",
|
|
"International 1924", -87, -95, -120 );
|
|
|
|
$_datum{"European 1950 (Greece)"}
|
|
= Datum->new( "European 1950 (Greece)",
|
|
"International 1924", -84, -95, -130 );
|
|
|
|
$_datum{"European 1950 (Iran)"}
|
|
= Datum->new( "European 1950 (Iran)",
|
|
"International 1924", -117, -132, -164 );
|
|
|
|
$_datum{"European 1950 (Italy:Sardinia)"}
|
|
= Datum->new( "European 1950 (Italy:Sardinia)",
|
|
"International 1924", -97, -103, -120 );
|
|
|
|
$_datum{"European 1950 (Italy:Sicily)"}
|
|
= Datum->new( "European 1950 (Italy:Sicily)",
|
|
"International 1924", -97, -88, -135 );
|
|
|
|
$_datum{"European 1950 (Malta)"}
|
|
= Datum->new( "European 1950 (Malta)",
|
|
"International 1924", -107, -88, -149 );
|
|
|
|
$_datum{"European 1950 (MEAN for Austria/Belgium/Denmark/Finland/France/W Germany/Gibraltar/Greece/Italy/Luxembourg/Netherlands/Norway/Portugal/Spain/Sweden/Switzerland)"}
|
|
= Datum->new( "European 1950 (MEAN for Austria/Belgium/Denmark/Finland/France/W Germany/Gibraltar/Greece/Italy/Luxembourg/Netherlands/Norway/Portugal/Spain/Sweden/Switzerland)",
|
|
"International 1924", -87, -98, -121 );
|
|
|
|
$_datum{"European 1950 (MEAN for Austria/Denmark/France/W Germany/Netherlands/Switzerland)"}
|
|
= Datum->new( "European 1950 (MEAN for Austria/Denmark/France/W Germany/Netherlands/Switzerland)",
|
|
"International 1924", -87, -96, -120 );
|
|
|
|
$_datum{"European 1950 (MEAN for Iraq/Israel/Jordan/Lebanon/Kuwait/Saudi Arabia/Syria)"}
|
|
= Datum->new( "European 1950 (MEAN for Iraq/Israel/Jordan/Lebanon/Kuwait/Saudi Arabia/Syria)",
|
|
"International 1924", -103, -106, -141 );
|
|
|
|
$_datum{"European 1950 (Portugal/Spain)"}
|
|
= Datum->new( "European 1950 (Portugal/Spain)",
|
|
"International 1924", -84, -107, -120 );
|
|
|
|
$_datum{"European 1950 (Tunisia)"}
|
|
= Datum->new( "European 1950 (Tunisia)",
|
|
"International 1924", -112, -77, -145 );
|
|
|
|
$_datum{"European 1979 (MEAN for Austria/Finland/Netherlands/Norway/Spain/Sweden/Switzerland)"}
|
|
= Datum->new( "European 1979 (MEAN for Austria/Finland/Netherlands/Norway/Spain/Sweden/Switzerland)",
|
|
"International 1924", -86, -98, -119 );
|
|
|
|
$_datum{"Finland Hayford"}
|
|
= Datum->new( "Finland Hayford",
|
|
"International 1924", -78, -231, -97 );
|
|
|
|
$_datum{"Fort Thomas"}
|
|
= Datum->new( "Fort Thomas",
|
|
"Clarke 1880", -7, 215, 225 );
|
|
|
|
$_datum{"Gandajika Base 1970"}
|
|
= Datum->new( "Gandajika Base 1970",
|
|
"International 1924", -133, -321, 50 );
|
|
|
|
$_datum{"Geodetic Datum 1949"}
|
|
= Datum->new( "Geodetic Datum 1949",
|
|
"International 1924", 84, -22, 209 );
|
|
|
|
$_datum{"Graciosa Base SW 1948"}
|
|
= Datum->new( "Graciosa Base SW 1948",
|
|
"International 1924", -104, 167, -38 );
|
|
|
|
$_datum{"Guam 1963"}
|
|
= Datum->new( "Guam 1963",
|
|
"Clarke 1866", -100, -248, 259 );
|
|
|
|
$_datum{"Gunung Segara"}
|
|
= Datum->new( "Gunung Segara",
|
|
"Bessel 1841", -403, 684, 41 );
|
|
|
|
$_datum{"GUX 1 Astro"}
|
|
= Datum->new( "GUX 1 Astro",
|
|
"International 1924", 252, -209, -751 );
|
|
|
|
$_datum{"Herat North"}
|
|
= Datum->new( "Herat North",
|
|
"International 1924", -333, -222, 114 );
|
|
|
|
$_datum{"Hermannskogel Datum (Namibia)"}
|
|
= Datum->new( "Hermannskogel Datum (Namibia)",
|
|
"Bessel 1841", 653, -212, 449 );
|
|
|
|
$_datum{"Hjorsey 1955"}
|
|
= Datum->new( "Hjorsey 1955",
|
|
"International 1924", -73, 46, -86 );
|
|
|
|
$_datum{"Hong Kong 1963"}
|
|
= Datum->new( "Hong Kong 1963",
|
|
"International 1924", -156, -271, -189 );
|
|
|
|
$_datum{"Hu-Tzu-Shan"}
|
|
= Datum->new( "Hu-Tzu-Shan",
|
|
"International 1924", -637, -549, -203 );
|
|
|
|
$_datum{"Indian (Bangladesh)"}
|
|
= Datum->new( "Indian (Bangladesh)",
|
|
"Everest (India 1830)", 282, 726, 254 );
|
|
|
|
$_datum{"Indian (India/Nepal)"}
|
|
= Datum->new( "Indian (India/Nepal)",
|
|
"Everest (India 1956)", 295, 736, 257 );
|
|
|
|
$_datum{"Indian (Pakistan)"}
|
|
= Datum->new( "Indian (Pakistan)",
|
|
"Everest (Pakistan)", 283, 682, 231 );
|
|
|
|
$_datum{"Indian 1954 (Thailand)"}
|
|
= Datum->new( "Indian 1954 (Thailand)",
|
|
"Everest (India 1830)", 217, 823, 299 );
|
|
|
|
$_datum{"Indian 1960 (Vietnam:Con Son Is)"}
|
|
= Datum->new( "Indian 1960 (Vietnam:Con Son Is)",
|
|
"Everest (India 1830)", 182, 915, 344 );
|
|
|
|
$_datum{"Indian 1960 (Vietnam:Near 160N)"}
|
|
= Datum->new( "Indian 1960 (Vietnam:Near 160N)",
|
|
"Everest (India 1830)", 198, 881, 317 );
|
|
|
|
$_datum{"Indian 1975 (Thailand)"}
|
|
= Datum->new( "Indian 1975 (Thailand)",
|
|
"Everest (India 1830)", 210, 814, 289 );
|
|
|
|
$_datum{"Indonesian 1974"}
|
|
= Datum->new( "Indonesian 1974)",
|
|
"Indonesian 1974)", -24, -15, 5 );
|
|
|
|
$_datum{"Ireland 1965"}
|
|
= Datum->new( "Ireland 1965",
|
|
"Modified Airy", 506, -122, 611 );
|
|
|
|
$_datum{"ISTS 061 Astro 1968"}
|
|
= Datum->new( "ISTS 061 Astro 1968",
|
|
"International 1924", -794, 119, -298 );
|
|
|
|
$_datum{"ISTS 073 Astro 1969"}
|
|
= Datum->new( "ISTS 073 Astro 1969",
|
|
"International 1924", 208, -435, -229 );
|
|
|
|
$_datum{"Johnston Island"}
|
|
= Datum->new( "Johnston Island",
|
|
"International 1924", 189, -79, -202 );
|
|
|
|
$_datum{"Kandawala"}
|
|
= Datum->new( "Kandawala",
|
|
"Everest (India 1830)", -97, 787, 86 );
|
|
|
|
$_datum{"Kerguelen Island 1949"}
|
|
= Datum->new( "Kerguelen Island 1949",
|
|
"International 1924", 145, -187, 103 );
|
|
|
|
$_datum{"Kertau 1948"}
|
|
= Datum->new( "Kertau 1948",
|
|
"Everest (Malay. & Sing)", -11, 851, 5 );
|
|
|
|
$_datum{"Kusaie Astro 1951"}
|
|
= Datum->new( "Kusaie Astro 1951",
|
|
"International 1924", 647, 1777, -1124 );
|
|
|
|
$_datum{"Korean Geodetic System"}
|
|
= Datum->new( "Korean Geodetic System",
|
|
"GRS 1980", 0, 0, 0 );
|
|
|
|
$_datum{"L. C. 5 Astro 1961"}
|
|
= Datum->new( "L. C. 5 Astro 1961",
|
|
"Clarke 1866", 42, 124, 147 );
|
|
|
|
$_datum{"Leigon"}
|
|
= Datum->new( "Leigon",
|
|
"Clarke 1880", -130, 29, 364 );
|
|
|
|
$_datum{"Liberia 1964"}
|
|
= Datum->new( "Liberia 1964",
|
|
"Clarke 1880", -90, 40, 88 );
|
|
|
|
$_datum{"Luzon (Philippines:Except Mindanao)"}
|
|
= Datum->new( "Luzon (Philippines:Except Mindanao)",
|
|
"Clarke 1866", -133, -77, -51 );
|
|
|
|
$_datum{"Luzon (Philippines:Mindanao)"}
|
|
= Datum->new( "Luzon (Philippines:Mindanao)",
|
|
"Clarke 1866", -133, -79, -72 );
|
|
|
|
$_datum{"M\'Poraloko"}
|
|
= Datum->new( "M\'Poraloko",
|
|
"Clarke 1880", -74, -130, 42 );
|
|
|
|
$_datum{"Mahe 1971"}
|
|
= Datum->new( "Mahe 1971",
|
|
"Clarke 1880", 41, -220, -134 );
|
|
|
|
$_datum{"Marco Astro"}
|
|
= Datum->new( "Marco Astro",
|
|
"International 1924", -289, -124, 60 );
|
|
|
|
$_datum{"Massawa"}
|
|
= Datum->new( "Massawa",
|
|
"Bessel 1841", 639, 405, 60 );
|
|
|
|
$_datum{"Merchich"}
|
|
= Datum->new( "Merchich",
|
|
"Clarke 1880", 31, 146, 47 );
|
|
|
|
$_datum{"Midway Astro 1961"}
|
|
= Datum->new( "Midway Astro 1961",
|
|
"International 1924", 912, -58, 1227 );
|
|
|
|
$_datum{"Minna (Cameroon)"}
|
|
= Datum->new( "Minna (Cameroon)",
|
|
"Clarke 1880", -81, -84, 115 );
|
|
|
|
$_datum{"Minna (Nigeria)"}
|
|
= Datum->new( "Minna (Nigeria)",
|
|
"Clarke 1880", -92, -93, 122 );
|
|
|
|
$_datum{"Montserrat Island Astro 1958"}
|
|
= Datum->new( "Montserrat Island Astro 1958",
|
|
"Clarke 1880", 174, 359, 365 );
|
|
|
|
$_datum{"Nahrwan (Oman:Masirah Is)"}
|
|
= Datum->new( "Nahrwan (Oman:Masirah Is)",
|
|
"Clarke 1880", -247, -148, 369 );
|
|
|
|
$_datum{"Nahrwan (Saudi Arabia)"}
|
|
= Datum->new( "Nahrwan (Saudi Arabia)",
|
|
"Clarke 1880", -243, -192, 477 );
|
|
|
|
$_datum{"Nahrwan (United Arab Emirates)"}
|
|
= Datum->new( "Nahrwan (United Arab Emirates)",
|
|
"Clarke 1880", -249, -156, 381 );
|
|
|
|
$_datum{"Naparima BWI"}
|
|
= Datum->new( "Naparima BWI",
|
|
"International 1924", -10, 375, 165 );
|
|
|
|
$_datum{"NAD27 Alaska:Except Aleutian Is"}
|
|
= Datum->new( "NAD27 Alaska:Except Aleutian Is",
|
|
"Clarke 1866", -5, 135, 172 );
|
|
|
|
$_datum{"NAD27 Alaska:Aleutian Is E of 180W"}
|
|
= Datum->new( "NAD27 Alaska:Aleutian Is E of 180W",
|
|
"Clarke 1866", -2, 152, 149 );
|
|
|
|
$_datum{"NAD27 Alaska:Aleutian Is W of 180W"}
|
|
= Datum->new( "NAD27 Alaska:Aleutian Is W of 180W",
|
|
"Clarke 1866", 2, 204, 105 );
|
|
|
|
$_datum{"NAD27 Bahamas:Except San Salvador Is"}
|
|
= Datum->new( "NAD27 Bahamas:Except San Salvador Is",
|
|
"Clarke 1866", -4, 154, 178 );
|
|
|
|
$_datum{"NAD27 Bahamas:San Salvador Is"}
|
|
= Datum->new( "NAD27 Bahamas:San Salvador Is",
|
|
"Clarke 1866", 1, 140, 165 );
|
|
|
|
$_datum{"NAD27 Canada (Alberta/B.C.)"}
|
|
= Datum->new( "NAD27 Canada (Alberta/B.C.)",
|
|
"Clarke 1866", -7, 162, 188 );
|
|
|
|
$_datum{"NAD27 Canada (Manitoba/Ontario)"}
|
|
= Datum->new( "NAD27 Canada (Manitoba/Ontario)",
|
|
"Clarke 1866", -9, 157, 184 );
|
|
|
|
$_datum{"NAD27 Canada MEAN"}
|
|
= Datum->new( "NAD27 Canada MEAN",
|
|
"Clarke 1866", -10, 158, 189 );
|
|
|
|
$_datum{"NAD27 Canada (New Brunswick/Newfoundland/Nova Scotia/Quebec)"}
|
|
= Datum->new( "NAD27 Canada (New Brunswick/Newfoundland/Nova Scotia/Quebec)",
|
|
"Clarke 1866", -22, 160, 190 );
|
|
|
|
$_datum{"NAD27 Canada (Northwest Territories/Saskatchewan)"}
|
|
= Datum->new( "NAD27 Canada (Northwest Territories/Saskatchewan)",
|
|
"Clarke 1866", 4, 159, 188 );
|
|
|
|
$_datum{"NAD27 Canada (Yukon)"}
|
|
= Datum->new( "NAD27 Canada (Yukon)",
|
|
"Clarke 1866", -7, 139, 181 );
|
|
|
|
$_datum{"NAD27 Canal Zone"}
|
|
= Datum->new( "NAD27 Canal Zone",
|
|
"Clarke 1866", 0, 125, 201 );
|
|
|
|
$_datum{"NAD27 Caribbean"}
|
|
= Datum->new( "NAD27 Caribbean",
|
|
"Clarke 1866", -7, 152, 178 );
|
|
|
|
$_datum{"NAD27 MEAN:Antigua/Barbados/Barbuda/Caicos Islands/Cuba/Dominican Republic/Grand Cayman/Jamaica/Turks Islands"}
|
|
= Datum->new( "NAD27 MEAN:Antigua/Barbados/Barbuda/Caicos Islands/Cuba/Dominican Republic/Grand Cayman/Jamaica/Turks Islands",
|
|
"Clarke 1866", -3, 142, 183 );
|
|
|
|
$_datum{"NAD27 MEAN:Belize/Costa Rica/El Salvador/Guatemala/Honduras/Nicaragua"}
|
|
= Datum->new( "NAD27 MEAN:Belize/Costa Rica/El Salvador/Guatemala/Honduras/Nicaragua",
|
|
"Clarke 1866", 0, 125, 194 );
|
|
|
|
$_datum{"NAD27 CONUS MEAN"}
|
|
= Datum->new( "NAD27 CONUS MEAN",
|
|
"Clarke 1866", -8, 160, 176 );
|
|
|
|
# Added for compatibility reasons. Same as above.
|
|
$_datum{"NAD27 CONUS"}
|
|
= Datum->new( "NAD27 CONUS",
|
|
"Clarke 1866", -8, 160, 176 );
|
|
|
|
$_datum{"NAD27 CONUS MEAN:E of Mississippi/Louisiana/Missouri/Minnesota"}
|
|
= Datum->new( "NAD27 CONUS MEAN:E of Mississippi/Louisiana/Missouri/Minnesota",
|
|
"Clarke 1866", -9, 161, 179 );
|
|
|
|
$_datum{"NAD27 CONUS MEAN:W of Mississippi/Except Louisiana/Minnesota/Missouri"}
|
|
= Datum->new( "NAD27 CONUS W of Mississippi/Except Louisiana/Minnesota/Missouri",
|
|
"Clarke 1866", -8, 159, 175 );
|
|
|
|
$_datum{"NAD27 Cuba"}
|
|
= Datum->new( "NAD27 Cuba",
|
|
"Clarke 1866", -9, 152, 178 );
|
|
|
|
$_datum{"NAD27 Greenland (Hayes Peninsula)"}
|
|
= Datum->new( "NAD27 Greenland (Hayes Peninsula)",
|
|
"Clarke 1866", 11, 114, 195 );
|
|
|
|
$_datum{"NAD27 Mexico"}
|
|
= Datum->new( "NAD27 Mexico",
|
|
"Clarke 1866", -12, 130, 190 );
|
|
|
|
$_datum{"NAD27 San Salvador"}
|
|
= Datum->new( "NAD27 San Salvador",
|
|
"Clarke 1866", 1, 140, 165 );
|
|
|
|
$_datum{"NAD83 Alaska (Except Aleutian Is)"}
|
|
= Datum->new( "NAD83 Alaska (Except Aleutian Is)",
|
|
"GRS 1980", 0, 0, 0 );
|
|
|
|
$_datum{"NAD83 Aleutian Is"}
|
|
= Datum->new( "NAD83 Aleutian Is",
|
|
"GRS 1980", -2, 0, 4 );
|
|
|
|
$_datum{"NAD83 Canada"}
|
|
= Datum->new( "NAD83 Canada",
|
|
"GRS 1980", 0, 0, 0 );
|
|
|
|
$_datum{"NAD83 CONUS"}
|
|
= Datum->new( "NAD83 CONUS",
|
|
"GRS 1980", 0, 0, 0 );
|
|
|
|
$_datum{"NAD83 Hawaii"}
|
|
= Datum->new( "NAD83 Hawaii",
|
|
"GRS 1980", 1, 1, -1 );
|
|
|
|
$_datum{"NAD83 Mexico/Central America"}
|
|
= Datum->new( "NAD83 Mexico/Central America",
|
|
"GRS 1980", 0, 0, 0 );
|
|
|
|
$_datum{"North Sahara"}
|
|
= Datum->new( "North Sahara",
|
|
"Clarke 1880", -186, -93, 310 );
|
|
|
|
$_datum{"Nahrwn Masirah Ilnd"}
|
|
= Datum->new( "Nahrwn Masirah Ilnd",
|
|
"Clarke 1880", -247, -148, 369 );
|
|
|
|
$_datum{"Nahrwn Saudi Arbia"}
|
|
= Datum->new( "Nahrwn Saudi Arbia",
|
|
"Clarke 1880", -231, -196, 482 );
|
|
|
|
$_datum{"Nahrwn United Arab"}
|
|
= Datum->new( "Nahrwn United Arab",
|
|
"Clarke 1880", -249, -156, 381 );
|
|
|
|
$_datum{"Naparima BWI"}
|
|
= Datum->new( "Naparima BWI",
|
|
"International 1924", -2, 374, 172 );
|
|
|
|
$_datum{"Observatorio Meteorologico 1939"}
|
|
= Datum->new( "Observatorio Meteorologico 1939",
|
|
"International 1924", -425, -169, 81 );
|
|
|
|
$_datum{"Old Egyptian 1907"}
|
|
= Datum->new( "Old Egyptian 1907",
|
|
"Helmert 1906", -130, 110, -13 );
|
|
|
|
$_datum{"Old Hawaiian Hawaii"}
|
|
= Datum->new( "Old Hawaiian Hawaii",
|
|
"Clarke 1866", 89, -279, -183 );
|
|
|
|
$_datum{"Old Hawaiian Kauai"}
|
|
= Datum->new( "Old Hawaiian Kauai",
|
|
"Clarke 1866", 45, -290, -172 );
|
|
|
|
$_datum{"Old Hawaiian Maui"}
|
|
= Datum->new( "Old Hawaiian Maui",
|
|
"Clarke 1866", 65, -290, -190 );
|
|
|
|
$_datum{"Old Hawaiian MEAN"}
|
|
= Datum->new( "Old Hawaiian MEAN",
|
|
"Clarke 1866", 61, -285, -181 );
|
|
|
|
$_datum{"Old Hawaiian Oahu"}
|
|
= Datum->new( "Old Hawaiian Oahu",
|
|
"Clarke 1866", 58, -283, -182 );
|
|
|
|
$_datum{"Oman"}
|
|
= Datum->new( "Oman",
|
|
"Clarke 1880", -346, -1, 224 );
|
|
|
|
$_datum{"Ordnance Survey Great Britain 1936 England"}
|
|
= Datum->new( "Ordnance Survey Great Britain 1936 England",
|
|
"Airy 1830", 371, -112, 434 );
|
|
|
|
$_datum{"Ordnance Survey Great Britain 1936 England/Isle of Man/Wales"}
|
|
= Datum->new( "Ordnance Survey Great Britain 1936 England/Isle of Man/Wales",
|
|
"Airy 1830", 371, -111, 434 );
|
|
|
|
$_datum{"Ordnance Survey Great Britain 1936 MEAN:England/Isle of Man/Scotland/Shetland Is/Wales"}
|
|
= Datum->new( "Ordnance Survey Great Britain 1936 MEAN:England/Isle of Man/Scotland/Shetland Is/Wales",
|
|
"Airy 1830", 375, -111, 431 );
|
|
|
|
$_datum{"Ordnance Survey Great Britain 1936 Scotland/Shetland Is"}
|
|
= Datum->new( "Ordnance Survey Great Britain 1936 Scotland/Shetland Is",
|
|
"Airy 1830", 384, -111, 425 );
|
|
|
|
$_datum{"Ordnance Survey Great Britain 1936 Wales"}
|
|
= Datum->new( "Ordnance Survey Great Britain 1936 Wales",
|
|
"Airy 1830", 370, -108, 434 );
|
|
|
|
$_datum{"Pico De Las Nieves"}
|
|
= Datum->new( "Pico De Las Nieves",
|
|
"International 1924", -307, -92, 127 );
|
|
|
|
$_datum{"Pitcairn Astro 1967"}
|
|
= Datum->new( "Pitcairn Astro 1967",
|
|
"International 1924", 185, 165, 42 );
|
|
|
|
$_datum{"Point 58"}
|
|
= Datum->new( "Point 58",
|
|
"Clarke 1880", -106, -129, 165 );
|
|
|
|
$_datum{"Pointe Noire 1948"}
|
|
= Datum->new( "Pointe Noire 1948",
|
|
"Clarke 1880", -148, 51, -291 );
|
|
|
|
$_datum{"Porto Santo 1936"}
|
|
= Datum->new( "Porto Santo 1936",
|
|
"International 1924", -499, -249, 314 );
|
|
|
|
$_datum{"Provisional South American 1956 Bolivia"}
|
|
= Datum->new( "Provisional South American 1956 Bolivia",
|
|
"International 1924", -270, 188, -388 );
|
|
|
|
$_datum{"Provisional South American 1956 Chile Northern/Near 19S"}
|
|
= Datum->new( "Provisional South American 1956 Chile Northern/Near 19S",
|
|
"International 1924", -270, 183, -390 );
|
|
|
|
$_datum{"Provisional South American 1956 Chile Southern/Near 43S"}
|
|
= Datum->new( "Provisional South American 1956 Chile Southern/Near 43S",
|
|
"International 1924", -305, 243, -442 );
|
|
|
|
$_datum{"Provisional South American 1956 Columbia"}
|
|
= Datum->new( "Provisional South American 1956 Columbia",
|
|
"International 1924", -282, 169, -371 );
|
|
|
|
$_datum{"Provisional South American 1956 Ecuador"}
|
|
= Datum->new( "Provisional South American 1956 Ecuador",
|
|
"International 1924", -278, 171, -367 );
|
|
|
|
$_datum{"Provisional South American 1956 Guyana"}
|
|
= Datum->new( "Provisional South American 1956 Guyana",
|
|
"International 1924", -298, 159, -369 );
|
|
|
|
$_datum{"Provisional South American 1956 MEAN:Bolivia/Chile/Columbia/Ecuador/Guyana/Peru/Venezuela"}
|
|
= Datum->new( "Provisional South American 1956 MEAN:Bolivia/Chile/Columbia/Ecuador/Guyana/Peru/Venezuela",
|
|
"International 1924", -288, 175, -376 );
|
|
|
|
$_datum{"Provisional South American 1956 Peru"}
|
|
= Datum->new( "Provisional South American 1956 Peru",
|
|
"International 1924", -279, 175, -379 );
|
|
|
|
$_datum{"Provisional South American 1956 Venezuela"}
|
|
= Datum->new( "Provisional South American 1956 Venezuela",
|
|
"International 1924", -295, 173, -371 );
|
|
|
|
$_datum{"Provisional South Chilean 1963 Near 53S"}
|
|
= Datum->new( "Provisional South Chilean 1963 Near 53S",
|
|
"International 1924", 16, 196, 93 );
|
|
|
|
$_datum{"Puerto Rico/Virgin Is"}
|
|
= Datum->new( "Puerto Rico/Virgin Is",
|
|
"Clarke 1866", 11, 72, -101 );
|
|
|
|
$_datum{"Pulkovo 1942"}
|
|
= Datum->new( "Pulkovo 1942",
|
|
"Krassovsky 1940", 28, -130, -95 );
|
|
|
|
$_datum{"Qatar National"}
|
|
= Datum->new( "Qatar National",
|
|
"International 1924", -128, -283, 22 );
|
|
|
|
$_datum{"Qornoq"}
|
|
= Datum->new( "Qornoq",
|
|
"International 1924", 164, 138, -189 );
|
|
|
|
$_datum{"Reunion"}
|
|
= Datum->new( "Reunion",
|
|
"International 1924", 94, -948, -1262 );
|
|
|
|
$_datum{"Rome 1940"}
|
|
= Datum->new( "Rome 1940",
|
|
"International 1924", -225, -65, 9 );
|
|
|
|
$_datum{"RT 90"}
|
|
= Datum->new( "RT 90",
|
|
"Bessel 1841", 498, -36, 568 );
|
|
|
|
$_datum{"S-42 (Pulkovo 1942) Hungary"}
|
|
= Datum->new( "S-42 (Pulkovo 1942) Hungary",
|
|
"Krassovsky 1940", 28, -121, -77 );
|
|
|
|
$_datum{"S-42 (Pulkovo 1942) Poland"}
|
|
= Datum->new( "S-42 (Pulkovo 1942) Poland",
|
|
"Krassovsky 1940", 23, -124, -82 );
|
|
|
|
$_datum{"S-42 (Pulkovo 1942) Czechoslavakia"}
|
|
= Datum->new( "S-42 (Pulkovo 1942) Czechoslavakia",
|
|
"Krassovsky 1940", 26, -121, -78 );
|
|
|
|
$_datum{"S-42 (Pulkovo 1942) Latvia"}
|
|
= Datum->new( "S-42 (Pulkovo 1942) Latvia",
|
|
"Krassovsky 1940", 24, -124, -82 );
|
|
|
|
$_datum{"S-42 (Pulkovo 1942) Kazakhstan"}
|
|
= Datum->new( "S-42 (Pulkovo 1942) Kazakhstan",
|
|
"Krassovsky 1940", 15, -130, -84 );
|
|
|
|
$_datum{"S-42 (Pulkovo 1942) Albania"}
|
|
= Datum->new( "S-42 (Pulkovo 1942) Albania",
|
|
"Krassovsky 1940", 24, -130, -92 );
|
|
|
|
$_datum{"S-42 (Pulkovo 1942) Romania"}
|
|
= Datum->new( "S-42 (Pulkovo 1942) Romania",
|
|
"Krassovsky 1940", 28, -121, -77 );
|
|
|
|
$_datum{"S-JTSK Czechoslavakia"}
|
|
= Datum->new( "S-JTSK Czechoslavakia",
|
|
"Bessel 1841", 589, 76, 480 );
|
|
|
|
$_datum{"Santo (DOS) 1965"}
|
|
= Datum->new( "Santo (DOS) 1965",
|
|
"International 1924", 170, 42, 84 );
|
|
|
|
$_datum{"Sao Braz"}
|
|
= Datum->new( "Sao Braz",
|
|
"International 1924", -203, 141, 53 );
|
|
|
|
$_datum{"Sapper Hill 1943"}
|
|
= Datum->new( "Sapper Hill 1943",
|
|
"International 1924", -355, 21, 72 );
|
|
|
|
$_datum{"Schwarzeck"}
|
|
= Datum->new( "Schwarzeck",
|
|
"Bessel 1841 (Namibia)", 616, 97, -251 );
|
|
|
|
$_datum{"Selvagem Grande 1938"}
|
|
= Datum->new( "Selvagem Grande 1938",
|
|
"International 1924", -289, -124, 60 );
|
|
|
|
$_datum{"Sierra Leone 1960"}
|
|
= Datum->new( "Sierra Leone 1960",
|
|
"Clarke 1880", -88, 4, 101 );
|
|
|
|
$_datum{"South American 1969 Argentina"}
|
|
= Datum->new( "South American 1969 Argentina",
|
|
"South American 1969", -62, -1, -37 );
|
|
|
|
$_datum{"South American 1969 Bolivia"}
|
|
= Datum->new( "South American 1969 Bolivia",
|
|
"South American 1969", -61, 2, -48 );
|
|
|
|
$_datum{"South American 1969 Brazil"}
|
|
= Datum->new( "South American 1969 Brazil",
|
|
"South American 1969", -60, -2, -41 );
|
|
|
|
$_datum{"South American 1969 Chile"}
|
|
= Datum->new( "South American 1969 Chile",
|
|
"South American 1969", -75, -1, -44 );
|
|
|
|
$_datum{"South American 1969 Colombia"}
|
|
= Datum->new( "South American 1969 Colombia",
|
|
"South American 1969", -44, 6, -36 );
|
|
|
|
$_datum{"South American 1969 Ecuador"}
|
|
= Datum->new( "South American 1969 Ecuador",
|
|
"South American 1969", -48, 3, -44 );
|
|
|
|
$_datum{"South American 1969 Ecuador:Baltra/Galapagos"}
|
|
= Datum->new( "South American 1969 Ecuador:Baltra/Galapagos",
|
|
"South American 1969", -47, 26, -42 );
|
|
|
|
$_datum{"South American 1969 Guyana"}
|
|
= Datum->new( "South American 1969 Guyana",
|
|
"South American 1969", -53, 3, -47 );
|
|
|
|
$_datum{"South American 1969 MEAN"}
|
|
= Datum->new( "South American 1969 MEAN",
|
|
"South American 1969", -57, 1, -41 );
|
|
|
|
$_datum{"South American 1969 Paraguay"}
|
|
= Datum->new( "South American 1969 Paraguay",
|
|
"South American 1969", -61, 2, -33 );
|
|
|
|
$_datum{"South American 1969 Peru"}
|
|
= Datum->new( "South American 1969 Peru",
|
|
"South American 1969", -58, 0, -44 );
|
|
|
|
$_datum{"South American 1969 Trinidad/Tobago"}
|
|
= Datum->new( "South American 1969 Trinidad/Tobago",
|
|
"South American 1969", -45, 12, -33 );
|
|
|
|
$_datum{"South American 1969 Venezuela"}
|
|
= Datum->new( "South American 1969 Venezuela",
|
|
"South American 1969", -45, 8, -33 );
|
|
|
|
$_datum{"South Asia"}
|
|
= Datum->new( "South Asia",
|
|
"Modified Fischer 1960", 7, -10, -26 );
|
|
|
|
$_datum{"Southeast Base"}
|
|
= Datum->new( "Southeast Base",
|
|
"International 1924", -499, -249, 314 );
|
|
|
|
$_datum{"Southwest Base"}
|
|
= Datum->new( "Southwest Base",
|
|
"International 1924", -104, 167, -38 );
|
|
|
|
$_datum{"Tananarive Observatory 1925"}
|
|
= Datum->new( "Tananarive Observatory 1925",
|
|
"International 1924", -189, -242, -91 );
|
|
|
|
$_datum{"Timbalai 1948"}
|
|
= Datum->new( "Timbalai 1948",
|
|
"Everest (Sabah Sarawak)", -679, 669, -48 );
|
|
|
|
$_datum{"Tokyo Japan"}
|
|
= Datum->new( "Tokyo Japan",
|
|
"Bessel 1841", -148, 507, 685 );
|
|
|
|
$_datum{"Tokyo MEAN"}
|
|
= Datum->new( "Tokyo MEAN",
|
|
"Bessel 1841", -148, 507, 685 );
|
|
|
|
$_datum{"Tokyo Okinawa"}
|
|
= Datum->new( "Tokyo Okinawa",
|
|
"Bessel 1841", -158, 507, 676 );
|
|
|
|
$_datum{"Tokyo South Korea"}
|
|
= Datum->new( "Tokyo South Korea",
|
|
"Bessel 1841", -147, 506, 687 );
|
|
|
|
$_datum{"Tristan Astro 1968"}
|
|
= Datum->new( "Tristan Astro 1968",
|
|
"International 1924", -632, 438, -609 );
|
|
|
|
$_datum{"Viti Levu 1916"}
|
|
= Datum->new( "Viti Levu 1916",
|
|
"Clarke 1880", 51, 391, -36 );
|
|
|
|
$_datum{"Voirol 1960"}
|
|
= Datum->new( "Voirol 1960",
|
|
"Clarke 1880", -123, -206, 219 );
|
|
|
|
$_datum{"Wake Island Astro 1952"}
|
|
= Datum->new( "Wake Island Astro 1952",
|
|
"International 1924", 276, -57, 149 );
|
|
|
|
$_datum{"Wake-Eniwetok 1960"}
|
|
= Datum->new( "Wake-Eniwetok 1960",
|
|
"Hough 1960", 102, 52, -38 );
|
|
|
|
$_datum{"WGS 72"}
|
|
= Datum->new( "WGS 72",
|
|
"WGS 72", 0, 0, 0 );
|
|
|
|
$_datum{"WGS 84"}
|
|
= Datum->new( "WGS 84",
|
|
"WGS 84", 0, 0, 0 );
|
|
|
|
$_datum{"Yacare"}
|
|
= Datum->new( "Yacare",
|
|
"International 1924", -155, 171, 37 );
|
|
|
|
$_datum{"Zanderij"}
|
|
= Datum->new( "Zanderij",
|
|
"International 1924", -265, 120, -358 );
|
|
|
|
|
|
#------------------------------------------------------------------------------------------------
|
|
|
|
|
|
package Coordinate;
|
|
|
|
|
|
#
|
|
# Note that we export NOTHING! This module strives to be object-oriented,
|
|
# therefore exporting is a bad thing. You can get to any of the public
|
|
# methods by using normal method calls on an object.
|
|
#
|
|
|
|
|
|
$VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
|
|
|
|
|
|
use Math::Trig;
|
|
#use Math::BigFloat; # Allows arbitrary length floating point operations
|
|
#use strict;
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Here is a Coordinate object. It contains all of the data
|
|
# for describing a single point on the earth and the methods
|
|
# for setting/getting these values.
|
|
#
|
|
|
|
#
|
|
# This constructor can be used to create and initialize an object
|
|
# with Latitude/Longitude/Datum fields.
|
|
#
|
|
sub new
|
|
{
|
|
my $class = shift; # What class are we constructing?
|
|
my $self = { }; # Allocate new memory
|
|
bless $self, $class; # Mark it of the right type
|
|
$self->_init(@_); # Call _init with remaining args
|
|
return $self;
|
|
}
|
|
|
|
|
|
sub _init
|
|
{
|
|
my $self = shift;
|
|
$self->{LATITUDE} = shift if @_;
|
|
$self->{LONGITUDE} = shift if @_;
|
|
$self->{DATUM} = shift if @_;
|
|
}
|
|
|
|
|
|
#
|
|
# This constructor can be used to create and initialize an object
|
|
# with easting/northing/zone/datum fields (UTM grid).
|
|
#
|
|
sub new_utm
|
|
{
|
|
my $class = shift; # What class are we constructing?
|
|
my $self = { }; # Allocate new memory
|
|
bless $self, $class; # Mark it of the right type
|
|
$self->_init_utm(@_); # Call _init with remaining args
|
|
return $self;
|
|
}
|
|
|
|
|
|
sub _init_utm
|
|
{
|
|
my $self = shift;
|
|
$self->{EASTING} = shift if @_;
|
|
$self->{NORTHING} = shift if @_;
|
|
$self->{ZONE} = shift if @_;
|
|
$self->{DATUM} = shift if @_;
|
|
}
|
|
|
|
|
|
#
|
|
# Returns the version number (RCS version tag) of this module.
|
|
#
|
|
sub version
|
|
{
|
|
return $VERSION;
|
|
}
|
|
|
|
|
|
|
|
sub latitude
|
|
{
|
|
my $self = shift;
|
|
$self->{LATITUDE} = shift if @_;
|
|
return $self->{LATITUDE};
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub longitude
|
|
{
|
|
my $self = shift;
|
|
$self->{LONGITUDE} = shift if @_;
|
|
return $self->{LONGITUDE};
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub formatted_latitude
|
|
{
|
|
my $self = shift;
|
|
$self->{FORMATTED_LATITUDE} = shift if @_;
|
|
return $self->{FORMATTED_LATITUDE};
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub formatted_longitude
|
|
{
|
|
my $self = shift;
|
|
$self->{FORMATTED_LONGITUDE} = shift if @_;
|
|
return $self->{FORMATTED_LONGITUDE};
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub easting
|
|
{
|
|
my $self = shift;
|
|
$self->{EASTING} = shift if @_;
|
|
return $self->{EASTING};
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub northing
|
|
{
|
|
my $self = shift;
|
|
$self->{NORTHING} = shift if @_;
|
|
return $self->{NORTHING};
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub zone
|
|
{
|
|
my $self = shift;
|
|
$self->{ZONE} = shift if @_;
|
|
return $self->{ZONE};
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub datum
|
|
{
|
|
my $self = shift;
|
|
$self->{DATUM} = shift if @_;
|
|
return $self->{DATUM};
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Converts lat/lon to UTM coordinates. Equations from USGS Bulletin 1532
|
|
# (According to comments in the original C code).
|
|
#
|
|
# East Longitudes are positive, West are negative.
|
|
# North latitudes are positive, South are negative.
|
|
# Latitude and longitude are in decimal degrees.
|
|
#
|
|
# This method fills in the Easting/Northing/Zone fields in the object.
|
|
# The Zone field will look something like: "10U" when filled in.
|
|
#
|
|
sub lat_lon_to_utm
|
|
{
|
|
my $position = shift; # Snag the pointer to the object.
|
|
|
|
my $PI = 3.14159265358979323846;
|
|
my $deg_2_rad = $PI / 180;
|
|
my $k0 = 0.9996;
|
|
|
|
# First get the datum used in the position from the object:
|
|
my $datum = $position->datum();
|
|
|
|
# Now find out the ellipsoid used by consulting the DatumTable:
|
|
my $ellipsoid = DatumTable->ellipsoid( $datum );
|
|
|
|
# Do a lookup in the $ellipsoid{} hash to find the Radius value.
|
|
my $a = EllipsoidTable->equatorial_radius( $ellipsoid );
|
|
|
|
# Do a lookup in the $ellipsoid{} hash to find the Ecc value.
|
|
my $ecc_Squared = EllipsoidTable->first_ecc_squared( $ellipsoid );
|
|
|
|
my $Lat = $position->latitude();
|
|
my $Long = $position->longitude();
|
|
|
|
# Make sure the longitude is between -180.00 .. 179.9
|
|
my $Long_Temp = ($Long+180)-int(($Long+180)/360)*360-180; # -180.00 .. 179.9;
|
|
|
|
my $Lat_Rad = $Lat * $deg_2_rad;
|
|
my $Long_Rad = $Long_Temp * $deg_2_rad;
|
|
my $Zone_Number = int(($Long_Temp + 180)/6) + 1;
|
|
|
|
if( $Lat >= 56.0 && $Lat < 64.0 && $Long_Temp >= 3.0 && $Long_Temp < 12.0 )
|
|
{
|
|
$Zone_Number = 32;
|
|
}
|
|
|
|
# Special zones for Svalbard
|
|
if( $Lat >= 72.0 && $Lat < 84.0 )
|
|
{
|
|
if( $Long_Temp >= 0.0 && $Long_Temp < 9.0 ) { $Zone_Number = 31 }
|
|
elsif( $Long_Temp >= 9.0 && $Long_Temp < 21.0 ) { $Zone_Number = 33 }
|
|
elsif( $Long_Temp >= 21.0 && $Long_Temp < 33.0 ) { $Zone_Number = 35 }
|
|
elsif( $Long_Temp >= 33.0 && $Long_Temp < 42.0 ) { $Zone_Number = 37 };
|
|
}
|
|
my $Long_Origin = ($Zone_Number - 1)*6 - 180 + 3; # +3 puts origin in middle of zone
|
|
my $Long_Origin_Rad = $Long_Origin * $deg_2_rad;
|
|
|
|
# Compute the UTM Zone from the latitude and longitude
|
|
# NOTE: Need to check for out-of-range here.
|
|
#
|
|
my $Zone_Letter = &_utm_letter_designator($Lat);
|
|
#printf( "Zone_Number: %d\t\tZone_Letter: %s\n", $Zone_Number, $Zone_Letter );
|
|
my $UTM_Zone = sprintf( "%d%s", $Zone_Number, $Zone_Letter );
|
|
|
|
my $ecc_Prime_Squared = ($ecc_Squared)/(1-$ecc_Squared);
|
|
|
|
my $N = $a/sqrt(1-$ecc_Squared*sin($Lat_Rad)*sin($Lat_Rad));
|
|
my $T = tan($Lat_Rad) * tan($Lat_Rad);
|
|
my $C = $ecc_Prime_Squared * cos($Lat_Rad) * cos($Lat_Rad);
|
|
my $A = cos($Lat_Rad) * ($Long_Rad-$Long_Origin_Rad);
|
|
|
|
my $M = $a * ((1 - $ecc_Squared/4 - 3 * $ecc_Squared * $ecc_Squared/64 - 5 * $ecc_Squared * $ecc_Squared * $ecc_Squared/256) * $Lat_Rad
|
|
- (3 * $ecc_Squared/8 + 3 * $ecc_Squared * $ecc_Squared/32 + 45 * $ecc_Squared * $ecc_Squared * $ecc_Squared/1024) * sin(2 * $Lat_Rad)
|
|
+ (15 * $ecc_Squared * $ecc_Squared/256 + 45 * $ecc_Squared * $ecc_Squared * $ecc_Squared/1024) * sin(4 * $Lat_Rad)
|
|
- (35 * $ecc_Squared * $ecc_Squared * $ecc_Squared/3072) * sin(6 * $Lat_Rad));
|
|
|
|
my $UTM_Easting = ($k0 * $N * ($A + (1 - $T + $C) * $A * $A * $A/6
|
|
+ (5 - 18 * $T + $T * $T + 72 * $C - 58 * $ecc_Prime_Squared) * $A * $A * $A * $A * $A/120)
|
|
+ 500000.0);
|
|
|
|
my $UTM_Northing = ($k0 * ($M + $N * tan($Lat_Rad) * ($A * $A/2 + (5 - $T + 9 * $C + 4 * $C * $C) * $A * $A * $A * $A/24
|
|
+ (61 - 58 * $T + $T * $T + 600 * $C - 330 * $ecc_Prime_Squared) * $A * $A * $A * $A * $A * $A/720)));
|
|
|
|
if($Lat < 0)
|
|
{
|
|
$UTM_Northing += 10000000.0; # 10000000 meter offset for southern hemisphere
|
|
}
|
|
|
|
# Write the results back to our position object
|
|
$position->easting( $UTM_Easting );
|
|
$position->northing( $UTM_Northing );
|
|
$position->zone( $UTM_Zone );
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# This routine determines the correct UTM letter designator for the given latitude.
|
|
# Returns 'Z' if latitude is outside the UTM limits of 84N to 80S.
|
|
#
|
|
# Note that this is a normal subroutine, not an object method. It is to
|
|
# be used inside this module only and is not exported.
|
|
#
|
|
sub _utm_letter_designator
|
|
{
|
|
my $Lat = shift;
|
|
my $Letter_Designator;
|
|
|
|
if (( 84 >= $Lat) && ($Lat >= 72)) { $Letter_Designator = 'X' }
|
|
elsif (( 72 > $Lat) && ($Lat >= 64)) { $Letter_Designator = 'W' }
|
|
elsif (( 64 > $Lat) && ($Lat >= 56)) { $Letter_Designator = 'V' }
|
|
elsif (( 56 > $Lat) && ($Lat >= 48)) { $Letter_Designator = 'U' }
|
|
elsif (( 48 > $Lat) && ($Lat >= 40)) { $Letter_Designator = 'T' }
|
|
elsif (( 40 > $Lat) && ($Lat >= 32)) { $Letter_Designator = 'S' }
|
|
elsif (( 32 > $Lat) && ($Lat >= 24)) { $Letter_Designator = 'R' }
|
|
elsif (( 24 > $Lat) && ($Lat >= 16)) { $Letter_Designator = 'Q' }
|
|
elsif (( 16 > $Lat) && ($Lat >= 8)) { $Letter_Designator = 'P' }
|
|
elsif (( 8 > $Lat) && ($Lat >= 0)) { $Letter_Designator = 'N' }
|
|
elsif (( 0 > $Lat) && ($Lat >= -8)) { $Letter_Designator = 'M' }
|
|
elsif (( -8 > $Lat) && ($Lat >= -16)) { $Letter_Designator = 'L' }
|
|
elsif ((-16 > $Lat) && ($Lat >= -24)) { $Letter_Designator = 'K' }
|
|
elsif ((-24 > $Lat) && ($Lat >= -32)) { $Letter_Designator = 'J' }
|
|
elsif ((-32 > $Lat) && ($Lat >= -40)) { $Letter_Designator = 'H' }
|
|
elsif ((-40 > $Lat) && ($Lat >= -48)) { $Letter_Designator = 'G' }
|
|
elsif ((-48 > $Lat) && ($Lat >= -56)) { $Letter_Designator = 'F' }
|
|
elsif ((-56 > $Lat) && ($Lat >= -64)) { $Letter_Designator = 'E' }
|
|
elsif ((-64 > $Lat) && ($Lat >= -72)) { $Letter_Designator = 'D' }
|
|
elsif ((-72 > $Lat) && ($Lat >= -80)) { $Letter_Designator = 'C' }
|
|
else { $Letter_Designator = 'Z' }; # An error flag: Latitude is outside UTM limits
|
|
|
|
return $Letter_Designator;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Converts UTM coordinates to lat/lon. Equations from USGS Bulletin 1532.
|
|
# East longitudes are positive, West are negative.
|
|
# North latitudes are positive, South are negative.
|
|
# Latitude and longitude are in decimal degrees.
|
|
# Zone should look something like: "10U" before starting the conversion.
|
|
#
|
|
sub utm_to_lat_lon
|
|
{
|
|
my $position = shift; # Input is in the form of a "Coordinate" object
|
|
|
|
my $PI = 3.14159265358979323846;
|
|
my $rad_2_deg = 180.0 / $PI;
|
|
my $k0 = 0.9996;
|
|
|
|
# First get the datum used in the position from the object:
|
|
my $datum = $position->datum();
|
|
|
|
# Now find out the ellipsoid used by consulting the DatumTable:
|
|
my $ellipsoid = DatumTable->ellipsoid( $datum );
|
|
|
|
# Do a lookup in the $ellipsoid{} hash to find the Radius value.
|
|
my $a = EllipsoidTable->equatorial_radius( $ellipsoid );
|
|
|
|
# Do a lookup in the $ellipsoid{} hash to find the Ecc value.
|
|
my $ecc_Squared = EllipsoidTable->first_ecc_squared( $ellipsoid );
|
|
|
|
my $x = $position->easting();
|
|
my $y = $position->northing();
|
|
my $Zone_Letter = $position->zone();
|
|
my $Zone_Number = $Zone_Letter;
|
|
$Zone_Number =~ s/(\d+).*/$1/; # Convert to an integer
|
|
|
|
my $e1 = (1-sqrt(1-$ecc_Squared))/(1+sqrt(1-$ecc_Squared));
|
|
|
|
$Zone_Letter =~ s/\d+(\w)/$1/; # Convert UTM zone to just a letter
|
|
#print "$Zone_Letter\n\n";
|
|
|
|
my $Northern_Hemisphere; # 1 for northern hemisphere, 0 for southern
|
|
|
|
$x = $x - 500000.0; # Remove 500,000 meter offset for longitude
|
|
$y = $y;
|
|
|
|
if(($Zone_Letter ge 'N'))
|
|
{
|
|
$Northern_Hemisphere = 1; # 'N' or higher is in the northern hemisphere
|
|
#print "Northern Hemisphere\n";
|
|
}
|
|
else
|
|
{
|
|
$Northern_Hemisphere = 0; # Point is in southern hemisphere
|
|
$y -= 10000000.0; # Remove 10,000,000 meter offset used for southern hemisphere
|
|
#print "Southern Hemisphere\n";
|
|
}
|
|
|
|
#print "Zone_Number: $Zone_Number\n";
|
|
my $Long_Origin = ($Zone_Number - 1) * 6 - 180 + 3; # +3 puts origin in middle of zone
|
|
|
|
my $ecc_Prime_Squared = ($ecc_Squared)/(1 - $ecc_Squared);
|
|
|
|
my $M = $y / $k0;
|
|
my $mu = $M/($a * (1 - $ecc_Squared/4 - 3 * $ecc_Squared * $ecc_Squared/64 - 5 * $ecc_Squared * $ecc_Squared * $ecc_Squared/256));
|
|
|
|
my $phi1_Rad = $mu + (3 * $e1/2 - 27 * $e1 * $e1 * $e1/32) * sin(2 * $mu)
|
|
+ (21 * $e1 * $e1/16 - 55 * $e1 * $e1 * $e1 * $e1/32) * sin(4 * $mu)
|
|
+(151 * $e1 * $e1 * $e1/96) * sin(6 * $mu);
|
|
|
|
my $phi1 = $phi1_Rad * $rad_2_deg;
|
|
|
|
my $N1 = $a/sqrt(1 - $ecc_Squared * sin($phi1_Rad) * sin($phi1_Rad));
|
|
my $T1 = tan($phi1_Rad) * tan($phi1_Rad);
|
|
my $C1 = $ecc_Prime_Squared * cos($phi1_Rad) * cos($phi1_Rad);
|
|
|
|
my $R1 = $a * (1 - $ecc_Squared)/(1 - $ecc_Squared * sin($phi1_Rad) * sin($phi1_Rad)**1.5);
|
|
|
|
my $D = $x/($N1 * $k0);
|
|
|
|
$Lat = $phi1_Rad - ($N1 * tan($phi1_Rad)/$R1) * ($D * $D/2 - (5 + 3 * $T1 + 10 * $C1 - 4 * $C1 * $C1 - 9 * $ecc_Prime_Squared) * $D * $D * $D * $D/24
|
|
+(61 + 90 * $T1 + 298 * $C1 + 45 * $T1 * $T1 - 252 * $ecc_Prime_Squared - 3 * $C1 * $C1) * $D * $D * $D * $D * $D * $D/720);
|
|
|
|
$Lat = $Lat * $rad_2_deg;
|
|
|
|
$Long = ($D - (1 + 2 * $T1 + $C1) * $D * $D * $D/6 + (5 - 2 * $C1 + 28 * $T1 - 3 * $C1 * $C1 + 8 * $ecc_Prime_Squared + 24 * $T1 * $T1)
|
|
*$D * $D * $D * $D * $D/120)/cos($phi1_Rad);
|
|
|
|
$Long = $Long_Origin + $Long * $rad_2_deg;
|
|
|
|
# Write the results back to our position object
|
|
$position->latitude( $Lat );
|
|
$position->longitude( $Long );
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Function to convert latitude and longitude in decimal degrees between WGS 84 and
|
|
# another datum. The arguments to this function are a Coordinate object ($position)
|
|
# and a direction flag ($from_WGS84). The Datum you're translating to/from is
|
|
# stored in the Datum() field of the object (the other Datum is by default WGS 84).
|
|
#
|
|
sub _datum_shift
|
|
{
|
|
my $position = shift; # This is our position object
|
|
|
|
my $from_WGS84 = shift; # If 1, then we're converting from WGS 84
|
|
# to the datum listed in the position object
|
|
# If 0, we're going the other way.
|
|
|
|
my $PI = 3.14159265358979323846;
|
|
my $rad_2_deg = 180.0 / $PI;
|
|
my $deg_2_rad = $PI / 180;
|
|
|
|
#printf("%s\n", $position->datum() );
|
|
|
|
my $datum = $position->datum(); # Snag the parameters from the position object
|
|
# (Get the "other" datum).
|
|
|
|
my $latitude = $position->latitude();
|
|
my $longitude = $position->longitude();
|
|
|
|
# Now find out the ellipsoid used by consulting the DatumTable:
|
|
my $ellipsoid = DatumTable->ellipsoid( $datum );
|
|
|
|
my $dx = DatumTable->dx($datum); # Grab the parameters for the "other" datum.
|
|
my $dy = DatumTable->dy($datum); # Offsets between "other" datum and WGS84
|
|
my $dz = DatumTable->dz($datum); # ellipsoid centers.
|
|
|
|
#print "$dx\t$dy\t$dz\n";
|
|
|
|
|
|
my $WGS_a = EllipsoidTable->equatorial_radius("WGS 84"); # WGS 84 semimajor axis
|
|
my $WGS_inv_f = EllipsoidTable->inverse_flattening("WGS 84"); # WGS 84 1/f
|
|
|
|
my $phi = $latitude * $deg_2_rad;
|
|
my $lambda = $longitude * $deg_2_rad;
|
|
my ($a0, $b0, $es0, $f0); # Reference ellipsoid of input data
|
|
my ($a1, $b1, $es1, $f1); # Reference ellipsoid of output data
|
|
my $psi; # geocentric latitude
|
|
my ($x, $y, $z); # 3D coordinates with respect to original datum
|
|
my $psi1; # transformed geocentric latitude
|
|
|
|
if ($datum eq "WGS 84") # do nothing if current datum is WGS 84
|
|
{
|
|
return(1);
|
|
}
|
|
|
|
if ($from_WGS84) # convert from WGS 84 to new datum
|
|
{
|
|
$a0 = $WGS_a; # WGS 84 semimajor axis
|
|
$f0 = 1.0 / $WGS_inv_f; # WGS 84 flattening
|
|
$a1 = EllipsoidTable->equatorial_radius($ellipsoid);
|
|
$f1 = 1.0 / EllipsoidTable->inverse_flattening($ellipsoid);
|
|
}
|
|
else # convert from old datum to WGS 84
|
|
{
|
|
$a0 = EllipsoidTable->equatorial_radius($ellipsoid); # semimajor axis
|
|
$f0 = 1.0 / EllipsoidTable->inverse_flattening($ellipsoid); # flattening
|
|
$a1 = $WGS_a; # WGS 84 semimajor axis
|
|
$f1 = 1 / $WGS_inv_f; # WGS 84 flattening
|
|
$dx = -$dx;
|
|
$dy = -$dy;
|
|
$dz = -$dz;
|
|
}
|
|
|
|
$b0 = $a0 * (1 - $f0); # semiminor axis for input datum
|
|
$es0 = 2 * $f0 - $f0*$f0; # eccentricity^2
|
|
|
|
$b1 = $a1 * (1 - $f1); # semiminor axis for output datum
|
|
$es1 = 2 * $f1 - $f1*$f1; # eccentricity^2
|
|
|
|
# Convert geodedic latitude to geocentric latitude, psi
|
|
|
|
if ($latitude == 0.0 || $latitude == 90.0 || $latitude == -90.0)
|
|
{
|
|
$psi = $phi;
|
|
}
|
|
else
|
|
{
|
|
$psi = atan((1 - $es0) * tan($phi));
|
|
}
|
|
|
|
# Calculate x and y axis coordinates with respect to the original ellipsoid
|
|
|
|
if ($longitude == 90.0 || $longitude == -90.0)
|
|
{
|
|
$x = 0.0;
|
|
$y = abs($a0 * $b0 / sqrt($b0*$b0 + $a0*$a0* ( tan($psi)**2.0) ) );
|
|
}
|
|
else
|
|
{
|
|
$x = abs(($a0 * $b0) /
|
|
sqrt( (1 + (tan($lambda)**2.0) ) * ($b0*$b0 + $a0*$a0 * (tan($psi)**2.0) ) ) );
|
|
|
|
$y = abs($x * tan($lambda));
|
|
}
|
|
|
|
if ($longitude < -90.0 || $longitude > 90.0)
|
|
{
|
|
$x = -$x;
|
|
}
|
|
if ($longitude < 0.0)
|
|
{
|
|
$y = -$y;
|
|
}
|
|
|
|
# Calculate z axis coordinate with respect to the original ellipsoid
|
|
|
|
if ($latitude == 90.0)
|
|
{
|
|
$z = $b0;
|
|
}
|
|
elsif ($latitude == -90.0)
|
|
{
|
|
$z = -$b0;
|
|
}
|
|
else
|
|
{
|
|
$z = tan($psi) * sqrt( ($a0*$a0 * $b0*$b0) / ($b0*$b0 + $a0*$a0 * (tan($psi)**2.0) ) );
|
|
}
|
|
|
|
# Calculate the geocentric latitude with respect to the new ellipsoid
|
|
|
|
$psi1 = atan(($z - $dz) / sqrt(($x - $dx)*($x - $dx) + ($y - $dy)*($y - $dy)));
|
|
|
|
# Convert to geocentric latitude and save return value
|
|
|
|
$latitude = atan(tan($psi1) / (1 - $es1)) * $rad_2_deg;
|
|
|
|
# Calculate the longitude with respect to the new ellipsoid
|
|
|
|
$longitude = atan(($y - $dy) / ($x - $dx)) * $rad_2_deg;
|
|
|
|
# Correct the resultant for negative x values
|
|
|
|
if ($x-$dx < 0.0)
|
|
{
|
|
if ($y-$dy > 0.0)
|
|
{
|
|
$longitude = 180.0 + $longitude;
|
|
}
|
|
else
|
|
{
|
|
$longitude = -180.0 + $longitude;
|
|
}
|
|
}
|
|
|
|
# Write the results back to our position object
|
|
$position->latitude($latitude);
|
|
$position->longitude($longitude);
|
|
|
|
if (! $from_WGS84) # If we're converting to WGS 84 datum
|
|
{
|
|
$position->datum( "WGS 84" ); # Change the datum to correspond to
|
|
# the new data in the object
|
|
}
|
|
|
|
#print "New one: $latitude, $longitude\n";
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Method to convert latitude and longitude in decimal degrees from another
|
|
# datum to WGS 84. The only argument to this method is a Coordinate object
|
|
# with the lat/lon/datum fields filled in.
|
|
#
|
|
# This method returns a NEW Coordinate object with lat/lon/datum fields
|
|
# filled in and the other fields empty. The original object is not changed.
|
|
#
|
|
sub datum_shift_to_wgs84
|
|
{
|
|
my $old_position = shift; # This is our original position object
|
|
|
|
my $to_WGS84 = 0;
|
|
|
|
# Create a new object and fill in a few fields
|
|
my $new_position = Coordinate->new( $old_position->latitude(),
|
|
$old_position->longitude(),
|
|
$old_position->datum() );
|
|
|
|
&_datum_shift( $new_position, $to_WGS84 );
|
|
|
|
return( $new_position ); # Return the datum-shifted object
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Method to convert latitude and longitude in decimal degrees from WGS 84 to
|
|
# another datum. The arguments to this method are a Coordinate object
|
|
# with the lat/lon/datum fields filled in (the datum field must be "WGS 84"),
|
|
# AND a datum (string) to shift to.
|
|
#
|
|
# This method returns a NEW Coordinate object with lat/lon/datum fields
|
|
# filled in. The original object is not changed.
|
|
#
|
|
sub datum_shift_from_wgs84_to
|
|
{
|
|
my $old_position = shift; # This is our original position object
|
|
my $new_datum = shift; # The datum we wish to shift to
|
|
|
|
my $from_WGS84 = 1;
|
|
|
|
# Create a new object and fill in a few fields
|
|
my $new_position = Coordinate->new( $old_position->latitude(),
|
|
$old_position->longitude(),
|
|
$new_datum );
|
|
|
|
&_datum_shift( $new_position, $from_WGS84 );
|
|
|
|
return( $new_position ); # Return the datum-shifted object
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Degrees and Decimal Minutes
|
|
#
|
|
# Fills in the Formatted_latitude and Formatted_longitude variables
|
|
# in the object.
|
|
#
|
|
sub degrees_minutes
|
|
{
|
|
my $self = shift; # Get the object to work on
|
|
|
|
$temp = CoordinateFormat->new(); # Create temporary object
|
|
|
|
$temp->raw( $self->latitude() ); # Fill in with raw data
|
|
$self->formatted_latitude ( $temp->degrees_minutes() ); # Process it & fill in our finished string
|
|
|
|
$temp->raw( $self->longitude() ); # Fill in with raw data
|
|
$self->formatted_longitude( $temp->degrees_minutes() ); # process it & fill in our finished string
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Degrees/Minutes/Seconds
|
|
#
|
|
# Fills in the Formatted_latitude and Formatted_longitude variables
|
|
# in the object.
|
|
#
|
|
sub degrees_minutes_seconds
|
|
{
|
|
my $self = shift; # Get the object to work on
|
|
|
|
$temp = CoordinateFormat->new(); # Create the temporary object
|
|
|
|
$temp->raw( $self->latitude() ); # Fill in with raw data
|
|
$self->formatted_latitude ( $temp->degrees_minutes_seconds() ); # Process it & fill in our finished string
|
|
|
|
$temp->raw( $self->longitude() ); # Fill in with raw data
|
|
$self->formatted_longitude( $temp->degrees_minutes_seconds() ); # Process it & fill in our finished string
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
# Decimal Degrees
|
|
#
|
|
# Fills in the Formatted_latitude and Formatted_longitude variables
|
|
# in the object.
|
|
#
|
|
sub decimal_degrees
|
|
{
|
|
my $self = shift; # Get the object to work on
|
|
|
|
$temp = CoordinateFormat->new(); # Create the temporary object
|
|
|
|
$temp->raw( $self->latitude() ); # Fill in with raw data
|
|
$self->formatted_latitude ( $temp->decimal_degrees() ); # Process it & fill in our finished string
|
|
|
|
$temp->raw( $self->longitude() ); # Fill in with raw data
|
|
$self->formatted_longitude( $temp->decimal_degrees() ); # Process it & fill in our finished string
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
#------------------------------------------------------------------------------------------------
|
|
|
|
|
|
#
|
|
# Auto-run code
|
|
#
|
|
# This code will get run automatically whenever this file gets "required"
|
|
# or "used" in another Perl program.
|
|
#
|
|
|
|
|
|
1; # Needed to prevent exception when loading this module
|
|
|
|
|