Using the Cosine law to calculate distance between

2019-07-04 17:14发布

问题:

I get some GPS coordinates from Google Maps and I need to find the distance between them using Objective C. I have implemented the formula but I get results that are way to big.

I have tested the values from Google Maps by passing them back into Google Earth and a Geocoding service on the internet and everything checks out. Im now beginning to suspect that the cosine law demands I do some sort of conversion with the coordinates before I pass them in.

I did a similar implementation of the Haversine formula, but this also gave me to big results. I then switched to the cosine since it was easier to debug and I don't need very high precision.

Hope someone could shed a little light on this one, or use the code:)

- (CGFloat) calculateDistanceBetweenPoints:(CGPoint) origin andDestination:(CGPoint) destination {

//To convert kilometers to miles, divide by 1.609
// x = latitude 
// y = longitude

/* example:
 Dubai      : 25.248665, 55.352917 
 Amsterdam  : 52.309071, 4.763385
 Approx dist: 5,182.62 KM
 Calc. dist : 8,253.33
 */

CGFloat toRad           =   (M_PI / 180);
CGFloat R               =   6371.0f; //earth's mean radius in Km

CGFloat sinePart        =   sinf( origin.x * toRad ) * sinf( destination.x * toRad );
CGFloat cosinePart      =   cosf( origin.x * toRad ) * cosf( destination.x * toRad );
CGFloat deltaCosinePart =   cosf( ( destination.y - origin.y ) * toRad );

CGFloat delta           =   acosf( sinePart + cosinePart * deltaCosinePart) * R;

return delta;
}

Above calculated from links referenced here:stackoverflow question

回答1:

The code might be alright, when i run it on your example data (minus a couple of decimal places) it returns 5168.3584



回答2:

Have you considered using the method provided in CLLocation:

- (CLLocationDistance)getDistanceFrom:(const CLLocation *)location?



回答3:

There are a number of questions that might help, including:

  • SO 389211
  • SO 1050950

Given the two positions, you create a spherical triangle corners A at Amsterdam, B at Dubai and C at the North Pole, with sides a = 90° - ϕAms, b = 90° - ϕDub, and angle C = Δλ = λDub - λAms. The required answer is the side c.

Using some material from my answer to SO 389211.

(This is a radically revised answer - my previous attempt used the wrong spherical triangle, and therefore got the wrong answer.)


ASCII art at its worst:

                   + C (North Pole)
                  /|
                b/ |
                /  |
(Amsterdam) A  +   | a
                \  |
                c\ |
                  \|
                   + B (Dubai)

The basic Cosine Law for Spherical Triangles is:

cos c = cos a . cos b + sin a . sin b . cos C

Noting that cos (90º - x) = sin x and sin (90º - x) = cos x, we can write:

cos c = sin ϕAms . sin ϕDub + cos ϕAms . cos ϕDub . cos Δλ

The angle c in radians is then converted to a distance by multiplying by the radius of the Earth.


Applying this to your data:

Dubai: ϕDub = 25.248665°N, λDub = 55.352917°E
Amsterdam: ϕAms = 52.309071°N, λAms = 4.763385°E

Δλ = 50.589532°

Working to 6 decimal places for the trigonometry:

cos c = 0.426548 × 0.791320 + 0.904465 × 0.611402 × 0.634872
      = 0.337536            + 0.351079
      = 0.688615

Whence:

c = 46.479426°
  =  0.811219 radians

Multiplying this by 6371 km as the nominal radius of the earth yields

c = 5168 km

Hence, for R = 6371 km, the distance is 0.811219 × 6371 = 5168 km (to 4 s.f.).

TrueKnowledge says it should be about 5155 km. The positional data it says it used is comparable to the values you specified, and Wikipedia confirms the radius you provided. This is reasonably close - redoing the calculation with identical coordinates and more digits in the calculation would yield a better answer, but close to this one.




回答4:

Guys Im so sorry :( and have a red face. I do some other calculations on these coordinates. I calculated their (x, y) position so they position the city correctly on a custom map I drew. These coordinates are calculated as such:

- (CGPoint) translateToPixelsFromLatitude:(CGFloat) latitude andLongitude:(CGFloat) longitude {

CGPoint position    = CGPointMake(0, 0);
CGFloat mapWidth    = 300.0f;
CGFloat mapHeight   = 200.0f;

CGFloat offsetX     = 5.0f;
CGFloat offsetY     = 35.0f;

position.x = (((180 + longitude) / 360) * mapWidth) + offsetX;
position.y = (mapHeight - (((90 + latitude) / 180) * mapHeight)) + offsetY;

return position;

}

By some, should not code in the middle of the night and then head over to SO to get help from busy people, accident I pass the transformed coordinates to the method.

I found this out when I noticed that when geocoding different cities I got very similar results and then I read hic3456's post and suddenly it made sense.

I log and test the coordinates and distance from a separate class so everything got logged before the wrong data were passed to the method.

Now I really hope someone other than me will benefit from this.

Sorry again and thanks to every one of you.



回答5:

Well, if I understand the question correctly, you are not accounting for the curvature of the earth. The cosine law works on a plane, not on a sphere. For example: the North Pole and the South Pole are located at ~20,000 km apart if you fly, but only ~6000km if you dig a tunnel ;)

Regards, Ari