Расчет отношения между двумя CLLocationCoordinate2Ds - PullRequest
38 голосов
/ 28 сентября 2010

Очень «простая» проблема: учитывая два CLLocationCoordinate2D, как я могу получить направление (в радианах) от первого до второго? Я провел много исследований и исследований по этому вопросу, как общей проблемы, так и Objective-C / Cocoa Touch / iOS в частности.

Вот моя реализация:

- (float) getHeadingForDirectionFromCoordinate:(CLLocationCoordinate2D)fromLoc toCoordinate:(CLLocationCoordinate2D)toLoc
{
    float fLat = fromLoc.latitude;
    float fLng = fromLoc.longitude;
    float tLat = toLoc.latitude;
    float tLng = toLoc.longitude;

    return atan2(sin(fLng-tLng)*cos(tLat), cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(fLng-tLng));         
}

Однако этот метод не возвращает для меня непротиворечивых результатов. Если направление близко к северу или югу, это нормально, однако, любое другое направление возвращает несогласованные данные, например:

От 50,405018, 8,437500

до 51,339802, 12,403340

Мой метод возвращает: 5,918441 радиан

должно быть 1.18660576 радиан

(см. http://www.movable -type.co.uk / scripts / latlong.html и http://www.movable -type.co.uk / scripts / latlong-map.html? Lat1 = 50.405018 & long1 = 8,437500 & LAT2 = 51,339802 & long2 = 12,403340 )

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

Есть идеи? Есть ли проблема с моим кодом? Может быть, я неправильно понял, как работают математические функции?

Ответы [ 4 ]

52 голосов
/ 02 октября 2012

Здесь код, модифицированный изменениями, предложенными Ореном Трутнером и мной:

#define degreesToRadians(x) (M_PI * x / 180.0)
#define radiansToDegrees(x) (x * 180.0 / M_PI)

- (float)getHeadingForDirectionFromCoordinate:(CLLocationCoordinate2D)fromLoc toCoordinate:(CLLocationCoordinate2D)toLoc
{
    float fLat = degreesToRadians(fromLoc.latitude);
    float fLng = degreesToRadians(fromLoc.longitude);
    float tLat = degreesToRadians(toLoc.latitude);
    float tLng = degreesToRadians(toLoc.longitude);

    float degree = radiansToDegrees(atan2(sin(tLng-fLng)*cos(tLat), cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(tLng-fLng)));

    if (degree >= 0) {
        return degree;
    } else {
        return 360+degree;
    }
}
31 голосов
/ 28 сентября 2010

Ваша математика верна, со следующими исключениями:

  1. Убедитесь, что преобразовали fLat , fLon , tLat и tLon в радианы, прежде чем применять грех () или cos () им. Разделите на 180,0 и умножьте на PI.

  2. Введите дельту между tLng и fLng как tLng-fLng , а не наоборот. Обратите внимание, что эта разница встречается в выражении дважды.

С этими изменениями я получаю 1.18660677830947 радиан с математикой двойной точности и значениями в вопросе.

10 голосов
/ 17 декабря 2016

Свифт 3:

extension CLLocationCoordinate2D {
    func bearing(to point: CLLocationCoordinate2D) -> Double {
        func degreesToRadians(_ degrees: Double) -> Double { return degrees * Double.pi / 180.0 }
        func radiansToDegrees(_ radians: Double) -> Double { return radians * 180.0 / Double.pi }

        let lat1 = degreesToRadians(latitude)
        let lon1 = degreesToRadians(longitude)

        let lat2 = degreesToRadians(point.latitude);
        let lon2 = degreesToRadians(point.longitude);

        let dLon = lon2 - lon1;

        let y = sin(dLon) * cos(lat2);
        let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
        let radiansBearing = atan2(y, x);

        return radiansToDegrees(radiansBearing)
    }
}
0 голосов
/ 30 мая 2013

вы можете использовать мой код ... он работает над моим проектом с микроконтроллером, который использует GPS для данных.

#define d2r ((22/7.0)/180.0)
#define r2d (180.0/(22/7.0))

double get_heading1(double lat1, double long1, double lat2, double long2)  
{
    double diff_lat, diff_long;
    double degree;

    diff_long =(double) (((long2*1000000)-(long1*1000000))/1000000) * d2r;
    diff_lat = (double) (((lat2*1000000)-(lat1*1000000))/1000000) * d2r;     

    degree = r2d     (atan2(sin(diff_long)*cos(d2r*lat2),cos(d2r*lat1)*sin(d2r*lat2)-sin(d2r*lat1)*cos(d2r*lat2)    *cos(diff_long)));

    if (degree >= 0) {
        return degree;
    } else {
        return 360+degree;
    }                                                                 
}
...