Минимальное расстояние между точкой и линией по широте, долготе
У меня есть линия с двумя точками широты и долготы
A: 3.222895, 101.719751
B: 3.227511, 101.724318
и 1 очко
C: 3.224972, 101.722932
Как рассчитать минимальное расстояние между точкой C и линией, состоящей из точек A и B? Это будет удобно, если вы также можете предоставить расчет и код objective-C. Расстояние составляет около 89 метров (с помощью линейки в Google Earth).
5 ответов
спасибо Мими и этой замечательной статье http://www.movable-type.co.uk/scripts/latlong.html но они не дают всей картины. Вот одна деталь. Все эти точки собираются с помощью Google Earth, используя метку, чтобы отметить места. Убедитесь, что lat/long установлены в десятичных градусах в настройках.
lat A = 3.222895
lon A = 101.719751
lat B = 3.222895
lon B = 101.719751
lat C = 3.224972
lon C = 101.722932
Earth radius, R = 6371
1. Сначала вам нужно найти подшипник от A до C и от A до B.
Формула подшипника
bearingAC = atan2( sin(Δλ)*cos(φ₂), cos(φ₁)*sin(φ₂) − sin(φ₁)*cos(φ₂)*cos(Δλ) )
bearingAB = atan2( sin(Δλ)*cos(φ₂), cos(φ₁)*sin(φ₂) − sin(φ₁)*cos(φ₂)*cos(Δλ) )
φ является широта, λ-долгота, R-радиус Земли
2. Найти расстояние с помощью косинусов
distanceAC = acos( sin(φ₁)*sin(φ₂) + cos(φ₁)*cos(φ₂)*cos(Δλ) )*R
3. Найти cross-track расстояние
distance = asin(sin(distanceAC/ R) * sin(bearingAC − bearing AB)) * R
Objective-C code
double lat1 = 3.227511;
double lon1 = 101.724318;
double lat2 = 3.222895;
double lon2 = 101.719751;
double lat3 = 3.224972;
double lon3 = 101.722932;
double y = sin(lon3 - lon1) * cos(lat3);
double x = cos(lat1) * sin(lat3) - sin(lat1) * cos(lat3) * cos(lat3 - lat1);
double bearing1 = radiansToDegrees(atan2(y, x));
bearing1 = 360 - ((bearing1 + 360) % 360);
double y2 = sin(lon2 - lon1) * cos(lat2);
double x2 = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lat2 - lat1);
double bearing2 = radiansToDegrees(atan2(y2, x2));
bearing2 = 360 - ((bearing2 + 360) % 360);
double lat1Rads = degreesToRadians(lat1);
double lat3Rads = degreesToRadians(lat3);
double dLon = degreesToRadians(lon3 - lon1);
double distanceAC = acos(sin(lat1Rads) * sin(lat3Rads)+cos(lat1Rads)*cos(lat3Rads)*cos(dLon)) * 6371;
double min_distance = fabs(asin(sin(distanceAC/6371)*sin(degreesToRadians(bearing1)-degreesToRadians(bearing2))) * 6371);
NSLog(@"bearing 1: %g", bearing1);
NSLog(@"bearing 2: %g", bearing2);
NSLog(@"distance AC: %g", distanceAC);
NSLog(@"min distance: %g", min_distance);
на самом деле для этого есть библиотека. Вы можете найти его здесь https://github.com/100grams/CoreLocationUtils
вычислить подшипник для каждого: C до A и C до B:
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1)*Math.sin(lat2) -
Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
var brng = Math.atan2(y, x).toDeg();
dLon= lon2-lon1;
рассчитать расстояние между дорожками:
var dXt = Math.asin(Math.sin(distance_CB/R)*Math.sin(bearing_CA-bearing_CB)) * R;
R-радиус Земли, dXt-минимальное расстояние, которое вы хотели рассчитать.
код для выполнения этого расчета размещен по адресу здесь. Это реализует точное решение в терминах эллипсоидальных геодезических. Для основных геодезических расчетов можно использовать GeographicLib или порт этих алгоритмов на C, которые включены в версию 4.9.0 PROJ.4. Этот интерфейс C документирован здесь.
вот результат компиляции и выполнения перехвата.cpp:
$ echo 3.222895 101.719751 3.227511 101.724318 3.224972 101.722932 | ./intercept
Initial guess 3.225203 101.7220345
Increment 0.0003349040566247297 0.0003313413822354505
Increment -4.440892098500626e-16 0
Increment 0 0
...
Final result 3.225537904056624 101.7223658413822
Azimuth to A1 -135.1593040635131
Azimuth to A2 44.84069593652217
Azimuth to B1 134.8406959363608
расстояние до линии 88,743 м:
$ echo 3.224972 101.722932 3.225537904056624 101.7223658413822 | GeodSolve -i
-45.15927221 -45.15930407 88.743
см. пост здесь: https://stackoverflow.com/a/33343505/4083623
для расстояния до нескольких тысяч метров я бы упростил вопрос от сферы до плоскости. Тогда проблема довольно проста, так как можно использовать простой расчет треугольника:
у нас есть точки A и B и ищем расстояние X до линии AB. Затем:
Location a;
Location b;
Location x;
double ax = a.distanceTo(x);
double alfa = (Math.abs(a.bearingTo(b) - a.bearingTo(x))) / 180
* Math.PI;
double distance = Math.sin(alfa) * ax;
Если вы знаете, как рассчитать расстояние между двумя точками, получите расстояния между каждой из двух точек, вы получите AB, AC и BC. Вы хотите знать расстояние между точкой С и прямой АВ.
сначала получите значение P
P=(AB+BC+AC)/2
используя P, вам нужно получить S
S=SQRT((P(P-AC)(P-AB)(P-AC))
SQRT означает квадратный корень. Тогда вы получите то, что хотите
2*S/AB