Convert WGS84 to OSGB36

2019-08-23 05:05发布

问题:

Is there any known java library which allows me to convert WGS 84 cords to OSGB36 or if there is a good formula I can use? I am currently using this one, but it's not very accurate so I'm wondering if there's a better one I can use.

private static double[] Wgs84ToBNG(double inLat, double inLon) {

    double lat = inLat * Math.PI / 180.0;
    double lon = inLon * Math.PI / 180.0;
    double a = 6377563.396; // Airy 1830 major & minor semi-axes
    double b = 6356256.910;
    double F0 = 0.9996012717; // NatGrid scale factor on central meridian
    double lat0 = 49 * Math.PI / 180.0; // NatGrid true origin
    double lon0 = -2 * Math.PI / 180.0;
    double N0 = -100000; // northing & easting of true origin, metres
    double E0 = 400000;
    double e2 = 1 - (b * b) / (a * a); // eccentricity squared
    double n = (a - b) / (a + b), n2 = n * n, n3 = n * n * n;
    double cosLat = Math.cos(lat), sinLat = Math.sin(lat);
    double nu = a * F0 / Math.sqrt(1 - e2 * sinLat * sinLat); // transverse
                                                                // radius of
                                                                // curvature
    double rho = a * F0 * (1 - e2)
            / Math.pow(1 - e2 * sinLat * sinLat, 1.5); // meridional radius
                                                        // of curvature
    double eta2 = nu / rho - 1;
    double Ma = (1 + n + (5 / 4) * n2 + (5 / 4) * n3) * (lat - lat0);
    double Mb = (3 * n + 3 * n * n + (21 / 8) * n3) * Math.sin(lat - lat0)
            * Math.cos(lat + lat0);
    double Mc = ((15 / 8) * n2 + (15 / 8) * n3)
            * Math.sin(2 * (lat - lat0)) * Math.cos(2 * (lat + lat0));
    double Md = (35 / 24) * n3 * Math.sin(3 * (lat - lat0))
            * Math.cos(3 * (lat + lat0));
    double M = b * F0 * (Ma - Mb + Mc - Md); // meridional arc
    double cos3lat = cosLat * cosLat * cosLat;
    double cos5lat = cos3lat * cosLat * cosLat;
    double tan2lat = Math.tan(lat) * Math.tan(lat);
    double tan4lat = tan2lat * tan2lat;
    double I = M + N0;
    double II = (nu / 2) * sinLat * cosLat;
    double III = (nu / 24) * sinLat * cos3lat * (5 - tan2lat + 9 * eta2);
    double IIIA = (nu / 720) * sinLat * cos5lat
            * (61 - 58 * tan2lat + tan4lat);
    double IV = nu * cosLat;
    double V = (nu / 6) * cos3lat * (nu / rho - tan2lat);
    double VI = (nu / 120)
            * cos5lat
            * (5 - 18 * tan2lat + tan4lat + 14 * eta2 - 58 * tan2lat * eta2);
    double dLon = lon - lon0;
    double dLon2 = dLon * dLon;
    double dLon3 = dLon2 * dLon;
    double dLon4 = dLon3 * dLon;
    double dLon5 = dLon4 * dLon;
    double dLon6 = dLon5 * dLon;
    double N = I + II * dLon2 + III * dLon4 + IIIA * dLon6;
    double E = E0 + IV * dLon + V * dLon3 + VI * dLon5;
    double[] returnValue = { E, N };
    return returnValue;
} 

回答1:

Have a look at this page

In the section "Programs/Source Code" you will find a subsection entitled "WGS84 Lat/Long <=> OSGB36 Grid References". In this subsection there are several links to utilities providing this functionality.

In this other post you can find the source code for such a task with explanations.



回答2:

If you are unsure about the correctness of other libraries I would compare results with PROJ.4. If you don't want to use the native lib there is also a pure Java port for PROJ.4 out there.

Using PROJ.4 for WGS84 Lat/Long <=> OSGB36 has been discussed here:
PROJ.4 library and OSGB36

Using cs2cs:
http://trac.osgeo.org/proj/wiki/man_cs2cs
OSGB36 string:
http://spatialreference.org/ref/epsg/27700/proj4/
WGS84 string:
http://spatialreference.org/ref/epsg/4326/proj4/

Java Port:
http://sourceforge.net/projects/jmapprojlib/



回答3:

I've done a bit of work on this and have used the document A guide to coordinate systems in Great Britain It tells you all you need to know if you read it carefully. From the look of the variable names used in your formula you may well have studied the same document. I think the most important paragraph in the whole document relating to converting between coordinate systems is this (from the bottom of page 30)

To summarise: For a simple datum change of latitude and longitude coordinates from datum A to datum B, first convert to Cartesian coordinates (formulae in annexe B), taking all ellipsoid heights as zero and using the ellipsoid parameters of datum A; then apply a Helmert transformation from datum A to datum B using equation (3); finally convert back to latitude and longitude using the ellipsoid parameters of datum B (formulae in annexe C), discarding the datum B ellipsoid height.

It describes the 3 steps you have to take. The formula you have quoted will convert a latitude/longitude to an easting/northing in the same datum. It's not a transformation

From the naming of your method you are passing WGS84 lat/lon in, so you should:

1) Put all thoughts of a grid reference system (and associated true origins etc) out of your mind until you have converted the lat/lon from one datum to the other

2) Convert that WGS84 lat/lon into the 3D Cartesians (that's the x, y and z) for the WGS84 datum, using the formulae B1 to B5 in the OS Guide. Make sure you use the parameters (major/minor axes) for the WGS84 datum

3) Using the Helmert transformation referred to, convert the Cartesians you've just calculated into Cartesians relative to the Airy 1830 ellipsoid. You'll find the 7 parameters you need to get the new Cartesians in section 6.6

The new coordinates xGB, yGB, zGB are:

double xGB = tx + (x * (1 + s)) + (-rz * y) + (ry * z);
double yGB = ty + (rz * x) + (y * (1 + s)) + (-rx * z);
double zGB = tz + (-ry * x) + (rx * y) + (z * (1 + s));

They don't actually spell that out, they just assume you remember your matrix maths

4) Now convert those new Cartesians (which are relative to the OSGB36 datum) into a lat/lon relative to that OSGB36 datum using formulae B6 to B8

From here you can go on to work out grid eastings and northings using that formula you have quoted



回答4:

I have used jcoord. Very useful and simple to implement.