在纬度和经度上,点与直线之间的最小距离是多少?

13

我有一条由两个经纬度点构成的线路
A: 3.222895, 101.719751
B: 3.227511, 101.724318

以及一个点
C: 3.224972, 101.722932

如何计算点C与由点A和B组成的直线之间的最小距离?如果您能提供计算方法和Objective-C代码,则更为方便。该距离大约为89米(使用Google Earth中的测量工具)。


可能是地球上点到直线的距离的重复问题。 - Lior Kogan
1
该问题没有任何分数可供计算。我需要计算示例。 - Azam
5个回答

16
感谢Mimi和这篇优秀的文章http://www.movable-type.co.uk/scripts/latlong.html,但它们并没有展现全部内容。这里提供详细信息。所有这些点都是使用Google Earth收集的,使用Placemark标记位置。请确保在首选项中将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

首先你需要找到从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


2
谢谢!我相信您的代码(计算方位)中有一些小错误——这些行应该写成360 - ((bearing + 360) % 360),因为模运算的优先级高于加法。 - astrowalker
也许我犯了一些愚蠢的打字错误,但是对于一条弧线/圆弧,读数应该始终相同,无论您调用 func(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
一旦计算出最小距离,是否有办法获取行进方向,以便您只需行进最小距离即可到达曲线?您已经知道了到点A和点C的方位角,但能否提供原始曲线与最小距离曲线的交点的方位角。 - Josh Gafni
1
代码似乎有错误。有时候你计算角度的正弦值是用度数(例如计算方位时),而有时候又是用弧度(最后两行)。两者都不可能正确!但还是谢谢你的回答,非常详细! - Dici

3

计算每个方位角:从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是你想要计算的最小距离。


dLon是什么?它是C语言的经度吗? - Azam
dLon 是经度的差异。 - user591593
1
这是点C和点B之间的距离。我也会编辑答案。 - user591593
你忘记将 distance_CB/R 转换为角度了。 - simlmx

1

查看此帖子: 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;

1

这个计算的代码发布在这里。它实现了一个基于椭球地理测量的准确解决方案。 对于基本的测地线计算,您可以使用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

0
如果您知道如何计算两点之间的距离,并获取每两个点之间的距离,您可以得到AB、AC和BC。您想知道点C与线段AB之间的最短距离。
首先获取P的值。
P=(AB+BC+AC)/2

使用 P,需要获取 S

S=SQRT((P(P-AC)(P-AB)(P-AC)) 

SQRT 意味着平方根。然后你可以通过以下方式得到你想要的结果

2*S/AB

1
由于纬度和经度不在平面上,因此无法精确转换。它们属于一个大地球球体。 - Azam
你说得对,我应该指出来。虽然我相信如果考虑到地球的圆形表面计算距离,造成的差异是很小的。 - David Lin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接