Использование закона косинуса для вычисления расстояния между двумя точками в задаче C? - PullRequest
3 голосов
/ 13 января 2010

Я получаю GPS-координаты от Google Maps, и мне нужно найти расстояние между ними используя Objective C. Я реализовал формулу, но я получаю результаты, которые являются большими.

Я проверил значения из Карт Google, передав их обратно в Google Earth и сервис геокодирования в Интернете, и все проверяется. Теперь я начинаю подозревать, что закон косинуса требует, чтобы я сделал какое-то преобразование с координатами, прежде чем передать их.

Я сделал аналогичную реализацию формулы Хаверсайна, но это также дало мне большие результаты. Затем я переключился на косинус, так как его было легче отлаживать, и мне не нужна очень высокая точность.

Надеюсь, кто-нибудь может пролить немного света на этот или использовать код:)

- (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;
}

Выше рассчитано по ссылкам, указанным здесь: stackoverflow question

Ответы [ 5 ]

3 голосов
/ 13 января 2010

Есть ряд вопросов, которые могут помочь, в том числе:

Учитывая две позиции, вы создаете сферические треугольные углы A в Амстердаме, B в Дубае и C на Северном полюсе со сторонами a = 90 ° - ϕ Ams , b = 90 ° - ϕ Dub , а угол C = Δλ = λ Dub - λ Ams . Требуемый ответ - сторона c.

Использование некоторого материала из моего ответа на SO 389211.

( Это радикально пересмотренный ответ - моя предыдущая попытка использовала неправильный сферический треугольник, и поэтому получил неправильный ответ. )


Искусство ASCII в худшем виде:

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

Основной закон косинуса для сферических треугольников:

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

Отметив, что cos (90º - x) = грех x и sin (90º - x) = cos x, мы можем написать:

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

Угол c в радианах затем преобразуется в расстояние путем умножения на радиус Земли.


Применение этого к вашим данным:

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

Δλ = 50.589532°

Работа до 6 знаков после запятой для тригонометрии:

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

Откуда:

c = 46.479426°
  =  0.811219 radians

Умножение этого на 6371 км как номинальный радиус земли дает

c = 5168 km

Следовательно, для R = 6371 км расстояние составляет 0,811219 × 6371 = 5168 км (до 4 с.ф.).

TrueKnowledge говорит, что должно быть около 5155 км. Позиционные данные, которые он использует, сравнимы с указанными вами значениями, и Википедия подтверждает указанный вами радиус. Это достаточно близко - повторный расчет с идентичными координатами и большим количеством цифр в расчете даст лучший ответ, но близкий к этому.


3 голосов
/ 13 января 2010

Рассматривали ли вы использовать метод, представленный в CLLocation:

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

2 голосов
/ 13 января 2010

Код может быть в порядке, когда я запускаю его на данных вашего примера (минус пара десятичных знаков), он возвращает 5168.3584

1 голос
/ 13 января 2010

Ребята, извините :( и у меня красное лицо. Я делаю некоторые другие расчеты по этим координатам. Я рассчитал их (х, у) положение поэтому они правильно позиционируют город на карте, которую я нарисовал. Эти координаты рассчитываются так:

- (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;

}

Некоторым не следует кодировать в середине ночи, а затем отправляться в SO, чтобы получить помощь от занятых людей, в результате несчастного случая я передаю преобразованные координаты методу.

Я узнал об этом, когда заметил, что при геокодировании разных городов я получил очень похожие результаты, а затем прочитал пост hic3456, и вдруг это имело смысл.

Я регистрирую и проверяю координаты и расстояние от отдельного класса, чтобы все регистрировалось до того, как в метод были переданы неправильные данные.

Теперь я действительно надеюсь, что кому-то, кроме меня, это поможет.

Снова извините и спасибо каждому из вас.

0 голосов
/ 13 января 2010

Ну, если я правильно понимаю вопрос, вы не учитываете кривизну земли.Закон косинуса работает на плоскости, а не на сфере.Например: Северный полюс и Южный полюс расположены на расстоянии ~ 20 000 км друг от друга, если вы летите, но только ~ 6000 км, если вы копаете туннель;)

С уважением, Ари

...