Skip to content

Instantly share code, notes, and snippets.

@idlem1nd
Created September 25, 2014 10:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save idlem1nd/3257a0cf7f9cda19daff to your computer and use it in GitHub Desktop.
Save idlem1nd/3257a0cf7f9cda19daff to your computer and use it in GitHub Desktop.
Can convert WGS84 Lat/Lon to OSGB Eastings/Northings and vice-versa. Credit for original work goes to Jonathan Stott
using System;
public class LatLonConversion
{
private LatLonConversion() { }
private static double Deg2Rad(double x)
{
return x * (Math.PI / 180);
}
private static double Rad2Deg(double x)
{
return x * (180 / Math.PI);
}
private static double SinSquared(double x)
{
return Math.Sin(x) * Math.Sin(x);
}
private static double TanSquared(double x)
{
return Math.Tan(x) * Math.Tan(x);
}
private static double Sec(double x)
{
return 1.0 / Math.Cos(x);
}
private static LatLon Osgb36ToWgs84(double lat, double lng)
{
var airy1830 = new RefEll(6377563.396, 6356256.909);
var a = airy1830.Maj;
var eSquared = airy1830.Ecc;
var phi = Deg2Rad(lat);
var lambda = Deg2Rad(lng);
var v = a / (Math.Sqrt(1 - eSquared * SinSquared(phi)));
const int h = 0; // height
var x = (v + h) * Math.Cos(phi) * Math.Cos(lambda);
var y = (v + h) * Math.Cos(phi) * Math.Sin(lambda);
var z = ((1 - eSquared) * v + h) * Math.Sin(phi);
const double tx = 446.448;
const double ty = -124.157;
const double tz = 542.060;
const double s = -0.0000204894;
var rx = Deg2Rad(0.00004172222);
var ry = Deg2Rad(0.00006861111);
var rz = Deg2Rad(0.00023391666);
var xB = tx + (x * (1 + s)) + (-rx * y) + (ry * z);
var yB = ty + (rz * x) + (y * (1 + s)) + (-rx * z);
var zB = tz + (-ry * x) + (rx * y) + (z * (1 + s));
var wgs84 = new RefEll(6378137.000, 6356752.3141);
a = wgs84.Maj;
eSquared = wgs84.Ecc;
var lambdaB = Rad2Deg(Math.Atan(yB / xB));
var p = Math.Sqrt((xB * xB) + (yB * yB));
var phiN = Math.Atan(zB / (p * (1 - eSquared)));
for (var i = 1; i < 10; i++)
{
v = a / (Math.Sqrt(1 - eSquared * SinSquared(phiN)));
double phiN1 = Math.Atan((zB + (eSquared * v * Math.Sin(phiN))) / p);
phiN = phiN1;
}
var phiB = Rad2Deg(phiN);
return new LatLon(phiB, lambdaB);
}
public static LatLon ConvertOsToLatLon(double easting, double northing)
{
var airy1830 = new RefEll(6377563.396, 6356256.909);
const double osgbF0 = 0.9996012717;
const double n0 = -100000.0;
const double e0 = 400000.0;
var phi0 = Deg2Rad(49.0);
var lambda0 = Deg2Rad(-2.0);
var a = airy1830.Maj;
var b = airy1830.Min;
var eSquared = airy1830.Ecc;
var n = (a - b) / (a + b);
double m;
var phiPrime = ((northing - n0) / (a * osgbF0)) + phi0;
do
{
m =
(b * osgbF0)
* (((1 + n + ((5.0 / 4.0) * n * n) + ((5.0 / 4.0) * n * n * n))
* (phiPrime - phi0))
- (((3 * n) + (3 * n * n) + ((21.0 / 8.0) * n * n * n))
* Math.Sin(phiPrime - phi0)
* Math.Cos(phiPrime + phi0))
+ ((((15.0 / 8.0) * n * n) + ((15.0 / 8.0) * n * n * n))
* Math.Sin(2.0 * (phiPrime - phi0))
* Math.Cos(2.0 * (phiPrime + phi0)))
- (((35.0 / 24.0) * n * n * n)
* Math.Sin(3.0 * (phiPrime - phi0))
* Math.Cos(3.0 * (phiPrime + phi0))));
phiPrime += (northing - n0 - m) / (a * osgbF0);
} while ((northing - n0 - m) >= 0.001);
var v = a * osgbF0 * Math.Pow(1.0 - eSquared * SinSquared(phiPrime), -0.5);
var rho =
a
* osgbF0
* (1.0 - eSquared)
* Math.Pow(1.0 - eSquared * SinSquared(phiPrime), -1.5);
var etaSquared = (v / rho) - 1.0;
var vii = Math.Tan(phiPrime) / (2 * rho * v);
var viii =
(Math.Tan(phiPrime) / (24.0 * rho * Math.Pow(v, 3.0)))
* (5.0
+ (3.0 * TanSquared(phiPrime))
+ etaSquared
- (9.0 * TanSquared(phiPrime) * etaSquared));
var ix =
(Math.Tan(phiPrime) / (720.0 * rho * Math.Pow(v, 5.0)))
* (61.0
+ (90.0 * TanSquared(phiPrime))
+ (45.0 * TanSquared(phiPrime) * TanSquared(phiPrime)));
var x = Sec(phiPrime) / v;
var xi =
(Sec(phiPrime) / (6.0 * v * v * v))
* ((v / rho) + (2 * TanSquared(phiPrime)));
var xii =
(Sec(phiPrime) / (120.0 * Math.Pow(v, 5.0)))
* (5.0
+ (28.0 * TanSquared(phiPrime))
+ (24.0 * TanSquared(phiPrime) * TanSquared(phiPrime)));
var xiia =
(Sec(phiPrime) / (5040.0 * Math.Pow(v, 7.0)))
* (61.0
+ (662.0 * TanSquared(phiPrime))
+ (1320.0 * TanSquared(phiPrime) * TanSquared(phiPrime))
+ (720.0
* TanSquared(phiPrime)
* TanSquared(phiPrime)
* TanSquared(phiPrime)));
double phi = phiPrime
- (vii * Math.Pow(easting - e0, 2.0))
+ (viii * Math.Pow(easting - e0, 4.0))
- (ix * Math.Pow(easting - e0, 6.0));
double lambda = lambda0
+ (x * (easting - e0))
- (xi * Math.Pow(easting - e0, 3.0))
+ (xii * Math.Pow(easting - e0, 5.0))
- (xiia * Math.Pow(easting - e0, 7.0));
var lat = Rad2Deg(phi);
var lng = Rad2Deg(lambda);
// convert to WGS84
return Osgb36ToWgs84(lat, lng);
}
}
public class RefEll
{
public double Maj { get; set; }
public double Min { get; set; }
public double Ecc { get; set; }
public RefEll(double major, double minor)
{
Maj = major;
Min = minor;
Ecc = ((major * major) - (minor * minor)) / (major * major);
}
}
public class LatLon
{
public double Latitude { get; set; }
public double Longitude { get; set; }
public LatLon()
{
Latitude = 0;
Longitude = 0;
}
public LatLon(double lat, double lon)
{
Latitude = lat;
Longitude = lon;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment