如何在C、C# / .NET 2.0或Java中计算点和线段之间的最短2D距离?

5

可能是重复问题:
点到线段的最短距离

我正在寻找一种计算所有情况下最小距离的方法。我发现的解决方案存在以下问题:

  1. 使用图形概念绘图的解决方案总是显示点始终在垂直于线段的位置,因此它位于“线段的端点之间”。我的几何技能很差,所以我无法验证这些解决方案在所有情况下都有效。

  2. 算法解决方案:a. 使用Fortran或其他我不完全理解的语言;b. 被人标记为不完整;c. 调用未经任何描述的方法/函数(被认为是微不足道的)。

2 a、b和c的一个很好的例子是

点到线段的最短距离

我有一个双精度坐标对(x1, y1)、(x2,y2)作为二维线段和一个双精度坐标(x3,y3)作为点。欢迎使用C#/Java/C解决方案。

感谢您的答案和问候:Matti


2
我在这里统计了6种不同语言的实现:https://dev59.com/fXRA5IYBdhLWcg3wuAcp - Tim Robinson
@oded:你指的是哪一部分?是已经被问答了无数次的部分吗?还是一开始没有“如何计算”的部分?就像我说的,非常抱歉我的搜索技能不好,但如果一个人无法想象“如何计算”在一开始的话……那么,你的链接是为了帮助人们相互理解的。我想你完全明白我的意思了。 - char m
你是: a. 没有恰当地描述你的问题。 b. 没有展示你已经尝试过什么。 c. 没有解释你在哪里遇到了困难。 - Oded
好的。缺少“如何…”似乎是一个问题。这完全没有出现在我意识中,但我会在未来提出更好的问题。 - char m
@tim: 这是我之前找到的链接(php/fortran)。实际上大部分实现都被标记为有误,并且缺少C#,所以并没有太多帮助。 - char m
@matti 除了Fortran,列表中的其他语言类似于C#。编写一个C#程序应该很容易。一旦你有了这个程序,就可以将你自己的C#答案添加到原始问题中。 - Tim Robinson
2个回答

19

因为它涵盖了所有语言的解决方案,所以我也回答了求点到线段的最短距离。此回答也放在这里,因为这个问题要求特别使用C#解决方案。这是从http://www.topcoder.com/tc?d1=tutorials&d2=geometry1&module=Static修改而来:

//Compute the dot product AB . BC
private double DotProduct(double[] pointA, double[] pointB, double[] pointC)
{
    double[] AB = new double[2];
    double[] BC = new double[2];
    AB[0] = pointB[0] - pointA[0];
    AB[1] = pointB[1] - pointA[1];
    BC[0] = pointC[0] - pointB[0];
    BC[1] = pointC[1] - pointB[1];
    double dot = AB[0] * BC[0] + AB[1] * BC[1];

    return dot;
}

//Compute the cross product AB x AC
private double CrossProduct(double[] pointA, double[] pointB, double[] pointC)
{
    double[] AB = new double[2];
    double[] AC = new double[2];
    AB[0] = pointB[0] - pointA[0];
    AB[1] = pointB[1] - pointA[1];
    AC[0] = pointC[0] - pointA[0];
    AC[1] = pointC[1] - pointA[1];
    double cross = AB[0] * AC[1] - AB[1] * AC[0];

    return cross;
}

//Compute the distance from A to B
double Distance(double[] pointA, double[] pointB)
{
    double d1 = pointA[0] - pointB[0];
    double d2 = pointA[1] - pointB[1];

    return Math.Sqrt(d1 * d1 + d2 * d2);
}

//Compute the distance from AB to C
//if isSegment is true, AB is a segment, not a line.
double LineToPointDistance2D(double[] pointA, double[] pointB, double[] pointC, 
    bool isSegment)
{
    double dist = CrossProduct(pointA, pointB, pointC) / Distance(pointA, pointB);
    if (isSegment)
    {
        double dot1 = DotProduct(pointA, pointB, pointC);
        if (dot1 > 0) 
            return Distance(pointB, pointC);

        double dot2 = DotProduct(pointB, pointA, pointC);
        if (dot2 > 0) 
            return Distance(pointA, pointC);
    }
    return Math.Abs(dist);
} 

4
哪些点A、B、C是线段的端点,哪一个是实际的奇点?你应该给变量命名,这就是我们使用名称而不是数字的原因。请正确地命名变量。 - mP.
1
这在注释中有说明。A和B是线段或直线的顶点,C是所讨论的点。一旦你明白了这一点,使用单个字母变量名可能更易读。 - Nat
1
第一个函数的注释说“//计算AB·AC的点积”,但它似乎计算的是AB•BC的点积。这是打字错误还是我没有完全理解点积? - M-Pixel
1
这个在垂线和共线点上会产生NaN。 - crokusek
1
//计算向量AB与AC的点积...难道不应该是AB·BC吗? - Humam Helfawi
显示剩余2条评论

0

如果你有一条线

L: A * x + B * y + C = 0

那么这条线到点(x1, y1)的距离是abs(A * x1 + B * y1 + C) / sqrt(A * A + B * B)。在你的情况下,如果你有区间(xa, ya); (xb, yb),你应该找到min( distance(x1, y1, xa, ya), distance(x1, y1, xb, yb)),然后看垂线从(x1, y1)到线L是否在区间上,如果是,则答案是距离,否则是两个距离的最小值。


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