Question

I'm making a PHP application involving Google Maps. Maps only accepts lat&lng pairs, and the data I want to display comes only with UTM style coordinates. Is there an open-source PHP function to convert from one to the other?

Something like this would be great:

$UTM_ZONE = '32';
$UTMX = '60329834,34';
$UTMY = '67382984,9';

$latlng = convert($UTM_ZONE, $UTMX, $UTMY);

// $latlng = now looks like
// array('lat' => '59.4472917501', 'lng' => '5.3928572425')
Was it helpful?

Solution 2

I've found sort of a dirty class that does the job. By dirty I mean that the function names are wonky and the code isn't very prettily formatted, but it does indeed do the job.

I'll be sure to update this answer if I find any better classes

OTHER TIPS

Here is the code in PHP, thanks a lot, works nice !

<?php
function ToLL($north, $east, $utmZone)
{ 
  // This is the lambda knot value in the reference
  $LngOrigin = Deg2Rad($utmZone * 6 - 183);

  // The following set of class constants define characteristics of the
  // ellipsoid, as defined my the WGS84 datum.  These values need to be
  // changed if a different dataum is used.    

  $FalseNorth = 0;   // South or North?
  //if (lat < 0.) FalseNorth = 10000000.  // South or North?
  //else          FalseNorth = 0.   

  $Ecc = 0.081819190842622;       // Eccentricity
  $EccSq = $Ecc * $Ecc;
  $Ecc2Sq = $EccSq / (1. - $EccSq);
  $Ecc2 = sqrt($Ecc2Sq);      // Secondary eccentricity
  $E1 = ( 1 - sqrt(1-$EccSq) ) / ( 1 + sqrt(1-$EccSq) );
  $E12 = $E1 * $E1;
  $E13 = $E12 * $E1;
  $E14 = $E13 * $E1;

  $SemiMajor = 6378137.0;         // Ellipsoidal semi-major axis (Meters)
  $FalseEast = 500000.0;          // UTM East bias (Meters)
  $ScaleFactor = 0.9996;          // Scale at natural origin

  // Calculate the Cassini projection parameters

  $M1 = ($north - $FalseNorth) / $ScaleFactor;
  $Mu1 = $M1 / ( $SemiMajor * (1 - $EccSq/4.0 - 3.0*$EccSq*$EccSq/64.0 - 5.0*$EccSq*$EccSq*$EccSq/256.0) );

  $Phi1 = $Mu1 + (3.0*$E1/2.0 - 27.0*$E13/32.0) * sin(2.0*$Mu1);
    + (21.0*$E12/16.0 - 55.0*$E14/32.0)           * sin(4.0*$Mu1);
    + (151.0*$E13/96.0)                          * sin(6.0*$Mu1);
    + (1097.0*$E14/512.0)                        * sin(8.0*$Mu1);

  $sin2phi1 = sin($Phi1) * sin($Phi1);
  $Rho1 = ($SemiMajor * (1.0-$EccSq) ) / pow(1.0-$EccSq*$sin2phi1,1.5);
  $Nu1 = $SemiMajor / sqrt(1.0-$EccSq*$sin2phi1);

  // Compute parameters as defined in the POSC specification.  T, C and D

  $T1 = tan($Phi1) * tan($Phi1);
  $T12 = $T1 * $T1;
  $C1 = $Ecc2Sq * cos($Phi1) * cos($Phi1);
  $C12 = $C1 * $C1;
  $D  = ($east - $FalseEast) / ($ScaleFactor * $Nu1);
  $D2 = $D * $D;
  $D3 = $D2 * $D;
  $D4 = $D3 * $D;
  $D5 = $D4 * $D;
  $D6 = $D5 * $D;

  // Compute the Latitude and Longitude and convert to degrees
  $lat = $Phi1 - $Nu1*tan($Phi1)/$Rho1 * ( $D2/2.0 - (5.0 + 3.0*$T1 + 10.0*$C1 - 4.0*$C12 - 9.0*$Ecc2Sq)*$D4/24.0 + (61.0 + 90.0*$T1 + 298.0*$C1 + 45.0*$T12 - 252.0*$Ecc2Sq - 3.0*$C12)*$D6/720.0 );

  $lat = Rad2Deg($lat);

  $lon = $LngOrigin + ($D - (1.0 + 2.0*$T1 + $C1)*$D3/6.0 + (5.0 - 2.0*$C1 + 28.0*$T1 - 3.0*$C12 + 8.0*$Ecc2Sq + 24.0*$T12)*$D5/120.0) / cos($Phi1);

  $lon = Rad2Deg($lon);

  // Create a object to store the calculated Latitude and Longitude values
  $PC_LatLon['lat'] = $lat;
  $PC_LatLon['lon'] = $lon;

  // Returns a PC_LatLon object
  return $PC_LatLon;
}

?>

I know it's late to answer this question but since I couldn't use any of the above codes, I wrote my own version which is actually very easy to use. This is the address: https://github.com/maroofi/coordinates To convert UTM to LatLong:

utm2ll(729286.9550018794,4021544.8279992654,40,true); 

output:

{"success":true,"attr":{"lat":36.311665575271,"lon":59.553858137274}} 

To convert LatLong to UTM:

ll2utm(36.311665575277935,59.55385813725379);

output:

{"success":true,"attr":{"x":729286.95500188,"y":4021544.8279993,"zone":40,"aboveEquator":true}} 

Hope it helps.

You asked for PHP, but here is javascript. Just throw in some '$' and you should be good ;). This returns Lat/Lon in WGS84. No warranties, use at your own risk.

////////////////////////////////////////////////////////////////////////////////////////////
//
// ToLL - function to compute Latitude and Longitude given UTM Northing and Easting in meters
//
//  Description:
//    This function converts input north and east coordinates (meters)
//    to the corresponding WGS84 Lat/Lon values relative to the defined
//    UTM zone.  
//
//  Parameters:
//    north   - (i) Northing (meters)
//    east    - (i) Easting (meters)
//    utmZone - (i) UTM Zone of the North and East parameters
//    lat     - (o) Latitude in degrees 
//    lon     - (o) Longitude in degrees
//
function ToLL(north,east,utmZone)
{ 
  // This is the lambda knot value in the reference
  var LngOrigin = DegToRad(utmZone * 6 - 183)

  // The following set of class constants define characteristics of the
  // ellipsoid, as defined my the WGS84 datum.  These values need to be
  // changed if a different dataum is used.    

  var FalseNorth = 0.   // South or North?
  //if (lat < 0.) FalseNorth = 10000000.  // South or North?
  //else          FalseNorth = 0.   

  var Ecc = 0.081819190842622       // Eccentricity
  var EccSq = Ecc * Ecc
  var Ecc2Sq = EccSq / (1. - EccSq)
  var Ecc2 = Math.sqrt(Ecc2Sq)      // Secondary eccentricity
  var E1 = ( 1 - Math.sqrt(1-EccSq) ) / ( 1 + Math.sqrt(1-EccSq) )
  var E12 = E1 * E1
  var E13 = E12 * E1
  var E14 = E13 * E1

  var SemiMajor = 6378137.0         // Ellipsoidal semi-major axis (Meters)
  var FalseEast = 500000.0          // UTM East bias (Meters)
  var ScaleFactor = 0.9996          // Scale at natural origin

  // Calculate the Cassini projection parameters

  var M1 = (north - FalseNorth) / ScaleFactor
  var Mu1 = M1 / ( SemiMajor * (1 - EccSq/4.0 - 3.0*EccSq*EccSq/64.0 -
    5.0*EccSq*EccSq*EccSq/256.0) )

  var Phi1 = Mu1 + (3.0*E1/2.0 - 27.0*E13/32.0) * Math.sin(2.0*Mu1)
    + (21.0*E12/16.0 - 55.0*E14/32.0)           * Math.sin(4.0*Mu1)
    + (151.0*E13/96.0)                          * Math.sin(6.0*Mu1)
    + (1097.0*E14/512.0)                        * Math.sin(8.0*Mu1)

  var sin2phi1 = Math.sin(Phi1) * Math.sin(Phi1)
  var Rho1 = (SemiMajor * (1.0-EccSq) ) / Math.pow(1.0-EccSq*sin2phi1,1.5)
  var Nu1 = SemiMajor / Math.sqrt(1.0-EccSq*sin2phi1)

  // Compute parameters as defined in the POSC specification.  T, C and D

  var T1 = Math.tan(Phi1) * Math.tan(Phi1)
  var T12 = T1 * T1
  var C1 = Ecc2Sq * Math.cos(Phi1) * Math.cos(Phi1)
  var C12 = C1 * C1
  var D  = (east - FalseEast) / (ScaleFactor * Nu1)
  var D2 = D * D
  var D3 = D2 * D
  var D4 = D3 * D
  var D5 = D4 * D
  var D6 = D5 * D

  // Compute the Latitude and Longitude and convert to degrees
  var lat = Phi1 - Nu1*Math.tan(Phi1)/Rho1 *
    ( D2/2.0 - (5.0 + 3.0*T1 + 10.0*C1 - 4.0*C12 - 9.0*Ecc2Sq)*D4/24.0
     + (61.0 + 90.0*T1 + 298.0*C1 + 45.0*T12 - 252.0*Ecc2Sq - 3.0*C12)*D6/720.0 )

  lat = RadToDeg(lat)

  var lon = LngOrigin + 
    ( D - (1.0 + 2.0*T1 + C1)*D3/6.0
      + (5.0 - 2.0*C1 + 28.0*T1 - 3.0*C12 + 8.0*Ecc2Sq + 24.0*T12)*D5/120.0) /     Math.cos(Phi1)

  lon = RadToDeg(lon)

  // Create a object to store the calculated Latitude and Longitude values
  var sendLatLon = new PC_LatLon(lat,lon)

  // Returns a PC_LatLon object
  return sendLatLon
}

The results from the script posted is a little of what i expected, but i found a tool on http://www.uwgb.edu/dutchs/usefuldata/ConvertUTMNoOZ.HTM which give me the results i expect. I have made a PHP version of it here: https://gist.github.com/datagutten/8083549

source link

<?php
function LatLonPointUTMtoLL($f, $f1, $j = 32) {

    $d = 0.99960000000000004;
    $d1 = 6378137;
    $d2 = 0.0066943799999999998;

    $d4 = (1 - sqrt(1 - $d2)) / (1 + sqrt(1 - $d2));
    $d15 = $f1 - 500000;
    $d16 = $f;
    $d11 = (($j - 1) * 6 - 180) + 3;
    $d3 = $d2 / (1 - $d2);
    $d10 = $d16 / $d;
    $d12 = $d10 / ($d1 * (1 - $d2 / 4 - (3 * $d2 * $d2) / 64 - (5 * pow($d2, 3)) / 256));
    $d14 = $d12 + ((3 * $d4) / 2 - (27 * pow($d4, 3)) / 32) * sin(2 * $d12) + ((21 * $d4 * $d4) / 16 - (55 * pow($d4, 4)) / 32) * sin(4 * $d12) + ((151 * pow($d4, 3)) / 96) * sin(6 * $d12);
    $d13 = rad2deg($d14);
    $d5 = $d1 / sqrt(1 - $d2 * sin($d14) * sin($d14));
    $d6 = tan($d14) * tan($d14);
    $d7 = $d3 * cos($d14) * cos($d14);
    $d8 = ($d1 * (1 - $d2)) / pow(1 - $d2 * sin($d14) * sin($d14) , 1.5);
    $d9 = $d15 / ($d5 * $d);
    $d17 = $d14 - (($d5 * tan($d14)) / $d8) * ((($d9 * $d9) / 2 - (((5 + 3 * $d6 + 10 * $d7) - 4 * $d7 * $d7 - 9 * $d3) * pow($d9, 4)) / 24) + (((61 + 90 * $d6 + 298 * $d7 + 45 * $d6 * $d6) - 252 * $d3 - 3 * $d7 * $d7) * pow($d9, 6)) / 720);
    $d17 = rad2deg($d17);
    $d18 = (($d9 - ((1 + 2 * $d6 + $d7) * pow($d9, 3)) / 6) + (((((5 - 2 * $d7) + 28 * $d6) - 3 * $d7 * $d7) + 8 * $d3 + 24 * $d6 * $d6) * pow($d9, 5)) / 120) / cos($d14);
    $d18 = $d11 + rad2deg($d18);
    return array(
        'lat' => $d17,
        'lng' => $d18
    );
}
?>

For completeness another option for people that is packaged up in Composer is https://packagist.org/packages/php-coord/php-coord

It's not that well documented but it looks like with a combination of Easting, Northing and Zone you can return the Latitude and Longitude. eg:

$easting = 505716.941;
$northing =  6961780.872;
$zone = 56;

$UTMRef = new PHPCoord\UTMRef($easting, $northing, NULL, $zone, $zone);
$LatLng = $UTMRef->toLatLng();

print "Lat/Lng:" . $LatLng->getLat() . ", " . $LatLng->getLng() . "\n";

Note it doesn't seem as accurate as gPoint mentioned above.

Another possibility is the package proj4php (https://github.com/proj4php/proj4php). Very powerful and it allows converting from and to many different coordinate systems.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top