Converting Northings Eastings (Cartesian) to Coordinates (Latitude / Longitude) in PHP

December 28th 2012

I work quite a lot with location based information. More often than not (don't ask why) I get given geographical references in Northings and Eastings (known as Cartesian) rather than latitude and longitude.

After a long time a friend of mine sent me over the calculations to convert cartesian northings and eastings into latitude and longitude in PHP.

Here's the class I use to convert these values:

PHP Code:
<?php
/**
 * App_Coordinates_From_Cartesian, a geographical class
 *
 * ******************************************************************
 *
 * Converts Cartesian geographical values into geographic coordinates
 *
 * ******************************************************************
 *
 * @author Roger E Thomas
 * @package App_
 * @subpackage App_Coordinates_From_
 * @copyright 2012 Roger E Thomas | http://www.rogerethomas.com
 *
 * ******************************************************************
 *
 *
 */
class App_Coordinates_From_Cartesian {

    
/**
     * Holds the final Latitude
     * @var Integer
     */
    
public $latitude;

    
/**
     * Holds the final Longitude
     * @var Integer
     */
    
public $longitude;

    
/**
     * Holds the initial easting
     * @var Integer
     */
    
public $easting;

    
/**
     * Holds the initial northing
     * @var Integer
     */
    
public $northing;

    function 
__construct($easting$northing)
    {
        if (
is_int($easting) && is_int($northing)) {
            
$this->easting $easting;
            
$this->northing $northing;
        }
        else {
            
$this->easting $easting;
            
$this->northing $northing;
        }
    }

    
/**
     * Uses the $this->northing and $this->easting set in __construct to return the
     * latitude and longitude of the final point.
     * @return array
     */
    
function Convert() {

        
$East $this->easting;
        
$North $this->northing;
        if (
$East == "" || $East == || $North == "" || $North == 0) {
            
$this->latitude 0;
            
$this->longitude 0;
            return array(
'latitude' => 0'longitude' => 0);
        }

        
$a  6377563.396// Semi-major axis, a
        
$b  6356256.910//Semi-minor axis, b
        
$e0 400000.000//True origin Easting, E0
        
$n0 = -100000.000//True origin Northing, N0
        
$f0 0.999601271700//Central Meridan Scale, F0

        
$PHI0 49.0// True origin latitude, j0
        
$LAM0 = -2.0// True origin longitude, l0

        //Convert angle measures to radians
        
$RadPHI0 $PHI0 * (M_PI 180);
        
$RadLAM0 $LAM0 * (M_PI 180);

        
//Compute af0, bf0, e squared (e2), n and Et
        
$af0 $a $f0;
        
$bf0 $b $f0;
        
$e2 = ($af0*$af0 $bf0*$bf0 ) / ($af0*$af0);
        
$n = ($af0 $bf0) / ($af0 $bf0);
        
$Et $East $e0;

        
//Compute initial value for latitude (PHI) in radians
        
$PHId $this->_initialLatitude($North$n0$af0$RadPHI0$n$bf0);

        
$sinPHId2 pow(sin($PHId),  2);
        
$cosPHId  pow(cos($PHId), -1);

        
$tanPHId  tan($PHId);
        
$tanPHId2 pow($tanPHId2);
        
$tanPHId4 pow($tanPHId4);
        
$tanPHId6 pow($tanPHId6);

        
//Compute nu, rho and eta2 using value for PHId
        
$nu $af0 / (sqrt(- ($e2 $sinPHId2)));
        
$rho = ($nu * ($e2)) / ($e2 $sinPHId2);
        
$eta2 = ($nu $rho) - 1;

        
//Compute Longitude
        
$X    $cosPHId $nu;
        
$XI   $cosPHId / (   pow($nu3)) * (($nu $rho)         +  $tanPHId2);
        
$XII  $cosPHId / ( 120 pow($nu5)) * (5  28 $tanPHId2  24 $tanPHId4);
        
$XIIA $cosPHId / (5040 pow($nu7)) * (61 662 $tanPHId2 1320 $tanPHId4 720 $tanPHId6);

        
$VII  $tanPHId / (  $rho $nu);
        
$VIII $tanPHId / ( 24 $rho pow($nu3)) * ( +  $tanPHId2 $eta2 $eta2 $tanPHId2 );
        
$IX   $tanPHId / (720 $rho pow($nu5)) * (61 90 $tanPHId2 45 $tanPHId4 );

        
$long = (180 M_PI) * ($RadLAM0 + ($Et $X) - pow($Et,3) * $XI pow($Et,5) * $XII pow($Et,7) * $XIIA);
        
$lat  = (180 M_PI) * ($PHId - (pow($Et,2) * $VII) + (pow($Et4) * $VIII) - (pow($Et6) * $IX));

        
$this->latitude $lat;

        
$this->longitude $long;

        return array(
'latitude' => $lat'longitude' => $long);
    }

    
/**
     * Helper function to compute meridional arc.
     * @param $bf0 ellipsoid semi major axis multiplied by central meridian scale factor (bf0) in meters;
     * @param $n n (computed from a, b and f0);
     * @param $PHI0 lat of false origin
     * @param $PHI initial or final latitude of point IN RADIANS.
     */
    
private function _meridianArc($bf0$n$PHI0$PHI) {
        
$n2 pow($n2);
        
$n3 pow($n3);
        
$ans  = (($n + ((4) * ($n2)) + ((4) * $n3)) * ($PHI $PHI0));
        
$ans -= ((($n) + ($n2) + ((21 8) * $n3)) * (sin($PHI $PHI0)) * (cos($PHI $PHI0)));
        
$ans += ((((15 8) * $n2) + ((15 8) * $n3)) * (sin(* ($PHI $PHI0))) * (cos(* ($PHI $PHI0))));
        
$ans -= (((35 24) * $n3) * (sin(* ($PHI $PHI0))) * (cos(* ($PHI $PHI0))));
        return 
$bf0 $ans;
    }

    
/**
     * Helper function to compute initial value for Latitude IN RADIANS.
     * @param $North northing of point
     * @param $n0 northing of false origin in meters;
     * @param $afo semi major axis multiplied by central meridian scale factor in meters;
     * @param $PHI0 latitude of false origin IN RADIANS;
     * @param $n computed from a, b and f0
     * @param $bfo ellipsoid semi major axis multiplied by central meridian scale factor in meters.
     */
    
private function _initialLatitude($North$n0$afo$PHI0$n$bfo) {


        
//First PHI value (PHI1)
        
$PHI1 = (($North $n0) / $afo) + $PHI0;

        
//Calculate M
        
$M $this->_meridianArc($bfo$n$PHI0$PHI1);

        
//Calculate new PHI value (PHI2)
        
$PHI2 = (($North $n0 $M) / $afo) + $PHI1;

        
//Iterate to get final value for InitialLat
        
while ( abs($North $n0 $M) > 0.00001 ) {
            
$PHI2 = (($North $n0 $M) / $afo) + $PHI1;
            
$M $this->_meridianArc($bfo$n$PHI0$PHI2);
            
$PHI1 $PHI2;
        }

        return 
$PHI2;
    }

}

To use the class all you need to know are the northings and eastings.

PHP Code:
<?php
$class 
= new App_Coordinates_From_Cartesian(464343100366);
$result $class->Convert();
var_dump($result);

// array(2) {
//   ["latitude"]=>
//   float(50.798714617948)
//   ["longitude"]=>
//   float(-1.0868854103489)
// }

You can see that the return from convert is an array containing 2 keys. latitude and longitude!

The returned values point to somewhere in Portsmouth. http://maps.google.co.uk/maps?q=50.798714617948+-1.0868854103489

Regardless of those northings and eastings, the fact that we get the correct latitude and longitude back is a big plus.

Let me know if this helps you out (or if you manage to simplify the calculations).

Joaquim commented on Jan 22nd 2013

TYVM you've solved all my porbmles

Muhammad Saleem commented on Apr 12th 2013

Hello Roger,
I am facing a problem in converting Grid Northing and Easting usually used in topomaps, expressed in yards or meters. It is differnt from UTM. I totally can't understand.
2312500E & 638000N
I will be thankful if you help me out to convert these values in Lat/long.

Regards,

MS