C#

Что я делаю не так?

 using System; 

namespace DistanceTask
{
public static class DistanceTask
{
// Расстояние от точки (x, y) до отрезка AB с координатами A(ax, ay), B(bx, by)
public static double GetDistanceToSegment(double ax, double ay, double bx, double by, double x, double y)
{
double ac = Math.Sqrt(Math.Pow(x - ax, 2) + Math.Pow(y - ay, 2));
double ab = Math.Sqrt(Math.Pow(bx - ax, 2) + Math.Pow(by - ay, 2));
double bc = Math.Sqrt(Math.Pow(x - bx, 2) + Math.Pow(y - by, 2));
if((x==ax&&y==ay)||(x==bx&y==by)) return 0;
else if (((Math.Pow(ac, 2) + Math.Pow(bc, 2)) >= Math.Pow(ab, 2)) || (Math.Pow(ab, 2) + Math.Pow(bc, 2) >= Math.Pow(ac, 2)))
{
double result1 = Math.Abs((ay - by) * x + (bx - ax) * y + (ax * by - bx * ay));
double result2 = Math.Sqrt((by-ay)*(by - ay) +(bx-ax)* (bx - ax));
double result = result1 / result2;
if(Double.IsNaN(result))
return 0;
return result;
}
else return Math.Min(ac, ab);
}
}
}
Напишите метод вычисления расстояния от отрезка до точки.

Для проверки своего решения запустите скачанный проект.

Расстоянием от отрезка до точки называется расстояние от ближайшей точки отрезка до точки. Это либо расстояние до точки от прямой, содержащей отрезок, либо расстояние до точки от одного из концов отрезка.
Во-первых, в программе ошибка в строке
 return Math.Min(ac, ab); 
По смыслу задачи должно быть
 return Math.Min(ac, bc); 
Во-вторых, result2 то же самое, что ab.

Условие в if, видимо, должно проверять попадание проекции точки на отрезок, но помимо явной несимметрии относительно точек A и B оно неверно (например, первое условие выполняется, если точка расположена достаточно далеко (в смысле длины отрезка) от отрезка, что, однако, не гарантирует попадание проекции на отрезок).

Вместо исправления ошибок я предложу другой подход.

Введём на прямой AB натуральный параметр t: t(A) = 0, t(B) = 1. Тогда нам надо будет определить значение этого параметра для проекции точки O на прямую AB, при непопадании в отрезок [0; 1] приравнять 0 или 1 (в зависимости от того, что ближе), и вычислить расстояние от полученной точки до точки O.

 .          AO * AB   (x – ax)(bx – ax) + (y – ay)(by – ay)
t(Pr(O)) = ――――――― = ―――――――――――――――――――――――――――――――――――――
AB * AB (bx – ax)² + (by – ay)²
(Знаком * обозначено скалярное произведение векторов.)

Проверяем t < 0 → t = 0, t > 1 → t = 1.

После этого вычисляем расстояние между точками O и Pr'(O) = A + AB*t.
 D = √(ax + (bx – ax)t - x)² + (ay + (by – ay)t - y)² 
Код получается такой (я добавил ещё функцию вычисления квадрата):
 public static class DistanceTask  
{
private static double Sqr(double val) { return val * val; }
// Расстояние от точки (x, y) до отрезка AB с координатами A(ax, ay), B(bx, by)
public static double GetDistanceToSegment(double ax, double ay, double bx, double by, double x, double y)
{
double t = Math.Clamp(((x - ax)*(bx - ax) + (y - ay)*(by - ay)) / (Sqr(bx - ax) + Sqr(by - ay)), 0, 1);
return Math.Sqrt(Sqr(ax + (bx - ax)*t - x) + Sqr(ay + (by - ay)*t - y));
}
}
Виталя Киселев
Виталя Киселев
12 091
Лучший ответ
Да много чего... Например, сравниваешь переменные с плавающей точкой оператором ==. Используешь уродский нейминг result1 result2 result в методе, который возвращает единственный результат. Проверяешь на IsNaN и возвращаешь 0, хотя 0 - это не NaN, дистанция вполне может быть нулевой, а если она NaN, это что-то совершенно другое. В общем, забыть как страшный сон и переделать.
Кемран Чахалов
Кемран Чахалов
58 351