Расчет расстояния от точки до линейной линии - PullRequest
0 голосов
/ 06 ноября 2018

Я работаю над подобной программе в C #. Я хочу иметь возможность стирать линию при нажатии рядом с ней (например, расстояние <10 пикселей). Я пробовал разные вычисления, и проблема, с которой я постоянно сталкиваюсь, заключается в том, что линия будет стерта только тогда, когда я щелкну рядом либо с начальной точкой линии, либо с конечной точкой. Кажется, что-то среднее между ними не работает. </p>

Пусть p будет точкой, по которой пользователь щелкнул в форме, начальный и конечный конечные точки линии.

double a = (endp.Y - startp.Y) / (endp.X - startp.X); // gradient
double b = endp.Y - a * endp.X; // y intercept

// condition such that it only works when i click close to the line segment,
// not the entire infinite line for which the calculation y=ax+b works

double yvalue = p.X * a + b;    // value the line segment has at the x-value which the user clicks on
double alpha = Math.Atan((endp.X - startp.X) / (endp.Y - startp.Y));    
double distance = Math.Sin(alpha) * Math.Abs((yvalue - p.Y));
if (distance<10)
     // remove line

Почему этот код работает только для точек, близких к начальной и конечной точкам? Я уверен, что это не из-за условий, которые я использую, которые я оставил вне моего примера здесь

Ответы [ 4 ]

0 голосов
/ 06 ноября 2018

Если у вас есть линия с базовой точкой startP и нормализованным вектором направления d и точкой P, самый простой способ найти расстояние от точки до линии - использовать перекрестное произведение

Dist = Abs(Cross(P-startP, d)) = 
       Abs((P.x -startP.x) * d.y - (P.y -startP.y) * d.x)

Но вы хотите расстояние до отрезка (не бесконечной линии). В этом случае вам также необходимо проверить, находится ли проекция точки в диапазоне сегмента. Рассчитать параметр с помощью скалярного произведения:

t = Dot(P-startP, d)

, если t находится в диапазоне 0..Len(D), то проекция находится на отрезке, в противном случае кратчайшее расстояние - это расстояние от точки до одного из концов отрезка (начиная с отрицательного значения t, заканчивая для большого значения t).

Обратите внимание, что векторный подход более универсален, чем использование уклона, он не терпит неудачу на горизонтальных или вертикальных линиях.

0 голосов
/ 06 ноября 2018

Попробуйте использовать это, чтобы увидеть, если это то, что вам нужно:

int variance = 10; // +/- distance
PointF lineStart = new PointF(80, 80); // Starting line point
PointF lineEnd = new PointF(200, 200); // Ending line point

double x1 = lineStart.X;
double x2 = lineEnd.X;
double y1 = lineStart.Y;
double y2 = lineEnd.Y;

double mouseX = e.X; // Mouse X position
double mouseY = e.Y; // Mouse Y position

double AB = Math.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
double AP = Math.Sqrt((mouseX - x1) * (mouseX - x1) + (mouseY - y1) * (mouseY - y1));
double PB = Math.Sqrt((x2 - mouseX) * (x2 - mouseX) + (y2 - mouseY) * (y2 - mouseY));

if ((AP + PB) >= (AB - variance / 4) && (AP + PB) <= (AB + variance / 4))
{
    // It's within the line and variance
    // so erase Line
}
0 голосов
/ 06 ноября 2018

Расстояние, которое вы хотите рассчитать, можно увидеть как высоту P в треугольнике P-startP-endP. Таким образом, это дает следующую формулу:

a = dist(startp, endp)
b = dist(startp, p)
c = dist(endp, p)
s = (a + b + c)/2
distance = 2 * sqrt(s(s-a)(s-b)(s-c)) / a

Cf. Высота (треугольник)

0 голосов
/ 06 ноября 2018

Это больше математическая задача. Я бы сделал следующее:

1: Найти вектор линии v = (x2 - x1; y2 -y1)

2: повернуть вектор линии на 90 градусов: v1 = (-vy; vx)

3: При наличии положения мыши m = (mx; my) найдите пересечение линий: (mx; my) + k1 (-vy; vx) = (x1; y1) + k2 (vx; vy)

4: проверьте, меньше ли расстояние между результатом, найденным на шаге 4, до точки m, чем желаемый результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...