2013-11-28 29 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