Расчет подшипника между двумя CLLocationCoordinate2Ds
Очень "простая" проблема: учитывая два CLLocationCoordinate2Ds, как я могу получить опору (как радианы) от первой до второй? Я провел много исследований и исследований по этому вопросу, как с общей проблемой, так и с 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 radians
Должно быть 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)
Я дважды и тройной проверял правильность формулы. Я также заметил, что проверил множество значений, подобных приведенному выше примеру, некоторые правильные, некоторые неправильные. Я играл с различными модулями или ограничивал возвращаемое значение, также не повезло.
Любые идеи? Есть ли проблема с моим кодом? Может быть, я неправильно понял, как работают математические функции?
Ответы
Ответ 1
Ваша математика правильная, со следующими исключениями:
-
Обязательно преобразуйте fLat, fLon, tLat и tLon в радианы, прежде чем применять к ним любые sin() или cos(). Разделите на 180.0 и умножьте на PI.
-
Введите дельта между tLng и fLng как tLng-fLng, а не наоборот. Обратите внимание, что эта разница появляется дважды в выражении.
С этими изменениями я получаю ранины 1.18660677830947 с математикой с двойной точностью и значениями в вопросе.
Ответ 2
Здесь код, измененный с изменениями, предложенными Ореном Трутнером и от меня:
#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;
}
}
Ответ 3
Swift 3:
func getBearing(toPoint point: CLLocationCoordinate2D) -> Double {
func degreesToRadians(degrees: Double) -> Double { return degrees * M_PI / 180.0 }
func radiansToDegrees(radians: Double) -> Double { return radians * 180.0 / M_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)
}
Ответ 4
вы можете использовать мой код.. он работает над моим проектом с микроконтроллером, который использует 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;
}
}