我正在用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
为什么此代码只适用于靠近起点或终点的点?我相信这不是因为我使用的条件,我在这里的例子中遗漏了这些条件
要计算的距离可以看作是三角形p-startP-endP中p的高度。因此,这给出了以下公式:
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
参见。高度(三角形(
试着使用这个来看看这是否是你所需要的:
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
}
这更像是一道数学题。我会做以下事情:
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之间的距离是否小于您想要的结果。
如果直线与基点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
结束(。
请注意,矢量法比斜率法更通用,它不会在水平或垂直线上失败。