dap*_*hez 26 language-agnostic gis geometry distance geospatial
我在地球上有一个线段(大圆圈部分).线段由其末端的坐标定义.显然,两个点定义了两个线段,所以假设我对较短的线段感兴趣.
我得到了第三点,我正在寻找线和点之间的(最短)距离.
所有坐标均以经度\纬度(WGS 84)给出.
我该如何计算距离?
任何合理的编程语言都可以使用解决方案.
dap*_*hez 19
这是我自己的解决方案,基于问Math博士的想法.我很乐意看到您的反馈.
首先免责声明.这种解决方案适用于球体.地球不是一个球体,坐标系统(WGS 84)并不认为它是一个球体.所以这只是一个近似值,我无法估计是错误.此外,对于非常小的距离,通过假设所有东西都只是一个共面,它也可能得到很好的近似.我再一次不知道距离必须"小".
现在去做生意.我将调用线A,B和第三点C的末端.基本上,算法是:
使用以下3个矢量积计算T,AB线上最接近C的点:
G = A x B
F = C x G.
T = G×F
归一化T并乘以地球半径.
如果你正在寻找C和A和B定义的大圆之间的距离,这些步骤就足够了.如果像我一样你对C和较短线段之间的距离感兴趣,你需要采取额外的步骤来验证T确实在这一部分.如果不是,那么最近的点必然是A或B两端之一 - 最简单的方法是检查哪一个.
一般而言,三种载体产品背后的想法如下.第一个(G)给出了A和B大圆的平面(所以包含A,B和原点的平面).第二个(F)给出了通过C并且垂直于G的大圆.然后T是由F和G定义的大圆的交点,通过归一化和乘以R得到正确的长度.
这是一些部分Java代码.
找到大圆上最近的点.输入和输出是长度为2的数组.中间阵列的长度为3.
double[] nearestPointGreatCircle(double[] a, double[] b, double c[])
{
double[] a_ = toCartsian(a);
double[] b_ = toCartsian(b);
double[] c_ = toCartsian(c);
double[] G = vectorProduct(a_, b_);
double[] F = vectorProduct(c_, G);
double[] t = vectorProduct(G, F);
normalize(t);
multiplyByScalar(t, R_EARTH);
return fromCartsian(t);
}
Run Code Online (Sandbox Code Playgroud)
找到段上最近的点:
double[] nearestPointSegment (double[] a, double[] b, double[] c)
{
double[] t= nearestPointGreatCircle(a,b,c);
if (onSegment(a,b,t))
return t;
return (distance(a,c) < distance(b,c)) ? a : c;
}
Run Code Online (Sandbox Code Playgroud)
这是一种简单的测试方法,如果我们知道的点T与A和B在同一个大圆上,则位于这个大圆的较短段上.但是有更有效的方法可以做到:
boolean onSegment (double[] a, double[] b, double[] t)
{
// should be return distance(a,t)+distance(b,t)==distance(a,b),
// but due to rounding errors, we use:
return Math.abs(distance(a,b)-distance(a,t)-distance(b,t)) < PRECISION;
}
Run Code Online (Sandbox Code Playgroud)