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

joh*_*hnc 7 .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)
            );
    }
Run Code Online (Sandbox Code Playgroud)

和_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));
Run Code Online (Sandbox Code Playgroud)

Coi*_*oin 7

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

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

GraphicsPath path = new GraphicsPath();

path.AddLine(x1, y1, x2, y2);
path.CloseFigure();
Run Code Online (Sandbox Code Playgroud)

然后,加宽路径并为命中测试创建一个区域:

path.Widen(new Pen(Color.Black, 3));
region = new Region(path);
Run Code Online (Sandbox Code Playgroud)

最后,命中测试:

region.IsVisible(point);
Run Code Online (Sandbox Code Playgroud)

该方法的优点是它可以很容易地扩展到样条线,箭头,弧形,馅饼或几乎任何可用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);
}
Run Code Online (Sandbox Code Playgroud)