2010-03-19 114 views
7

我在Winform上的两个对象之间绘制了一个箭头。.NET确定鼠标是在两个任意点之间绘制的线条

什么是最简单的方法来确定我的鼠标当前悬停在这条线上或附近。

我已经考虑测试鼠标点是否与由两点定义和外推的平方相交,但只有两点具有非常相似的x或y值才可行。

我在想,这个问题可能更多的是线性代数领域,而不是简单的三角学,虽然我记得矩阵的更简单的方面,但这个问题超出了我对线性代数的认识。

另一方面,如果一个.NET库可以处理该功能,甚至更好。

编辑 感谢您的答案,有几个非常好的答案,都应该被标记为答案。

我选择了Coincoin的答案,因为我喜欢它可以应用于任何形状的绘制,但是最终实现了Tim Robinson的方程,因为使用简单的方程看起来效率更高,而不是新建图形路径和笔,就像在我的情况下,我需要在1-n不同关系上进行鼠标移动(显然会有一些缓存和优化,但该点仍然存在)

这个方程的主要问题是它似乎要处理这条线是无限的,所以我加了一个边界测试。

代码(初始切,我可能会neaten有点),对于那些有兴趣,低于

if (Math.Sqrt(Math.Pow(_end.X - _start.X, 2) + 
      Math.Pow(_end.Y - _start.Y, 2)) == 0) 
    { 
     _isHovering = 
      new RectangleF(e.X, e.Y, 1, 1).IntersectsWith(_bounds); 
    } 
    else 
    { 
     float threshold = 10.0f; 

     float distance = (float)Math.Abs( 
      (((_end.X - _start.X) * (_start.Y - e.Y)) - 
      ((_start.X - e.X) * (_end.Y - _start.Y)))/
      Math.Sqrt(Math.Pow(_end.X - _start.X, 2) + 
      Math.Pow(_end.Y - _start.Y, 2))); 

     _isHovering = (
      distance <= threshold && 
       new RectangleF(e.X, e.Y, 1, 1).IntersectsWith(_bounds) 
      ); 
    } 

和_bounds被定义为:

_bounds = new Rectangle(
    Math.Min(_start.X, _end.X), 
    Math.Min(_start.Y, _end.Y), 
    Math.Abs(_start.X - _end.X), Math.Abs(_start.Y - _end.Y)); 
+0

我所需要的,而且当我通过什么0特例检查 – johnc 2010-03-20 04:15:16

回答

7

如果你想伊斯利就随意绘制的形状击中测试,您可以创建一个包含您的绘制路径,然后widden路径和使用进行可视化检测只有框架功能。

例如,在这里我们创建了一个路径以行:

GraphicsPath path = new GraphicsPath(); 

path.AddLine(x1, y1, x2, y2); 
path.CloseFigure(); 

然后,拓宽路径和命中测试创建一个区域:

path.Widen(new Pen(Color.Black, 3)); 
region = new Region(path); 

最后,点击测试:

region.IsVisible(point); 

该方法的优点是它可以很容易地扩展到样条曲线,箭头,弧,馅饼或几乎任何东西用GDI +绘制。通过提取逻辑,可以在HitTestDraw逻辑中使用相同的路径。

这里是代码合并这一切:

public GraphicsPath Path 
{ 
    get { 
     GraphicsPath path = new GraphicsPath(); 
     path.AddLine(x1, y1, x2, y2); 
     path.CloseFigure(); 

     return path; 
    } 
} 

bool HitTest(Point point) 
{ 
    using(Pen new pen = Pen(Color.Black, 3)) 
    using(GraphicsPaht path = Path) 
    { 
     path.Widen(pen); 

     using(Region region = new Region(path)) 
      return region.IsVisible(point); 
    } 
} 


void Draw(Graphics graphics) 
{ 
    using(Pen pen = new Pen(Color.Blue, 0)) 
    using(GraphicsPaht path = Path) 
     graphics.DrawPath(pen, path); 
} 
+0

非常好。 ...确实... – 2010-03-19 20:41:19

+0

非常好,谢谢 – johnc 2010-03-19 20:50:37

0

退房的MouseEnter(对象发件人,EventArgs e)。当它“进入”控制区域时陷阱。

+0

检查的MouseEnter做div来考虑的门槛?这是由GDI图形对象绘制的线条? – johnc 2010-03-19 20:27:52

+0

啊。我不知道你是直接画画的。 如果它是一个winforms控件,它会连接鼠标事件。你可以从控制库继承并覆盖绘图来挑选它们。 – 2010-03-19 20:29:01

+0

谢谢,但恐怕在这种情况下使用控制库的效率太低。 – johnc 2010-03-19 20:31:32

4

要回答“鼠标悬停在这条线上?”,您需要检查点线相交。但是,由于您要求“鼠标靠近线条?”,因此您想要计算鼠标点和线条之间的距离。

这里的点线距离的合理详尽的解释:http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html

我说你需要实现这个公式在您的代码:(从钨被盗。COM)

http://mathworld.wolfram.com/images/equations/Point-LineDistance2-Dimensional/NumberedEquation8.gif

其中:

  • (X0,X0)是鼠标指针
  • (X1,Y1)的位置是行
  • (×2的一个端部,y2)是该行的另一端
  • |n|Math.Abs(n)
  • 下半部分是Math.Sqrt
  • 可以忽略|v.r|如果你想
+0

我会给它一个镜头,让你知道。谢谢。 – johnc 2010-03-19 20:29:20

+0

@蒂姆罗宾逊,我已经实现了这个公式,看到这个问题 – johnc 2010-03-20 04:13:54

1

需要构建两(名义)边界线平行于理想路径。那么你只需要为每个鼠标位置计算鼠标是在这些线所形成的通道之外还是之内。

不需要需要计算从鼠标到主线的距离。

+0

好主意[任意文本来弥补所需的评论长度] – johnc 2010-03-19 20:33:10

2

我会计算我的线的斜率截距方程(y = mx + b),然后用它来测试鼠标坐标。你可以很容易地把范围放在你的周围,看看你是否“接近”。

编辑样本。

我认为像这样的工作:

PointF currentPoint; 
PointF p1, p2; 
float threshold = 2.0f; 
float m = (p1.Y - p2.Y)/(p1.X - p2.X); 
float b = p1.Y - (m * p1.X); 

if (Math.Abs(((m * currentPoint.X) + b) - currentPoint.Y) <= threshold) 
{ 
    //On it. 
} 
+0

我喜欢这个的效率 – johnc 2010-03-19 20:51:16

+0

+1这就是我所暗示的,但他拿了时间写出数学。 – egrunin 2010-03-19 21:01:45

+1

这不适用于p1.X == p2.X的垂直线,因为您将被零除。垂直线没有定义的斜率。 – 2010-03-19 21:11:26

相关问题