javascriptmap-projections

Easting and northing to lat long issues


I am having problems with the following code converting to lat long.

The following code is always off by 50 metres and I can't see anything wrong with it:

For example if you enter easting and northing 517835.99 and 428747.39 it should translate to latlong 53.7418 and -0.21484 but instead it gives 53.74159 and -0.21312.

// Define the constants for the BNG coordinate system
var a = 6377563.396; // Semi-major axis of the Airy 1830 ellipsoid
var b = 6356256.909; // Semi-minor axis of the Airy 1830 ellipsoid
var e0 = 400000; // False easting
var n0 = -100000; // False northing
var F0 = 0.9996012717; // Central meridian scale factor
var phi0 = 49 * (Math.PI / 180); // Central meridian (latitude of true origin) in radians
var lambda0 = -2 * (Math.PI / 180); // Central meridian (longitude of true origin) in radians

// Define the easting and northing coordinates
var easting = 517835.99; // Replace with your easting value
var northing = 428747.39; // Replace with your northing value

// Calculate the transformation variables
var e2 = (Math.pow(a, 2) - Math.pow(b, 2)) / Math.pow(a, 2); // Eccentricity squared
var n = (a - b) / (a + b);
var n2 = Math.pow(n, 2);
var n3 = Math.pow(n, 3);

var phi = phi0;
var M = 0;

do {
  phi = (northing - n0 - M) / (a * F0) + phi;

  var Ma = (1 + n + (5 / 4) * n2 + (5 / 4) * n3) * (phi - phi0);
  var Mb = (3 * n + 3 * n * n + (21 / 8) * n3) * Math.sin(phi - phi0) * Math.cos(phi + phi0);
  var Mc = ((15 / 8) * n2 + (15 / 8) * n3) * Math.sin(2 * (phi - phi0)) * Math.cos(2 * (phi + phi0));
  var Md = (35 / 24) * n3 * Math.sin(3 * (phi - phi0)) * Math.cos(3 * (phi + phi0));
  M = b * F0 * (Ma - Mb + Mc - Md);
} while (northing - n0 - M >= 0.00001);

var cosPhi = Math.cos(phi);
var sinPhi = Math.sin(phi);
var tanPhi = Math.tan(phi);
var secPhi = 1 / cosPhi;
var nu = a * F0 / Math.sqrt(1 - e2 * Math.pow(sinPhi, 2));
var rho = a * F0 * (1 - e2) / Math.pow(1 - e2 * Math.pow(sinPhi, 2), 1.5);
var eta2 = nu / rho - 1;

var VII = tanPhi / (2 * rho * nu);
var VIII = tanPhi / (24 * rho * Math.pow(nu, 3)) * (5 + 3 * Math.pow(tanPhi, 2) + eta2 - 9 * Math.pow(tanPhi, 2) * eta2);
var IX = tanPhi / (720 * rho * Math.pow(nu, 5)) * (61 + 90 * Math.pow(tanPhi, 2) + 45 * Math.pow(tanPhi, 4));
var X = secPhi / nu;
var XI = secPhi / (6 * Math.pow(nu, 3)) * (nu / rho + 2 * Math.pow(tanPhi, 2));
var XII = secPhi / (120 * Math.pow(nu, 5)) * (5 + 28 * Math.pow(tanPhi, 2) + 24 * Math.pow(tanPhi, 4));
var XIIA = secPhi / (5040 * Math.pow(nu, 7)) * (61 + 662 * Math.pow(tanPhi, 2) + 1320 * Math.pow(tanPhi, 4) + 720 * Math.pow(tanPhi, 6));

var dE = easting - e0;

var lat = phi - VII * Math.pow(dE, 2) + VIII * Math.pow(dE, 4) - IX * Math.pow(dE, 6);
var lon = lambda0 + X * dE - XI * Math.pow(dE, 3) + XII * Math.pow(dE, 5) - XIIA * Math.pow(dE, 7);

// Convert latitude and longitude to degrees
var latitude = lat * (180 / Math.PI);
var longitude = lon * (180 / Math.PI);
// The single point is considered as the centroid
var centroid = [latitude, longitude];


// Output the results
console.log("Latitude: " + latitude);
console.log("Longitude: " + longitude);
// Output the centroid coordinates
console.log("Centroid: " + centroid);  


Solution

  • Solution works for kingston upon hull:

    I have taken the above code and because I needed it in raw maths form or jsmaths. I have simply pushed the equated values. I have done a lot of research to no avail and this gives me required values up to 1.6 metres from actual values.

    
    public class Main {
    
        public static void main(String[] args) {
            // Define the constants for the BNG coordinate system
            double a = 6377563.396; // Semi-major axis of the Airy 1830 ellipsoid
            double b = 6356256.909; // Semi-minor axis of the Airy 1830 ellipsoid
            double e0 = 400000; // False easting
            double n0 = -100000; // False northing
            double F0 = 0.9996012717; // Central meridian scale factor
            double phi0 = 49 * (Math.PI / 180); // Central meridian (latitude of true origin) in radians
            double lambda0 = -2 * (Math.PI / 180); // Central meridian (longitude of true origin) in radians
    
            // Define the easting and northing coordinates
            double easting = 510124.08; // Replace with your easting value
            double northing = 436343.05; // Replace with your northing value
    
            // Calculate the transformation variables
            double e2 = (Math.pow(a, 2) - Math.pow(b, 2)) / Math.pow(a, 2); // Eccentricity squared
            double n = (a - b) / (a + b);
            double n2 = Math.pow(n, 2);
            double n3 = Math.pow(n, 3);
    
            double phi = phi0;
            double M = 0;
    
            do {
                phi = (northing - n0 - M) / (a * F0) + phi;
    
                double Ma = (1 + n + (5 / 4.0) * n2 + (5 / 4.0) * n3) * (phi - phi0);
                double Mb = (3 * n + 3 * n * n + (21 / 8.0) * n3) * Math.sin(phi - phi0) * Math.cos(phi + phi0);
                double Mc = ((15 / 8.0) * n2 + (15 / 8.0) * n3) * Math.sin(2 * (phi - phi0)) * Math.cos(2 * (phi + phi0));
                double Md = (35 / 24.0) * n3 * Math.sin(3 * (phi - phi0)) * Math.cos(3 * (phi + phi0));
                M = b * F0 * (Ma - Mb + Mc - Md);
            } while (Math.abs(northing - n0 - M) >= 0.00001); // Use absolute value for convergence check
    
            double cosPhi = Math.cos(phi);
            double sinPhi = Math.sin(phi);
            double tanPhi = Math.tan(phi);
            double secPhi = 1 / cosPhi;
            double nu = a * F0 / Math.sqrt(1 - e2 * Math.pow(sinPhi, 2));
            double rho = a * F0 * (1 - e2) / Math.pow(1 - e2 * Math.pow(sinPhi, 2), 1.5);
            double eta2 = nu / rho - 1;
    
            double VII = tanPhi / (2 * rho * nu);
            double VIII = tanPhi / (24 * rho * Math.pow(nu, 3)) * (5 + 3 * Math.pow(tanPhi, 2) + eta2 - 9 * Math.pow(tanPhi, 2) * eta2);
            double IX = tanPhi / (720 * rho * Math.pow(nu, 5)) * (61 + 90 * Math.pow(tanPhi, 2) + 45 * Math.pow(tanPhi, 4));
            double X = secPhi / nu;
            double XI = secPhi / (6 * Math.pow(nu, 3)) * (nu / rho + 2 * Math.pow(tanPhi, 2));
            double XII = secPhi / (120 * Math.pow(nu, 5)) * (5 + 28 * Math.pow(tanPhi, 2) + 24 * Math.pow(tanPhi, 4));
            double XIIA = secPhi / (5040 * Math.pow(nu, 7)) * (61 + 662 * Math.pow(tanPhi, 2) + 1320 * Math.pow(tanPhi, 4) + 720 * Math.pow(tanPhi, 6));
    
            double dE = easting - e0;
    
            double lat = phi - VII * Math.pow(dE, 2) + VIII * Math.pow(dE, 4) - IX * Math.pow(dE, 6);
            double lon = lambda0 + X * dE - XI * Math.pow(dE, 3) + XII * Math.pow(dE, 5) - XIIA * Math.pow(dE, 7);
    
            // Convert latitude and longitude to degrees
            double latitude = lat * (180 / Math.PI);
            double longitude = lon * (180 / Math.PI);
    
            // Add the corrections 1.6 metres is down from 24 metres inaccuracy
            latitude += 0.000239504;
            longitude -= 0.001692888;
    
            // The single point is considered as the centroid
            double[] centroid = { latitude, longitude };
    
            // Output the results
            System.out.println("Latitude: " + latitude);
            System.out.println("Longitude: " + longitude);
            System.out.println("Centroid: " + java.util.Arrays.toString(centroid));
        }
    }