Provided by: libgeo-coordinates-osgb-perl_2.06-1_all bug

NAME

       Geo::Coordinates::OSTN02 - An implementation of the OSGB's OSTN02 transformation

SYNOPSIS

         use Geo::Coordinates::OSTN02 qw/OSGB36_to_ETRS89 ETRS89_to_OSGB36/;

         ($x, $y, $z) = OSGB36_to_ETRS89($e, $n, $h);
         ($e, $n, $h) = ETRS89_to_OSGB36($x, $y, $z);

DESCRIPTION

       The purpose and use of these modules is described briefly in the companion Geo::Coordinates::OSGB
       modules.  In essence they implement in Perl the Ordnance Survey's OSTN02 transformation which is part of
       the current definition of the British National Grid.  You are strongly recommended to read the official
       public guides and other introductory documents that are published by the Ordnance Survey of Great Britain
       with a wealth of other technical information about the OSTN02 transformation.

FUNCTIONS

       The following functions can be exported from the "Geo::Coordinates::OSTN02" module:

           OSGB36_to_ETRS89
           ETRS89_to_OSGB36

       None is exported by default.

       OSGB36_to_ETRS89(easting, northing, [elevation])
           Transforms from normal OSGB36 grid references to a pseudo-grid based on the WGS84/ETRS89 geoid model,
           which can then be translated to lat/long coordinates using "grid_to_ll()" with the 'WGS84' parameter.

              my $elevation = '100'; # in metres
              my ($e, $n) = parse_grid_trad('TQ304293');
              my ($x, $y, $z) = OSGB36_to_ETRS89($e, $n, $elevation);
              my ($lat, $lon) = grid_to_ll($x, $y, 'ETRS89'); # or 'WGS84'

           Elevation will default to 0 metres if you omit it.

       ETRS89_to_OSGB36(x, y, [z])
           Transforms WGS84/ETRS89 pseudo-grid coordinates into OSGB36 grid references.

             my ($lat, $lon, $height) = (51.5, -1, 10); # Somewhere in London
             my ($x, $y) = ll_to_grid($lat, $lon, 'ETRS89'); # or 'WGS84'
             my ($e, $n, $elevation) = ETRS89_to_OSGB36($x, $y, $height);

IMPLEMENTATION NOTES

       Since  2002  the British Ordnance Survey have defined the UK national grid not as a projection from their
       own model of the earth (the Airy 1830 geoid, revised 1936, known as OSGB36), but as  a  simple  table  of
       calculated differences from a projection based on the European standard geoid ETRS89 (which is for Europe
       a  functional  equivalent  of  the  international WGS84 geoid).  This revision is known as OSGM02 and the
       transformation is called OSTN02.

       The idea is that you project your WGS84 latitude and longitude coordinates into WGS84 (or ETRS89) pseudo-
       grid references, and then look up the appropriate three dimensional correction in the OS table,  and  add
       the  results  to  your grid reference to give you a standard British National Grid reference that you can
       use with British OS maps.  Going back the other way is slightly more complicated, as  you  have  to  work
       backwards,  but  a  simple  iteration  will  do  the  job.   This  package  implements  these lookups and
       adjustments.  You give it a three dimensional grid reference (easting, northing,  and  altitude,  all  in
       metres) and the package returns it corrected from one system to the other.

       The  problem  in  the  implementation  is  that the table is huge, and most of it is empty as the OS have
       chosen to leave the transformation undefined for areas that are off shore.  So this  package  only  works
       properly for grid references that are actually on one or more OS maps.  The complete table (including all
       the 0 lines) contains nearly 1 million lines with six data points and a key.  In text form as supplied by
       the OS that is about 36M bytes of table.  By leaving out the lines where the transformation is undefined,
       omitting  a  couple  of  redundant  fields, and storing everything as hex strings, this module brings the
       amount of data down to just over 6M bytes, which loads in about 1 second on my test system.  It would  be
       possible  to  compress  the  data down to 3M bytes by storing it as packed decimals, but then it would be
       difficult to include inline in this module, as it would break every time I edited it.

       The data is stored below, after the __DATA__ line.  Each  line  is  18  bytes  long  and  represents  the
       transformation  parameters  for  an individual grid square of 1km by 1km.  Each line contains five fields
       all expressed as hexadecimal integers.

           Start   Length  Meaning
           0       3       The northing of the square in km
           3       3       The easting of the square in km
           6       4       The x-offset in mm (easting)
           10      4       The y-offset in mm (northing)
           14      4       The z-offset in mm (elevation)

       To keep the numbers small and positive the values given for the offsets are actually the amount that they
       exceed the respective smallest values in the data set.   Currently  these  minima  are  x:   86275mm,  y:
       -81603mm,  and  z:   43982mm.   So  when  we read a line from the data we have to add these minima to the
       values, convert to decimal, and multiply by 1000 to get back to metres.

       When you load the OSTN02 module, the first thing it does is to load  all  309,798  lines  into  an  array
       called @ostn_data by simply doing this.

           our @ostn_data = <DATA>;

       This is why it takes a few microseconds to load the module, but once loaded it's all very fast.

       When  we need to find the data values for a given grid reference, we work out the appropriate grid square
       by truncating the easting and northing to the next lowest whole kilometer, and pass these as the argument
       to the "_get_ostn_ref" subroutine.  This is the only subroutine that actually touches the data.

       The core of the subroutine is a binary search.  We work out  the  key  by  converting  the  northing  and
       easting  to hexadecimal and concatenating them.  We add leading zeros so that each value is exactly three
       bytes long and the combined key is exactly six bytes long.  The maximum value for  easting  in  the  OSGB
       grid  is 700km and for northing 1250km, which are 2BC and 4E2, so each fits into three bytes. (And by the
       time this is called we have already checked that the values don't exceed the maxima).

       This works pretty quickly, the only slow bit is loading the array at the beginning, but it is much faster
       and needs *much* less memory than loading all the data into the hash. (This would be simpler, and is what
       the original version did, but it was too slow to be usable and  meant  that  the  tests  failed  on  many
       smaller  systems  as  part  of CPAN testing).  We do still use a hash, but only to cache lines that we've
       already found.  Read the code for details.  This only gives a tiny speed up in general, so I might remove
       it in future versions.

       Back in 2008, loading the array took about 1.2 seconds on my Windows machine (a 2.8G Hz Intel  Pentium  M
       processor  with 2G byte of memory) and just under 0.5 seconds on my Linux system (a 2.8G Hz Intel Pentium
       4 processor with 512M bytes of memory).  I think that probably said more about speed of the disks  I  had
       (and probably the efficiency of Perl under Linux) back then.  Today on my newish Mac Mini there is only a
       very slightly noticeable delay.  Once the data is loaded, calling the routines is reasonably quick.

BUGS

       Please report any to toby@cpan.org

EXAMPLES

       See the test routines included in the distribution.

AUTHOR

       Toby Thurston -- 04 Oct 2013

       toby@cpan.org

SEE ALSO

       See Geo::Coordinates::OSGB for the main routines.

perl v5.18.1                                       2013-10-04                      Geo::Coordinates::OSTN02(3pm)