2013-11-28 71 views
1

我的情況:檢測鼠標的碰撞與帆布封閉的貝塞爾曲線形狀

我對HTML5 /畫布/ JavaScript框架的工作進行縮放,用戶界面,然後我用了一個數據可視化Web應用程序項目。我需要的框架之一是能夠檢測用戶的鼠標是否在渲染的形狀上。對於更復雜的形狀(如多邊形和具有貝塞爾曲線的形狀),這成爲一項挑戰。

我找到解決這個問題的方法有兩種:

(1)一種方法是在畫布上繪製兩遍。第一次,每個形狀都被哈希表中的唯一顏色填充。第二次,這些形狀在第一層上獲得了真實的色彩和蒙版。爲了檢測鼠標形狀的碰撞,我不得不從第一層抓住鼠標下面的像素的顏色,並將我得到的顏色映射到哈希表中的對應形狀。

(2)或者我可以使用光線投射算法(http://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm)。我實際上已經使用檢測射線碰撞和射線 - 貝塞爾碰撞的代碼實現了該算法。

實際的問題:

我不喜歡第一種方法,因爲一切都被抽了兩次,這是不計算便宜。但第二種方法並不能保證準確性,這是由於計算的舍入誤差。

理想情況下,我想提高第二種方法的準確性,以接近完美。

我試圖提高精度的方法是在不同的方向投射4條光線:頂部,左側,底部和右側。如果至少有一條水平光線和一條垂直光線表明鼠標位於該形狀內,則我認爲該點位於該形狀內。雖然這消除了大部分失火,但當鼠標放在形狀內時仍會發生錯誤(不會觸發)。

如果有人可以建議對光線投射算法進行修復,或者甚至可以選擇第三種方法,那就太棒了!

在此先感謝。

回答

6

你可以做光線投射,但你也可以使用內置函數上下文:

var flag = ctx.isPointInPath(x, y); 

您需要做的僅僅是重建要測試(不需要每個路徑中風或填充他們)並做這個測試。

還有:

var flag = ctx.isPointInStroke(x, y); 

,如果你還需要考慮它的情況下,行程本身寬度> 1.不支持IE瀏覽器這個功能作爲尚未雖然。

例如:

/// build some polygon/shape/... 
ctx.beginPath();; 
ctx.moveTo(x1, y1); 
ctx.lineTo(x2, y2); 
ctx.lineTo(x3, y3); 
ctx.closePath(); 

/// no need to fill/stroke it, just test the path: 
var flag = ctx.isPointInPath(x, y); 

你需要爲每個獨特的外形做到這一點,但性能相當好,除非你有數不勝數的形狀在這種情況下,你可以考慮四樹等。

要檢測您點擊的形狀,您可以將形狀存儲爲對象而不是使用唯一的顏色(取決於實際的場景),因此當您遍歷對象數組時,您將知道當前正在檢查哪個對象,以及如果真正命中,則中止迭代。

+0

不可思議!我很樂意處理光線投射法。這個內置函數完美工作!非常感謝你! – Hans

+0

沒問題@Hans,很高興我能幫忙:) – K3N