/usr/share/perl5/Geography/NationalGrid/TW.pm is in libgeography-nationalgrid-perl 1.6-10.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | package Geography::NationalGrid::TW;
use Exporter;
use strict;
use vars qw(@ISA $VERSION %ellipsoids %mercators);
($VERSION) = 0.07;
use constant DEFAULT_PROJECTION => 'TWD97';
use constant MIN_LATI => Geography::NationalGrid->deg2rad(21.5);
use constant MAX_LATI => Geography::NationalGrid->deg2rad(25.5);
use constant MIN_LONG => Geography::NationalGrid->deg2rad(118.75);
use constant MAX_LONG => Geography::NationalGrid->deg2rad(122.5);
@ISA = qw( Exporter Geography::NationalGrid );
%ellipsoids = (
'int1967' => {
'a' => 6378160.000,
'b' => 6356774.719,
'info' => 'Australian National',
}, # same as grs67
'int1924' => {
'a' => 6378388.000,
'b' => 6356911.946,
'info' => 'ED50, UTM',
}, # same as hayford1909
'wgs84' => {
'a' => 6378137.000,
'b' => 6356752.3141,
'info' => 'WGS84, ITRS, ETRS89',
}, # same as grs80
);
$ellipsoids{'grs67'} = $ellipsoids{'int1967'};
$ellipsoids{'grs80'} = $ellipsoids{'wgs84'};
$ellipsoids{'hayford1909'} = $ellipsoids{'int1924'};
%mercators = (
'TWD67' => {
'scalefactor' => 0.9999,
'phio' => 0,
'lambdao' => Geography::NationalGrid->deg2rad(121),
'Eo' => 250000,
'No' => 0,
'ellipsoid' => 'int1967',
},
'TWD97' => {
'scalefactor' => 0.9999,
'phio' => 0,
'lambdao' => Geography::NationalGrid->deg2rad(121),
'Eo' => 250000,
'No' => 0,
'ellipsoid' => 'grs80',
},
);
### PUBLIC INTERFACE
# new() does most of the work - we regularize the input to create a fully-populated object
sub new {
my $class = shift;
my %options = @_;
unless ((exists $options{'Latitude'} && exists $options{'Longitude'}) ||
(exists $options{'Easting'} && exists $options{'Northing'})
) {
die __PACKAGE__ . ": You must supply lat/long, or easting/northing";
}
my $self = bless({
Userdata => $options{'Userdata'},
}, $class);
# keep constructor options
delete $options{'Userdata'};
while (my ($k, $v) = each %options) { $self->{'_constructor_'.$k} = $v; }
$self->{'Projection'} = $options{'Projection'} || DEFAULT_PROJECTION;
# gather information that will be needed in lat/long <-> east/north method
my $mercatordata = $mercators{ $self->{'Projection'} } || die "Couldn't find Mercator projection data for $self->{'Projection'}";
my $ellipsoiddata = $ellipsoids{ $mercatordata->{'ellipsoid'} } || die "Couldn't find ellipsoid data for $self->{'Projection'}";
$self->{'MercatorData'} = $mercatordata;
$self->{'EllipsoidData'} = $ellipsoiddata;
$self->{'DefaultResolution'} = 0;
my $flagTodo = 1;
# if given lat/long, first make that into easting/northing
if (exists $options{'Latitude'} && exists $options{'Longitude'}) {
$self->{'Latitude'} = $self->deg2rad( $options{'Latitude'} );
$self->{'Longitude'} = $self->deg2rad( $options{'Longitude'} );
$self->_latlong2mercator;
$flagTodo = 0;
}
# if got absolute northing and easting, convert that into a lat/long
if ($flagTodo && exists $options{'Easting'} && exists $options{'Northing'}) {
($self->{'Easting'}, $self->{'Northing'}) = ($options{'Easting'}, $options{'Northing'});
$self->_mercator2latlong;
$flagTodo = 0;
}
$self->_boundscheck;
return $self;
}
### Main conversion methods (to transform lat/long to/from a transverse mercator projection) are inherited from the NationaGrid module
sub transform {
my $self = shift;
my $Projection = shift;
return $self if $Projection eq $self->{'Projection'};
my $a = 0.00001549;
my $b = 0.000006521;
my $c = 807.8;
my $d = -248.6;
my $e = $self->{'Easting'};
my $n = $self->{'Northing'};
my ($_e, $_n);
if ($Projection eq 'TWD97') { # TWD67 -> TWD97
$_e = $e + $c + $a * $e + $b * $n;
$_n = $n + $d + $a * $n + $b * $e;
} else { # TWD97 -> TWD67
$_e = $e - $c - $a * $e - $b * $n;
$_n = $n - $d - $a * $n - $b * $e;
}
return new Geography::NationalGrid::TW('Projection' => $Projection,
'Easting' => $_e, 'Northing' => $_n);
}
### PRIVATE ROUTINES
sub _boundscheck {
my $self = shift;
if ($self->{'Longitude'} < MIN_LONG) { die "Point is out of the area covered by this module - too far east"; }
if ($self->{'Longitude'} > MAX_LONG) { die "Point is out of the area covered by this module - too far west"; }
if ($self->{'Latitude'} < MIN_LATI) { die "Point is out of the area covered by this module - too far south"; }
if ($self->{'Latitude'} > MAX_LATI) { die "Point is out of the area covered by this module - too far north"; }
}
1;
__END__
=pod
=head1 NAME
Geography::NationalGrid::TW - Module to convert Taiwan Datum (TWD67/TM2, TWD97/TM2) to/from Latitude and Longitude
=head1 SYNOPSIS
You should _create_ the object using the Geography::NationalGrid factory class, but you still need to
know the object interface, given below.
use Geography::NationalGrid;
use Geography::NationalGrid::TW;
# default TWD97
my $point1 = new Geography::NationalGrid::TW(
'Easting' => 302721.36,
'Northing' => 2768851.3995,
);
printf("Point 1 is %f X and %f Y\n", $point1->easting, $point1->northing);
printf("Point 1 is %f N and %f E\n", $point1->latitude, $point1->longitude);
# transform to TWD67
$point1->transform('TWD67');
=head1 DESCRIPTION
Once created, the object allows you to retrieve information about the point that the object represents.
For example you can create an object using easting / northing and the retrieve the latitude / longitude.
=head1 OPTIONS
These are the options accepted in the constructor. You MUST provide either Latitude and Longitude,
or Easting and Northing.
=over
=item Projection
Default is 'TWD97', the "TAIWAN DATUM 97".
Another projection recognized is 'TWD67', but only 'TWD97' is tested.
=item GridReference
There is no grid reference in Taiwan datum. Grid related functions are disabled.
=item Latitude
The latitude of the point. Actually should be the latitude using the spheroid related to the grid projection but for most purposes the difference is not too great. Specify the amount in any of these ways: as a decimal number of degrees, a reference to an array of three values (i.e. [ $degrees, $minutes, $seconds ]), or as a string of the form '52d 13m 12s'. North is positive degrees, south is negative degrees.
=item Longitude
As for latitude, except that east is positive degrees, west is negative degrees.
=item Easting
The number of metres east of the grid origin, using grid east.
=item Northing
The number of metres north of the grid origin, using grid north.
=item Userdata
The value of this option is a hash-reference, which you can fill with whatever you want - typical usage might be to specify C<Userdata => { Name =E<gt> 'Dublin Observatory' }> but add whatever you want. Access using the data() method.
=back
=head1 METHODS
Most of these methods take no arguments. Some are inherited from Geography::NationalGrid
=over 4
=item latitude
Returns the latitude of the point in a floating point number of degrees, north being positive.
=item longitude
As latitude, but east is positive degrees.
=item easting
How many metres east of the origin the point is. The precision of this value depends on how it was derived, but is truncated to an integer number of metres.
=item northing
How many metres north of the origin the point is. The precision of this value depends on how it was derived, but is truncated to an integer number of metres.
=item deg2string( DEGREES )
Given a floating point number of degrees, returns a string of the form '51d 38m 34.34s'. Intended for formatting, like:
$self->deg2string( $self->latitude );
=item data( PARAMETER_NAME )
Returns the item from the Userdata hash whose key is the PARAMETER_NAME.
=item transform( PROJECTION )
Transform the point to the new projection, i.e. TWD67 to TWD97 or reverse. Return the point after transformation and keep original point intact. Uses the formula proposed by John Hsieh which is supposed to provide 2 meter accuracy conversions.
=back
=head1 ACCURACY AND PRECISION
The routines used in this code may not give you completely accurate results for various mathematical and theoretical reasons. In tests the results appeared to be correct, but it may be that under certain conditions the output
could be highly inaccurate. It is likely that output accuracy decreases further from the datum, and behaviour is probably divergent outside the intended area of the grid.
This module has been coded in good faith but it may still get things wrong. Hence, it is recommended that this module is used for preliminary calculations only, and that it is NOT used under any circumstance where its lack of accuracy could cause any harm, loss or other problems of any kind. Beware!
=head1 REFERENCES
http://wiki.osgeo.org/wiki/Taiwan_datums
John Hsieh - http://gis.thl.ncku.edu.tw/coordtrans/coordtrans.aspx
=head1 AUTHOR AND COPYRIGHT
Copyright (c) 2006 Yen-Ming Lee C<< <leeym@leeym.com> >>. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=cut
|