【问题标题】:Detecting mouse collision with closed Bezier curved shapes in Canvas在 Canvas 中检测鼠标与闭合贝塞尔曲线形状的碰撞
【发布时间】:2013-11-28 21:57:37
【问题描述】:

我的情况:

我正在开发用于缩放用户界面的 HTML5/Canvas/JavaScript 框架,然后我将其用于数据可视化 Web 应用程序项目。我的框架需要的功能之一是能够检测用户的鼠标是否在渲染的形状上。对于更复杂的形状,例如多边形和带有贝塞尔曲线的形状,这将成为一项挑战。

我找到了解决这个问题的两种方法:

(1) 一种方法是在画布上绘制所有内容两次。第一次,每个形状都用哈希表中的唯一颜色填充。第二次,形状在第一层上得到它们的真实颜色和蒙版。为了检测鼠标形状碰撞,我必须从第一层抓取鼠标下方像素的颜色,并将我得到的颜色映射到哈希表中的相应形状。

(2) 或者我可以使用光线投射算法 (http://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm)。我实际上已经使用检测射线线碰撞和射线-贝塞尔曲线碰撞的代码实现了这个算法。

实际问题:

我不喜欢第一种方法,因为所有内容都必须绘制两次,这在计算上并不便宜。但第二种方法不能保证准确性,因为计算会产生舍入误差。

理想情况下,我想将第二种方法的准确性提高到接近完美。

我提高准确性的尝试是向不同方向投射 4 条光线:上、左、下和右。如果至少一条水平射线和一条垂直射线表明鼠标在形状内,那么我断定该点在形状内。虽然这消除了大多数失火,但当鼠标在形状内时仍然会发生错误(不触发)。

如果有人可以建议修复光线投射算法,或者甚至是第三种选择,那就太棒了!

提前致谢。

【问题讨论】:

    标签: javascript html algorithm canvas bezier


    【解决方案1】:

    您可以进行光线投射,但也可以在上下文中使用内置函数:

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

    您需要为每个独特的形状执行此操作,但性能相当不错,除非您有无数的形状,在这种情况下您可以考虑四叉树等。

    要检测您单击的形状,您可以将形状存储为对象,而不是使用唯一颜色(但取决于实际情况),因此当您遍历对象数组时,您将知道当前正在检查哪个对象,以及是否真正命中然后中止迭代。

    【讨论】:

    • 难以置信!我很乐意处理光线投射方法。这个内置功能完美运行!非常感谢!
    • 没问题@Hans,很高兴我能帮上忙 :)
    猜你喜欢
    • 2018-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-10
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多