Dot-Net

.NET 確定滑鼠在兩個任意點之間繪製的線上

  • July 3, 2019

我在 Winform 上的兩個對象之間繪製了一個箭頭。

確定我的滑鼠目前懸停在這條線上或附近的最簡單方法是什麼。

我考慮過測試滑鼠點是否與由兩個點定義和外推的正方形相交,但是這只有在兩個點具有非常相似的 x 或 y 值時才可行。

我也在想,這個問題可能更多地屬於線性代數而不是簡單的三角學,雖然我確實記得矩陣的簡單方面,但這個問題超出了我對線性代數的了解。

另一方面,如果 .NET 庫能夠處理該功能,那就更好了。

編輯 感謝您的回答,有一些非常好的都值得被標記為已回答。

我選擇了 Coincoin 的答案作為接受,因為我喜歡它可以應用於繪製的任何形狀,但最終實現了 Tim Robinson 的方程,因為使用簡單的方程而不是更新圖形路徑和筆似乎更有效,如我的情況我需要為 1-n 個不同的關係做 onMouseMove (顯然會有一些記憶體和優化,但重點仍然存在)

該方程的主要問題是它似乎將這條線視為無限,所以我也添加了一個邊界測試。

對於那些感興趣的人,程式碼(最初的剪輯,我可能會稍微整理一下)如下

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

如果您想輕鬆地對任意繪製的形狀進行命中測試,您可以創建一個包含您的繪圖的路徑,然後加寬路徑並僅使用框架函式進行可見性測試。

例如,在這裡我們創建一條帶有一行的路徑:

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+ 繪製的東西。通過提取相同的路徑可以在HitTest和邏輯中使用。Draw

這是結合所有這些的程式碼:

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

引用自:https://stackoverflow.com/questions/2480321