views:

421

answers:

7

I found a function in a PHP page that calculates the number of miles between 2 points, but it's faulty. It's supposed to work with google maps, but the difference in distances are ranging from 1.3 to 1.65 times further in google maps(which is more accurate).

Here's the function:

$M =  69.09 * rad2deg(acos(sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($lon1 - $lon2))));

I find it to be a bit complicated and I don't know that much about geometry to know wheter or not this is correct.

Can someone with a bit more knowhow take a look at this and see what's wrong with it?

+5  A: 

Maybe you are comparing the 'distance as the crow flies' (direct line between two points) with driving distance?

Also, see this post for calculating distance between two points in PHP.

jonstjohn
A: 

I don't know anything about geometry either, but google suggested this page.Maybe you will find it useful

Alekc
+2  A: 

You're looking for the Haversine formula to calculate distance between two points that you have longitude and latitude for.

A straightforward implementation of it in Javascript can be found here, which should be easy to convert to PHP.

Chad Birch
A: 

It looks like the calculation you're referencing uses a spherical coordinate system. The formula is almost correct. Part of what could be throwing your calculation off is the radius you're using. The 69.09 is the radius of the sphere (earth in this case). As you may know, the earth isn't really a sphere, more of an ellipsoid. I'd suggest trying the formulation below:

3963 * acos(sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($lon1 - $lon2)));

For more accurate results, you'll want to use Vincenty or Haversine calculations.

EDIT: To clarify, I'm not trying to imply that the bulk of the error you're reporting is due to using a spherical coordinate calculation. That error is much smaller than what you're seeing. The formula adjustment I supplied was intended to be a clearer version of the formula, as the 69.09 was a value of the radius of the earth adjusted to a degree system, which is less intuitive than simply using radians. Additionally, it's worth noting that for calculating very small distances, using the formula above is highly accurate (down to about 1m distances) as long as the system doing the calculation is working with enough decimal places. Using a float in modern computing gives you this accuracy.

patjbs
You do realize that's the same formula as in the OP? Also, the error introduced by the nonsphericity of the Earth is tiny, certainly nowhere near enough to explain the 1.3-1.65 factor Vordreller mentioned.
David Zaslavsky
Yes it's the same formula, but the radius has been corrected, and is more readable. I also wasn't attempting to imply that the elipsoid nature of the earth was introducing the error (which, as you say, is far smaller), but primarily he had an inaccurate radius.
patjbs
Actually the radius was accurate, since the OP's formula converted to degrees before multiplying. That introduces an extra factor of 180/pi, and 180/pi*69.09 is very nearly 3963.
David Zaslavsky
...and I didn't read your edit before that last comment. I agree, 3963 is more intuitive.
David Zaslavsky
A: 

It looks like the formula is accurate - see, for example, Wikipedia on "great circle distance". The factor of 69.09 in front is, I believe, the number of miles in one degree measured along a great circle (e.g. miles in 1 degree of longitude at the equator), so your answer will be in miles.

jonstjohn's idea that you might be incorrectly comparing straight-line distance with driving distance seems like the most likely explanation to me.

EDIT: or it could be the rounding error Wikipedia mentions, if you're working with small separations. But I would point my finger at the direct/driving distance difference first.

David Zaslavsky
+2  A: 

There are at least three couple different methods of calculating distance on the surface of the Earth, which vary in accuracy and required computation.

  1. Spherical Law of Cosines [not very accurate, very simple to calculate]
  2. Haversine Formula [accurate except at smaller distances, still relatively simple to calculate]
  3. Vincenty Formula [highly accurate and can use several different ellipsoid models of the Earth's surface, more complicated to calculate]

The example you provided appears to be the law of cosines calculation, while Google Maps is more accurate since it uses the Vincenty Formula. (I find that the Vincenty link explains the formula in better detail than it's Wikipedia page)

Edit: I saw a comment above that the error introduced by the deviation in the Earth's surface is trivial and cannot compose the error you are seeing. I'm afraid this is only true over very large distances. At distances of a couple hundred km or less, the errors can be decidedly non-trivial.

Soonil
If you're talking about my answer: the error introduced by the ellipticity of the Earth's surface is negligible/trivial over small distances because both a sphere and an ellipsoid are flat over small scales. You are probably thinking of the roundoff error in the law of cosines calculation.
David Zaslavsky
Over small distances (1-10km) I recall some results where law of cosines doubles the distance (at least) the vincenty formula produced. Being too lazy to recheck those :D, I ran haversine and vincenty on some points i have lying around and got a 1km error for a 250km distance. Not trivial for me :)
Soonil
On giving it more thought, I don't know how much round off error the law of cosines can put in, but it seems a reasonable answer.
Soonil
A: 

Here is a simpler version, but not accurate for very distant locations:

    const ONE_DEGREE = 111120;

public function distance( $point ) {
 $coef = cos( $this->getLatitude() / 180 * M_PI );
    $x = $this->getLatitude() - $point->getLatitude();
    $y = ( $this->getLongitude() - $point->getLongitude() ) * $coef;
    $result = sqrt( $x * $x + $y * $y ) * self::ONE_DEGREE;
 return $result;
}

$point and $this are instances of Location class with getLatitude() and getLongitude() methods.

puzz