Я работаю над программой, похожей на рисование, на 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, спасибо! Я знаю и сделал это в своем коде. Мне действительно просто интересно, почему он не работает в общих случаях
@dlatikay да, я должен был упомянуть, но я использую тригонометрию, чтобы проверить кратчайшее расстояние от моей точки до линии.
вам нужно перпендикулярное расстояние; что, по-видимому, делает ваш код, если я не ошибаюсь, - это совсем другое. формула y = kx + d не может работать с вертикальными линиями (когда k будет бесконечным - деление на ноль), поэтому идея использовать тригонометрию в порядке, но какой подход вы на самом деле используете и что такое yvalue? представьте минимально полный пример.
связанные: stackoverflow.com/a/20059470/1132334





Это скорее математическая задача. Я бы сделал следующее:
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).
Обратите внимание, что векторный подход более универсален, чем использование уклона, он не дает сбоев на горизонтальных или вертикальных линиях.
Помните, что при использовании деления для всегда проверяйте деление на ноль.