Sunday, 28 January 2007

Converting OS Coodinates
into Longitude and Latitude

So, I've been doing some digging to try and work around the legal restrictions which mean that Google can't provide Longitude & Latitude for British Postcodes.

Preface: Geolocating Postcode Solution

I've found, so far, two legal sources of data which describes the geographical relationship of every postcode in the UK.

  • The Post Office: "PostZon" [ accuracy ~100m, cost ~£250 ]
    The British Post office does provide a list of every postcode ( >1.5Million ) with the geographical relationship of every code. However, these locations are rounded to the nearest 100 metres which, for the exacting user is simply not good enough.

    The reseller who seems to dominate associated adwords sells the data for £250 - not bad if you consider that's 60 postcodes for every penny!

    - The Post Office PostZon File

  • The Ordinance Survey: "Code-Point" [1m, £750+]
    The Ordinance Survey ( in association with a number of other UK Gov. Depts. it seems ) provides an alternate database of 1.7Million postcodes with a 'resolution' of 1metre.

    My understanding is that the figure given is the location of the property closest to the centre of the scatter of all the properties in the code, which seems about as good as it's going to get, short of giving you the locations of every one of the 26M properties. This also ensures that the code-point will be within the boundries of the scatter, whatever it's shape.

    This is a little more pricey, but worth it for the extra resolution. There are also some interesting extras; as well as things like NHS wards and such you get a number of business versus residential versus PO-Box delivery points within the code. Licenses start at £750 and range to ~£5.5k for 101+ users.

    - The Ordinance Survey Code-Point

The Catch! : Both provide "Northing" and "Easting"

The only catch is that both the OS and the PO provide their locations in what is known as Eastings and Northings. I shalln't go into a great deal of detail about these here as a number of sites/articles cited here explain it better than I can but in short this co-ordinating system stems from the UK Ordinance Survey maps of the country.

Use of Easting & Northing does not in of itself bring inaccuracy to mapping postcodes on something like Google Maps - these coordinates are exceedinly accurate - but translating between the two systems is not increadably simple.

There are two things you need to do here:

  1. Convert Easting & Northing to Longitude & Latitude

    This is the process of translating OS Coordinates like "264046", "192487", which as a GridRef looks like SN26401924 to their Lat/Long equivalents : 051°50′40″N, 004°31′13″W or, in decimal 51.61430, -3.96382

    There are a number of great online tools for demonstrating this; Chris Veness has published some javaScript here which shows how intricate just this little bit of maths is!
  2. Converting between Airy1830/OSGB36 and WGS84/GRS80

    What? Ok, so you have your latitude & longitude but when you compare these to Google's estimation of where a postcode lies you'll realise that you're a few blocks out!

    As I understand it it goes like this: The OS coordinates are based on a model of the shape of the Earth called the "Airy 1830 ellipsoid".

    Google Maps ( and GPS systems etc ) are based on a different model of the curvature of the Earth, developed - to be fair to George Airy - some 150 years later. This model - or "Datum" is called called WGS84

    It is this difference between the Datum used within the OS Coordinates and the Datum used by Google that causes the lats and longs to be out.

    According to Wikipedia longitude lines are our byt around 70 metres in Cornwall, rising to ~120metres on the east coast of East Anglia.

Fitting the square peg through the round hole.

I have therefore been trawling around looking for a solution for the next problem: how do we convert our Eastings and Northings into Longitude and Latitude that work with Google Maps?

First we need to convert East/North to Lat/Long.

Solution 1: Geo::Coordinates::OSGB ( Perl )

This is a perl module written by a chap called Toby Thurston. I've just found a png on his site which describes the problem very well: here

Result for SA1 4LS : 51.6143013958951, -3.96382366182886 ( Marker A )

Solution 2: Geography::NationalGrid::GB ( Perl )

Another perl module, this time written by a P Kent.

Now, solutions 1 & 2 both claim inaccuracies for mathematical and theoretical reasons. Interestingly though they do show exceedinly similar results ( a difference of around 1.5e-10 degrees ) which suggest to me that while written separately they have been written pretty exactingly to the same mathematical rules.

Result for SA1 4LS : 51.614301395634, -3.9638236618435 ( Marker A )

Solution 3: PHPcoord, JScoord, Jcoord ( php, javaScript & java )

This is a PHP library written by a chap called Jonathan Stott.

This solution has a couple of distinct advantages over the first two: that for many people doing this in PHP or javaScript would make more sense.. and because it both converts to Lat/Long and converts into the WGS84 Datum.

It also calculates distances which could be very handy.

Result for SA1 4LS (Airy1830) : 51.6143013965, -3.96382366167 ( Marker A )

Then we convert OSGB/Airy1830 to WGS84

Solution 1 : Geo::HelmertTransform ( perl )

A datum transformation module written by Chris Lightfoot.

This will take our Airy1830 Lat/Longs derived from our OS data and translate them to the WGS84 datum used by Google Maps

Result for SA1 4LS : 51.614743995912299, -3.964993028066230 ( Marker B )

Solution 2 : PHPcoord, JScoord, Jcoord ( php, javaScript & java )

Yup.. same libraries as above..

Result for SA1 4LS (Airy1830) : 51.6147522043, -3.96497954404 ( Marker C )

Putting all this together

I think this is probably far more easily explained on a map! .. so here it is:

  • A = Before transformation;
  • B = After transformation;
  • C = phpcoord, jcoord, jscoord's transformed answer ( which is so similar it's obscured by B );
  • X = Google's opinion of "SA1 4LS"

So.. is that it?

Well... yes... that's it: some solutions for turning Easting/Northing into Lat/Longs that can be used with Google Maps.

.. I just spent a long time banging my head against this so I thought it might help someone else if it were all in one place... or in yet another place!

( Incidentally, if anyone can explain why all the methods above agree on the position but Google's own estimate is different I'd be interested to hear. It seems ( having looked up the postcode in question ) that Marker "C" is in exactly the right spot so I'd be interested in understanding the discrepancy. )


barryhunter said...

Excellent Writeup! From a quick read looks good.

When I was doing something similar a few years ago, I ended up converting some code from the OS site to do the Helmert Transform, to go with Geography::NationalGrid::GB**, as didn't find Geo::HelmertTransform* at the time. Unfortunately never got round to tidying it up to be able to release the code :(

* I haven't looked in detail at this module, will see how it compares with mine - which IIRC coincides pretty well with PHPcoord.

** check the bug reports page for the module, as I fixed a few bugs I found, and added the fix there.

- As for Google's answer I believe they source the postcodes from Teleatlas, which uses its own datasource! (possibly based on PostZon, but certainly uses data from their street gazetteer)

- Barry

barryhunter said...

Checking, using your e/n numbers against Geography::NationalGrid::GB and my transformation:

51.614301 -3.963824 (OSGB36)
51.614745 -3.964993 (WGS84)

Matches pretty well with Geo::HelmertTransform - but still slightly different to PHPcoord.

Also a PHP solution converted from the OS website, matches:
51.614745270442,-3.9649930274528 (WGS84)

flp said...

Thanks for gathering this all in one place - perfect! :)

Anonymous said...

Thanks for the overview! Being trying to get my head around a massive DB of easting northing values all morning ;) now to cobvert them to lat long....