我有一条由两个经纬度点构成的线路
A: 3.222895, 101.719751
B: 3.227511, 101.724318
以及一个点
C: 3.224972, 101.722932
如何计算点C与由点A和B组成的直线之间的最小距离?如果您能提供计算方法和Objective-C代码,则更为方便。该距离大约为89米(使用Google Earth中的测量工具)。
我有一条由两个经纬度点构成的线路
A: 3.222895, 101.719751
B: 3.227511, 101.724318
以及一个点
C: 3.224972, 101.722932
如何计算点C与由点A和B组成的直线之间的最小距离?如果您能提供计算方法和Objective-C代码,则更为方便。该距离大约为89米(使用Google Earth中的测量工具)。
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
首先你需要找到从A到C和从A到B的方位角。
方位角公式
bearingAC = atan2( sin(Δλ)*cos(φ₂), cos(φ₁)*sin(φ₂) − sin(φ₁)*cos(φ₂)*cos(Δλ) )
bearingAB = atan2( sin(Δλ)*cos(φ₂), cos(φ₁)*sin(φ₂) − sin(φ₁)*cos(φ₂)*cos(Δλ) )
φ代表纬度,λ代表经度,R代表地球半径。
2. 使用余弦定理计算A到C的距离
distanceAC = acos( sin(φ₁)*sin(φ₂) + cos(φ₁)*cos(φ₂)*cos(Δλ) )*R
3. 寻找横向距离
distance = asin(sin(distanceAC/ R) * sin(bearingAC − bearing AB)) * R
Objective-C 代码
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
360 - ((bearing + 360) % 360)
,因为模运算的优先级高于加法。 - astrowalkerfunc(point,start,end)
还是 func(point,end,start)
。对于 start = { Latitude = 36.496902, Longitude = -93.223531 }
、end = { Latitude = 36.496902, Longitude = -90.151775 }
和 point = { Latitude = 36.501227, Longitude = -93.368405 }
,我的读数不同(巨大)。我还发现了 https://dev59.com/WVwY5IYBdhLWcg3wTWQu,它给出了到圆弧**段**的距离,在修改后可以正常运行。 - greenoldman计算每个方位角:从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是你想要计算的最小距离。
distance_CB/R
转换为角度了。 - simlmx查看此帖子: https://dev59.com/93M_5IYBdhLWcg3wn0lO#33343505
对于距离在几千米以内的情况,我会将问题从球体化简为平面。 然后,问题非常简单,可以使用简单的三角形计算:
我们有点A和点B,并寻找到线AB的距离X。那么:
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;
这个计算的代码发布在这里。它实现了一个基于椭球地理测量的准确解决方案。 对于基本的测地线计算,您可以使用GeographicLib或这些算法的C语言移植版本,它们包含在PROJ.4的4.9.0版本中。该C接口的文档在这里。
以下是编译和运行intercept.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
P=(AB+BC+AC)/2
使用 P,需要获取 S
S=SQRT((P(P-AC)(P-AB)(P-AC))
SQRT 意味着平方根。然后你可以通过以下方式得到你想要的结果
2*S/AB