2010-03-19 128 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

相關問題