Расчет расстояния от точки до линейной линии

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

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

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

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

Помните, что при использовании деления для всегда проверяйте деление на ноль.

JosephDoggie 06.11.2018 15:18

Я бы посоветовал сначала поработать над вашим определением «близкого к этому», прежде чем вы начнете набирать математику, а затем реализовать. каков тригонометрический принцип вычисления расстояния? вы хотите протестировать ограничивающий прямоугольник с двумя ограничивающими параллельными линиями с полукруглыми «горячими точками» на концах или без них?

Cee McSharpface 06.11.2018 15:21

@JosephDoggie, спасибо! Я знаю и сделал это в своем коде. Мне действительно просто интересно, почему он не работает в общих случаях

FleetL 06.11.2018 15:27

@dlatikay да, я должен был упомянуть, но я использую тригонометрию, чтобы проверить кратчайшее расстояние от моей точки до линии.

FleetL 06.11.2018 15:31

вам нужно перпендикулярное расстояние; что, по-видимому, делает ваш код, если я не ошибаюсь, - это совсем другое. формула y = kx + d не может работать с вертикальными линиями (когда k будет бесконечным - деление на ноль), поэтому идея использовать тригонометрию в порядке, но какой подход вы на самом деле используете и что такое yvalue? представьте минимально полный пример.

Cee McSharpface 06.11.2018 15:40

связанные: stackoverflow.com/a/20059470/1132334

Cee McSharpface 06.11.2018 15:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
1 476
4

Ответы 4

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

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, чем желаемый результат.

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

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
}

Расстояние, которое вы хотите вычислить, можно увидеть как высоту 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

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

Если у вас есть линия с базовой точкой 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).

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

Другие вопросы по теме