.NET确定鼠标在两个任意点之间绘制

时间:2010-03-19 20:14:55

标签: .net geometry intersection

我在Winform上的两个对象之间绘制了一个箭头。

确定我的鼠标当前是否在此行上方或附近停留的最简单方法是什么。

我已经考虑过测试鼠标点是否与两个点定义的方形相交并外推,但只有当这两个点具有非常相似的x或y值时,这才是可行的。

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

另一方面,如果.NET库可以处理该功能,那就更好了。

修改的 感谢您的回答,有一些非常好的应该被标记为已回答。

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

该等式的主要问题是它似乎将该线视为无限,所以我也添加了一个边界测试。

代码(初步剪切,我可能会稍微讨论一下),对于那些感兴趣的人,在下面

    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));

5 个答案:

答案 0 :(得分:7)

如果您想轻松地对任意绘制的形状进行命中测试,您可以创建一个包含绘图的路径,然后使用框架函数来隐藏路径并进行可见性测试。

例如,我们在这里创建一个带有一行的路径:

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);
}

答案 1 :(得分:4)

要回答“鼠标悬停在此线上吗?”,您需要检查点线交叉点。但是,既然你问“鼠标是否在线附近?”,听起来你想要计算鼠标点和线之间的距离。

以下是对点线距离的合理详尽解释:http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html

我说你需要在你的代码中实现这个公式:(从wolfram.com窃取)

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

其中:

  • (x0,x0)是鼠标指针的位置
  • (x1,y1)是该行的一端
  • (x2,y2)是该行的另一端
  • |n|Math.Abs(n)
  • 下半部分为Math.Sqrt
  • 如果需要,您可以忽略|v.r|

答案 2 :(得分:2)

我会为我的线计算斜率 - 截距方程(y = mx + b),然后用它来测试鼠标坐标。您可以轻松地在y周围放置一个范围,看看您是否“接近”。

编辑样本。

我认为这样的事情有效:

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.
}

答案 3 :(得分:1)

您需要构建与理想路径平行的两条(名义)边界线。然后,您只需要为每个鼠标位置计算鼠标是在这些线形成的通道之外还是之内。

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

答案 4 :(得分:0)

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