Как рассчитать кратчайшее 2D-расстояние между точкой и сегментом линии во всех случаях в C, С#/.NET 2.0 или Java?

Возможный дубликат:
Самое короткое расстояние между точкой и сегментом линии

Я ищу способ расчета минимального расстояния во всех случаях. проблемы с найденными решениями:

  • Решения с графическими концептуальными чертежами показывают точку всегда на перпендикулярном отрезке линии, поэтому она "между конечными точками сегмента линии". Мои навыки геометрии ужасны, поэтому я не могу проверить, что эти решения работают во всех случаях.

  • Алгоритмические решения: с fortran или каким-либо другим языком, я не совсем понимаю, b: отмечены как неполные люди, c: вызывающие методы/функции, которые не описаны каким-либо образом (считаются тривиальными).

Хороший пример 2 a, b и c -

Самое короткое расстояние между точкой и сегментом линии

i имеет двустрочный сегмент в виде пары кодов двойного типа (x1, y1), (x2, y2) и указывает координату двойного типа (x3, y3). Решения на С#/Java/C приветствуются.

Спасибо за ваши ответы и BR: Matti

Ответ 1

Отвечено также кратчайшее расстояние между точкой и сегментом линии, поскольку оно собирает решения на всех языках. Ответ также здесь, потому что в этом вопросе конкретно рассматривается решение С#. Это изменено с 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);
} 

Ответ 2

Если у вас есть строка

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)), а затем посмотреть, будет ли perpendecular от (x1, y1) до строки L на интервале, тогда ответ - это расстояние. в противном случае мин двух расстояний.