[Closed] Converting Coordinates from OsGrid to Lat Lon
I am trying to create a script that allows me to accurately convert Ordnance Survey Coordinates into Latitude and Longitude for use in a KML exporter. Here is the function I have created so far
function OSGridToLatLong East North =
(
Local a = 6377563.396, b = 6356256.910 -- Airy 1830 major & minor semi-axes
Local F0 = 0.9996012717 -- NatGrid scale factor on central meridian
Local lat0 = 49*PI/180, lon0 = -2*PI/180 -- NatGrid true origin
Local N0 = -100000, E0 = 400000 -- northing & easting of true origin, metres
Local e2 = 1 - (b*b)/(a*a) -- eccentricity squared
Local n = (a-b)/(a+b), n2 = n*n, n3 = n*n*n
Local lat=lat0, M=0
do (
lat = (North-N0-M)/(a*F0) + lat
Local Ma = (1 + n + (5/4)*n2 + (5/4)*n3) * (lat-lat0)
Local Mb = (3*n + 3*n*n + (21/8)*n3) * sin(lat-lat0) * cos(lat+lat0)
Local Mc = ((15/8)*n2 + (15/8)*n3) * sin(2*(lat-lat0)) * cos(2*(lat+lat0))
Local Md = (35/24)*n3 * sin(3*(lat-lat0)) * cos(3*(lat+lat0))
M = b * F0 * (Ma - Mb + Mc - Md) -- meridional arc
) while (North-N0-M >= 0.00001) -- ie until < 0.01mm
Local cosLat = cos(lat), sinLat = sin(lat)
Local nu = a*F0/sqrt(1-e2*sinLat*sinLat) -- transverse radius of curvature
Local rho = a*F0*(1-e2)/pow(1-e2*sinLat*sinLat) 1.5 -- meridional radius of curvature
Local eta2 = nu/rho-1
Local tanLat = tan(lat)
Local tan2lat = tanLat*tanLat, tan4lat = tan2lat*tan2lat, tan6lat = tan4lat*tan2lat
Local secLat = 1/cosLat
Local nu3 = nu*nu*nu, nu5 = nu3*nu*nu, nu7 = nu5*nu*nu
Local VII = tanLat/(2*rho*nu)
Local VIII = tanLat/(24*rho*nu3)*(5+3*tan2lat+eta2-9*tan2lat*eta2)
Local IX = tanLat/(720*rho*nu5)*(61+90*tan2lat+45*tan4lat)
Local X = secLat/nu
Local XI = secLat/(6*nu3)*(nu/rho+2*tan2lat)
Local XII = secLat/(120*nu5)*(5+28*tan2lat+24*tan4lat)
Local XIIA = secLat/(5040*nu7)*(61+662*tan2lat+1320*tan4lat+720*tan6lat)
Local dE = (East-E0), dE2 = dE*dE, dE3 = dE2*dE, dE4 = dE2*dE2, dE5 = dE3*dE2, dE6 = dE4*dE2, dE7 = dE5*dE2
lat = lat - VII*dE2 + VIII*dE4 - IX*dE6
Local lon = lon0 + X*dE - XI*dE3 + XII*dE5 - XIIA*dE7
return "[" + (formattedPrint (radtodeg lat) format: "12.12g")+ "," + (formattedPrint (radtodeg lon) format: "12.12g") + ",0]"
)
function convert p =
(
P1 = p
P1.x = degtorad p.x
P1.y = degtorad p.y
Local a = 6377563.396d0, b = 6356256.910d0
Local sinPhi = sin(p1.x), cosPhi = cos(p1.x)
Local sinLambda = sin(p1.y), cosLambda = cos(p1.y)
Local H = p1.z
Local eSq = (a*a - b*b) / (a*a)
Local nu = a / sqrt(1 - eSq*sinPhi*sinPhi)
Local x1 = (nu+H) * cosPhi * cosLambda
Local y1 = (nu+H) * cosPhi * sinLambda
Local z1 = ((1-eSq)*nu + H) * sinPhi
-- apply helmert transform using appropriate params
Local tx = 446.448, ty = -125.157, tz = 542.060
Local rx = 0.1502/3600 * PI/180 --normalise seconds to radians
Local ry = 0.2470/3600 * PI/180
Local rz = 0.8421/3600 * PI/180
Local s1 = -20.4894/1e6 + 1 -- normalise ppm to (s+1)
--apply transform
Local x2 = tx + x1*s1 - y1*rz + z1*ry
Local y2 = ty + x1*rz + y1*s1 - z1*rx
Local z2 = tz - x1*ry + y1*rx + z1*s1
-- convert cartesian to polar coordinates (using ellipse 2)
a = 6378137d0
b = 6356752.3142d0
Local precision = 4 / a --results accurate to around 4 metres
eSq = (a*a - b*b) / (a*a)
Local p = sqrt(x2*x2 + y2*y2)
Local phi = atan2 z2 (p*(1-eSq))
Local phiP = 2*PI
do
(
nu = a / sqrt(1 - eSq*sin(phi)*sin(phi))
phiP = phi
phi = atan2 (z2 + eSq*nu*sin(phi)) p
) while (abs(phi-phiP) > precision)
Local lambda = atan2 y2 x2
H = p/cos(phi) - nu
return #(radtodeg phi, radtodeg lambda, H)
)
convert (execute (OSGridToLatLong 530000 180000))
The maths of which were taken from http://www.movable-type.co.uk/scripts/latlong-gridref.html
However I seem to be experiencing mathematical inaccuracies from the above script? With easting:530000 and Northing:180000 I would expect to return:
easting: 51.503992°
Northing: 0.128329°
(As converted from here http://www.ordnancesurvey.co.uk/gps/transformation )
Instead I seem to return:
easting: 51.7955°
Northing: -0.882482°
Does anybody have any ideas as to what could be causing the inaccuracies? Could it be to do with single-precision floating point?
Any thoughts would be most appreciated.