perl – Convert references of British and Irish national Grids to or from geodetic coordinates WGS84

I have been using this wgs84togrid Program for some years. It converts in both directions between the coordinates of the National Grid for GB or Ireland (starting with a letter or pair of letters that identify the 100 square km) and the latitude / longitude positions (in decimal degrees, decimal minutes or decimal seconds) in an ellipsoid WGS84.

Acts as a filter, waiting one point per line, copying without modifying any unrecognized part of the line.

Program options (everything can be shortened, provided it is not ambiguous):

  • -Gridcha EschaKcha EschaK EschaKcha Escha Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es!
  • -reverse: reverse direction – convert the positions of the National Grid to WGS84
  • -lolat: the geodesic positions are the first length
  • -fact: use alternative datum instead of WGS84 (the coordinates of the National Grid are always in the appropriate fixed datum)
  • -precision: how many digits should be included in the north and east (default: 5, which gives a resolution of 1 meter)
  • -verbose: additional output (to confirm that lat / lon is analyzed as expected).

Example of use (in Bash):

$ wgs84togrid -p 3 <<< "55 ° 56'55" N 3 ° 12'03 "W"
NT251734
$ wgs84togrid -r <<< NT251734
55.9482278708547 -3.20011121889597

The heavy work of coordinate transformation is done by the PROJ.4 library; All I do is manage the grid letters and the I / O formats.

I assume the presence of Scotland.gsb Y england-wales.gsb files of grid corrections, but that option can be eliminated if you do not have them, at a cost of a few meters of accuracy (<10 m, I'm sure).

Specifically out of reach:

  • I do not check that the point is within the valid area of ​​the chosen grid (and I certainly do not think of the automatic selection of the correct grid).
  • There are no plans to support any other network anywhere else in the world.

#! / usr / bin / perl -w

strict use

use Getopt :: Long;

use Geo :: Proj4;



my square% = (A => & # 39; 04 & # 39 ;, B => & # 39; 14 & # 39 ;, C => & # 39 ;, D => & # 39; 34 & # 39 ;, E => & # 39; 44 & # 39 ;,
F => & # 39; 03 & # 39 ;, G => & # 39; 13 & # 39 ;, H => & # 39 ;, 23 & # 39 ;, J => & # 39 ;, 33 & # 39 ;, K = > & # 39; 43 & # 39 ;,
L => & # 39; 02 & # 39 ;, M => & # 39 ;, & # 39 ;, N => & # 39; 22 & # 39 ;, O => & # 39 ;, & # 39 ;, P = > & # 39; 42 & # 39 ;,
Q => & # 39; 01 & # 39 ;, R => & # 39 ;, & # 39 ;, S => & # 39 ;, & # 39 ;, T => & # 39; 31 & # 39 ;, U = > & # 39; 41 & # 39 ;,
V => & # 39 ;, & # 39 ;, W => & # 39 ;, X => & # 39 ;, & # 39 ;, Y => & # 39 ;, & # 39 ;, Z = > & # 39; 40 & # 39;);

my% tosquare = map {($ squares {$ _}, $ _)} keys% square;

my $ grid = & # 39; GB & # 39 ;;
my $ lonlat;
my $ datum = & # 39; WGS84 & # 39 ;;
my $ precision = 5;
my $ reverse
my detailed $


GetOptions (& # 39; grid = s & # 39; =>  $ grid,
& Backing! & # 39; =>  $reverse,
& # 39; Lonlat! & # 39; =>  $ lonlat,
& # 39; datum = s & # 39; =>  $fact,
& # 39; precision = i & # 39; =>  $ precision,
& Verbose! & # 39; =>  $verbose) or die "Option parsing failure  n";

sub any2xy ($$$) {
my ($ x, $ y, $ numbers) = @_;
my $ len = length $ numbers;
die "Odd gridref length - & # 39; $ _ & # 39; ($ len)  n" if $ len% 2;
$ len / = 2;
$ x = 100000 * ("$ x.". substr ($ numbers, 0, $ len). & # 39; 5 & # 39;);
$ y = 100000 * ("$ y.". substr ($ numbers, $ len). & # 39; 5 & # 39;);
he came back [$x, $y];
}

sub osgb2xy ($) {
local $ _ = change;
my ($ letters, $ numbers) = m / ^ ( D {2}) ( d +) $ / or die "malformed OSGB ref & # 39; $ _ & # 39;  n";
my $ x = 0;
my $ y = 0;
foreach (split & # 39; & # 39 ;, $ letters) {
my @sq = divide & # 39 ;, $ square {$ _} or die "Square without grid & # 39; $ _ & # 39;  n";
$ x = 5 * $ x + $ sq[0];
$ y = 5 * $ and + $ sq[1];
}
$ x - = 10;
$ y - = 5;
returns any2xy ($ x, $ y, $ numbers);
}

sub osi2xy ($) {
$ _ = change;
my ($ letters, $ numbers) = m / ^ ( D) ( d +) $ or die "Ref. OSI with incorrect format & # 39; $ _ & # 39;  n";
my ($ x, $ y) = divide & # 39; & # 39 ;, $ squared {$ letters} or die "Square without grid & # 39; $ _ & # 39;  n";
returns any2xy ($ x, $ y, $ numbers);
}

subgroup$$$$) {
mi ($ sq, $ x, $ y, $ prec) = @_;
return sprintf (& # 39;% s% s% s & # 39 ;, $ sq, map {substr (100000 + $ _% 100000, 1, $ prec)} ($ x, $ y));
}

sub xy2osi ($$$) {
mi ($ x, $ y, $ prec) = @_;
my $ sq = $ tosquare {int ($ x / 100000). int ($ y / 100000)} or die "No square for $ x, $ and  n";
return togrid ($ sq, $ x, $ y, $ prec);
}

sub xy2osgb ($$$) {
mi ($ x, $ y, $ prec) = @_;
$ x + = 1000000;
$ y + = 500000;
my $ sq = $ tosquare {int ($ x / 500000). int ($ y / 500000)}. $ tosquare {int ($ x / 100000)% 5. int ($ y / 100000)% 5} or die "Not squared for $ x, $ and  n";
return togrid ($ sq, $ x, $ y, $ prec);
}

my $ tickets;
sub getnext ();
sub getnext () {
if ($ tickets) {
$ _ = <$inputs>;
returns $ _ if $ _;
$ inputs = undef;
}
if (@ARGV) {
$ _ = change @ARGV;
yes ($ _ eq & # 39; - & # 39;) {
$ inputs =  * STDIN;
return getnext ();
}
returns $ _;
}
returns undef;
}


my $ wgs84 = Geo :: Proj4-> new (proj => & # 39; latlon & # 39 ;, datum => $ datum) or die Geo :: Proj4-> error;

my ($ proj, $ xy2grid, $ grid2xy);
if (uc $ grid eq & # 39; GB & # 39;) {
$ proj = Geo :: Proj4-> new (init => & # 39; epsg: 27700 + nadgrids = scotland.gsb, england-wales.gsb & # 39;) or die Geo :: Proj4-> error;
$ xy2grid =  & xy2osgb;
$ grid2xy =  & osgb2xy;
} elsif (uc $ grid eq & # 39; IE & # 39;) {
$ proj = Geo :: Proj4-> new (init => & # 39; epsg: 29901 & # 39;) or die Geo :: Proj4-> error;
$ xy2grid =  & xy2osi;
$ grid2xy =  & osi2xy;
} else {
die "Unknown grid & # 39; $ grid & # 39;  n";
}

my $ numpat = & # 39;[+-]?  d + (?: .  d +)?  s * & # 39 ;;

@ARGV = (& # 39; - & # 39;) unless @ARGV;
while ($ _ = getnext ()) {
chomp
if ($ reverse) {
my $ point = $ grid2xy -> ($ _);
my ($ lon, $ lat) = @ {$ proj-> transform ($ wgs84, $ point)};
print $ lonlat? "$ lon $ lat  n": "$ lat $ lon  n";
} else {
tr /, & # 39; "/ ms /;
s / ° / d / g;
s / '/ m / g;
s / "/ s / g;
s / ($ numpat) m  s * ($ numpat) s? / ($ 1 + $ 2  /60.0). "m" / oeg;
Es Es Es Es Es Escha Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es EsK Es EsK Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es Es EsK Es Es Es!  s * ($ numpat) (?: m  s *)? / ($ 1 + $ 2  /60.0) / oeg;
tr / d // d;
s /  s *  b ([nsew])  b  s * / $ 1 / i;
tr! /,! !
s / ($ numpat[ew ])  s * ($ numpat[ns]?) / $ 2 $ 1 / oi;
cha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha Escha![ns]|[ns]Es Escha EsK Escha EsK Escha! Escha Escha! Escha EschaK Escha EschaKcha EschaK Escha EschaKcha Escha EschaKcha Escha EschaKcha Escha EschaK Escha Escha Es!

my ($ lat, $ ns, $ lon, $ ew) = m / ^  s * ($ numpat) ([ns ]?)  s * ($ numpat) ([ew]?)  s * $ / i
or die "Input malformed: $ _  n";
$ lat * = -1 if lc $ ns eq & # 39; s & # 39 ;;
$ lon * = -1 if lc $ ew eq & # 39; w & # 39 ;;
print STDERR "$ lat, $ lon  n" if $ verbose;
my $ dot = ($ ns || $ ew || $ lonlat)? [$lon, $lat] : [$lat, $lon];
mi ($ x, $ y) = @ {$ wgs84-> transform ($ proj, $ point)};
print $ xy2grid -> ($ x, $ y, $ precision), " n";
}
}