php 在十进制坐标和度数坐标之间转换

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php 在十进制坐标和度数坐标之间转换相关的知识,希望对你有一定的参考价值。

Skip to content
dougv.com « Doug Vanderweide
Azure, .NET, WordPress, PHP, SQL, XML, JavaScript, Web geekery, entrepreneurship
HOME
 
PROGRAMMING
Azure
WordPress
.NET
PHP
JavaScript
 
ENTREPRENEURSHIP
 
GEEKERY
Help Desk
 
ABOUT THIS BLOG
Copyright & Attribution
Commenting Guidelines
Privacy
 
ABOUT ME
Need More Help Or Want To Say Thanks?
Search for:
PHP/PROGRAMMING
Converting Latitude And Longitude Coordinates Between Decimal And Degrees, Minutes, Seconds
Posted	on	7 March 2012	/ 9 Comments
I received an email yesterday from a reader who needed help with implementing my blog post, “Calculating The Bearing And Compass Rose Direction Between Two Latitude / Longitude Coordinates In PHP.”

His problem: He has latitude and longitude coordinates in his database tables that are in degrees-minutes-seconds (DMS) format, rather than decimal format. In other words, his coordinates look more like 55° 45′ 06″ N, 37° 37′ 04″ E than 55.751667, 37.617778.

So, my reader needed a way to convert back and forth between the two.

Fortunately, that’s easily done with a couple PHP functions. And since there’s not a lot that comes up in a Google search about how to make those conversions in PHP (lots of standalone converters, some JavaScript code, little PHP), I’ll fill the void here.

I should also note this function can be used for my other PHP latitude / longitude post, “Getting All ZIP Codes In A Given Radius From A Known Point / ZIP Code Via PHP And MySQL.”

Converting From DMS To Decimal
The easier of the two conversions is going from degrees-minutes-seconds to decimal. That’s because just as in an hour of time, each degree has 60 minutes, and each minute has 60 seconds.

So, to convert from DMS to decimal, we simply start with the degrees; then add the minutes value divided by 60, and the seconds value divided by 3600 (60 * 60). If the coordinates are South (latitude) or West (longitude), we need to make the decimal coordinate negative; North and East coordinates are positive.

Thus, a North latitude or East longitude is converted as:

1
$decimal = $degrees + ($minutes / 60) + ($seconds / 3600);
A South latitude or West longitude is calculated as:

1
$decimal = ($degrees + ($minutes / 60) + ($seconds / 3600)) * -1;
Here’s a simple function that makes these conversions. It takes, as arguments, the degrees, minutes and seconds of either a latitude or longitude coordinate, as well as its direction (N, S, E or W), and returns a decimal response.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function DMS2Decimal($degrees = 0, $minutes = 0, $seconds = 0, $direction = 'n') {
   //converts DMS coordinates to decimal
   //returns false on bad inputs, decimal on success
    
   //direction must be n, s, e or w, case-insensitive
   $d = strtolower($direction);
   $ok = array('n', 's', 'e', 'w');
    
   //degrees must be integer between 0 and 180
   if(!is_numeric($degrees) || $degrees < 0 || $degrees > 180) {
      $decimal = false;
   }
   //minutes must be integer or float between 0 and 59
   elseif(!is_numeric($minutes) || $minutes < 0 || $minutes > 59) {
      $decimal = false;
   }
   //seconds must be integer or float between 0 and 59
   elseif(!is_numeric($seconds) || $seconds < 0 || $seconds > 59) {
      $decimal = false;
   }
   elseif(!in_array($d, $ok)) {
      $decimal = false;
   }
   else {
      //inputs clean, calculate
      $decimal = $degrees + ($minutes / 60) + ($seconds / 3600);
       
      //reverse for south or west coordinates; north is assumed
      if($d == 's' || $d == 'w') {
         $decimal *= -1;
      }
   }
    
   return $decimal;
}
You can test this function here: http://demo.dougv.com/php_lat_lon_conversion/dms2decimal.php

You call this function as you would any built-in PHP function. For example, assuming you have DMS coordinate values stored in the PHP variables $deg, $min, $sec and $dir, you could assign a value to a decimal equivalent variable, $dec, thus:

1
$dec = DMS2Decimal($deg, $min, $sec, $dir);
Converting Decimal To DMS
Going from decimal coordinates to degrees-minutes-seconds is a bit more complicated.

Set the DMS direction to South (negative latitude), West (negative longitude), North (positive latitude) or East (positive longitude);
set the decimal to its absolute (i.e., unsigned) value;
set degrees to be the floor of the decimal;
subtract degrees from decimal, to get its fractional portion;
multiply that by 3600, to get the total number of seconds;
divide the seconds by 60, to get the total number of minutes;
subtract the total number of minutes, times 60, from seconds; then
set seconds value to its floor.
To accomplish this task via a PHP function, we will pass to it six arguments: the decimal coordinate; variables for degrees, minutes, seconds and direction; and a Boolean indicating if this is a latitude or longitude coordinate.

Four of our six arguments — degrees, minutes, seconds and direction — will be passed by reference. What that means to a layman is, the values of those arguments will be set by the function, without the need to specifically set them via an evaluation.

In other words, in PHP, you usually set a variable value via a function like this:

1
$foo = myfunction($bar);
But we’ll do it this way:

1
myfunction($bar, $foo);
An example of that in practice follows the function code.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
function DecimalToDMS($decimal, &$degrees, &$minutes, &$seconds, &$direction, $type = true) {
   //set default values for variables passed by reference
   $degrees = 0;
   $minutes = 0;
   $seconds = 0;
   $direction = 'X';
 
   //decimal must be integer or float no larger than 180;
   //type must be Boolean
   if(!is_numeric($decimal) || abs($decimal) > 180 || !is_bool($type)) {
      return false;
   }
    
   //inputs OK, proceed
   //type is latitude when true, longitude when false
    
   //set direction; north assumed
   if($type && $decimal < 0) { 
      $direction = 'S';
   }
   elseif(!$type && $decimal < 0) {
      $direction = 'W';
   }
   elseif(!$type) {
      $direction = 'E';
   }
   else {
      $direction = 'N';
   }
    
   //get absolute value of decimal
   $d = abs($decimal);
    
   //get degrees
   $degrees = floor($d);
    
   //get seconds
   $seconds = ($d - $degrees) * 3600;
    
   //get minutes
   $minutes = floor($seconds / 60);
    
   //reset seconds
   $seconds = floor($seconds - ($minutes * 60));   
}
You can see this in action here: http://demo.dougv.com/php_lat_lon_conversion/index.php

Let’s suppose you have the variables $deg, $min, $sec, $dir, for degrees, minutes, seconds and direction, respectively. You also have a decimal coordinate stored in $dec.

This is how you would invoke the function above to assign values to your DMS variables:

1
2
3
4
5
//if your decimal coordinate is a latitude:
DecimalToDMS($dec, $deg, $min, $sec, $dir, true);
 
//if your decimal coordinate is a longitude:
DecimalToDMS($dec, $deg, $min, $sec, $dir, false);
This code on github: https://github.com/dougvdotcom/php_convert_lat_lon

I distribute code under the GNU GPL. See Copyright & Attribution for details.

All links in this post on delicious: http://delicious.com/dougvdotcom/converting-latitude-and-longitude-coordinates-between-decimal-and-hours-minutes-seconds

Share this
PrintEmailRedditFacebook1LinkedInTwitterMore
 Google, latitude / longitude
Post navigation
OLDER POST
Working With authorize.net Server Integration Method (SIM) Payment Gateway, Part 2: Proper Form Design
NEWER POST
Displaying Selected YouTube Video Thumbnails On An ASP.NET Web Forms Page
YOU MIGHT ALSO LIKE
Getting All ZIP Codes In A Given Radius From A Known Point / ZIP Code Via ASP.NET
Getting All ZIP Codes In A Given Radius From A Known Point / ZIP Code Via ASP.NET
11 April 2012

Calculating The Bearing And Compass Rose Direction Between Two Latitude / Longitude Coordinates In PHP
Calculating The Bearing And Compass Rose Direction Between Two Latitude / Longitude Coordinates In PHP
13 July 2009

Getting All ZIP Codes In A Given Radius From A Known Point / ZIP Code Via PHP And MySQL
Getting All ZIP Codes In A Given Radius From A Known Point / ZIP Code Via PHP And MySQL
27 March 2009

9 Comments
Matthew
9 September 2012 at 9:14 am CST
I am trying to use this, but not in a form, just as function in my wordpress. I can put the code in the functions.php, but without having a form to submit it with I am just not getting it. I think I want two functions, one for lat and one for lng then I want to say

Right? This is just really not sinking in, any help is apreciated! Just want this decimals to dms using an on page variable not a form…thanks man!

Doug Vanderweide 
9 September 2012 at 9:52 pm CST
@Matthew: I get the gist of what you want. If you would like me to assist you with a specific implementation of my code, I do that for hire. See http://dougvdotcom.wpengine.com/need-more-help for details.

Sedat Kumcu
25 May 2013 at 5:53 pm CST
Hello, thanks for this sample. I prepared a javascript version sample of this Degrees to Decimal Converter for Google Maps. And here: http://jsbin.com/abolil/2/

Sedat Kumcu
25 May 2013 at 5:55 pm CST
And Revision #3
http://jsbin.com/abolil/3/edit

Udo Braavi
29 November 2014 at 12:42 pm CST
Hello,
Thanks for your code. May I use a part of your code? I need to use the core logic on a project. Going to make it return a string though instead of using references in the function parameters.
Alternatively I think I might return an array and recover the variables with list()

If I may, though it seems to be that the seconds can be represented as decimal values and do not need to be rounded up. But maybe there are issues with precision of php floats that might force this?

Doug Vanderweide 
29 November 2014 at 6:23 pm CST
@Udo:

May I use a part of your code?

http://dougvdotcom.wpengine.com/copyright-attribution/

If I may, though it seems to be that the seconds can be represented as decimal values and do not need to be rounded up.

The conversion of a coordinates between DMS and decimals, when the seconds of the DMS coordinate is not expressed as a high-precision decimal, naturally introduces precision in favor of the DMS measurement.

That’s not a factor of PHP, which uses the same 32-bit and 64-bit integers that other scripting languages use. It’s a factor of the limitations of a DMS coordinate itself.

In other words, a latitude coordinate of 46.5232912482 is considerably more precise than a DMS of 46° 31′ 23″ N, which you will see if you convert between the two without rounding.

Therefore, it makes sense to round results in both directions, as the inaccuracy of DMS coordinates without fractional seconds will introduce error in both directions during conversion if you don’t round.

In other words, converting 46° 31′ 23″ N to a decimal will produce 46.5230555… {ad infinitum}, not 46.5232912482. If we then reconvert that result to DMS, we get 46° 31′ 22″ N. Repeat that process enough, and you won’t be anywhere near the initial coordinate, whether it was decimal or DMS.

So this conversion doesn’t need high precision. If anything, high precision gives us false confidence in our results, because this conversion is, by nature, imprecise.

Jose Ricardo Borba
27 January 2015 at 6:53 pm CST
Dear Doug,
Your contribution is a way good. I like the way you write. Simple and clear. But your code have a mistake: if the seconds from a coordinate is more than 59 (yes, this happens), your code return false for lat or lng. Please, correct this for other people that learn with your code (my coordinate is “30 0m 14.478s S, 51 6m 59.108s W”). Best regards and keep your good work!

Doug Vanderweide 
29 January 2015 at 9:18 am CST
@Jose: Thanks for your note. You are correct; one should not pass in fractional seconds coordinates.

You can fix this one of two ways. The preferred way would be to floor() your seconds argument before passing it in, since the accuracy of fractional seconds coordinates is an illusion. (That is, it seems that a fractional seconds coordinate is more precise, and technically it is, but in truth it’s probably not any more accurate than had you simply passed in the next integer.)

Alternatively, you can change the sanitation routine to see if the minutes and seconds are less than 60.

17
18
19
20
//seconds must be integer or float between 0 and 59
elseif(!is_numeric($seconds) || $seconds < 0 || $seconds >= 60) {
     $decimal = false;
}
Again, I would floor() my seconds argument before passing it in, because while it might seem like a decimal seconds argument is more precise, and technically it is, the actual precision you are getting from a fractional seconds coordinate is pretty much useless.

tumbas
10 February 2015 at 1:43 am CST
Thanx guys, it work’s for me (y)

Leave a Reply	

Check out the Commenting Guidelines before commenting, please!
Want to share code? Please put it into a GitHub Gist, CodePen or pastebin and link to that in your comment.
Just have a line or two of markup? Wrap them in an appropriate SyntaxHighlighter Evolved shortcode for your programming language, please!
MCSE Cloud Platform and Infrastructure Certified 2017
MCSD App Builder Certified 2017
Microsoft Certified Trainer
Contact QR
Powered by WordPress	| Theme: Graphy by Themegraphy

以上是关于php 在十进制坐标和度数坐标之间转换的主要内容,如果未能解决你的问题,请参考以下文章

将坐标从非常规格式的度数转换为十进制度数

将地理坐标从度数转换为十进制

python 脚本将以DMS(度数分钟秒)格式给出的坐标转换为DD(度数)

GeoTools 从以米为单位的 CRS 转换为以度数为单位的 CRS (WGS84)

将 DDM 转换为 DEC(十进制度)

iPhone指南针坐标转换腾讯地图坐标步骤