【问题标题】:.isPointInPath() for stroked lines and polylines.isPointInPath() 用于描边线和折线
【发布时间】:2012-07-14 16:13:05
【问题描述】:

我需要一种机制来检测具有不同笔划宽度的直线、曲线和折线的鼠标悬停事件,我已经为矩形和椭圆建立了这种机制,所以我对 canvas API 并不陌生。我会勾勒出所有绘制对象的轮廓并检测鼠标在它们上方的位置,当矩形或椭圆的笔画宽度超过 1 像素时,我会扩展路径以使其也包含边框。例如,对于线条和折线,当我的 lineWidth 为 20 像素时,我很难理解应该如何扩展它们。

我的问题是:如何在一些形状路径中转换直线、曲线和多段线,以便这条路径可以包含它们的所有宽度?

我需要创建的路径包含此图像中用黑色表示的线/曲线宽度。

---------更多信息----------

我会尽量简化问题: 我们有 2 个点(在下图中用红色表示),它们形成一条具有特定公式(y = mx + n)的线,我需要确定穿过这两个初始点的垂直线的公式,之后,有必要确定“蓝色”点的位置,它们位于 context.lineWidth 值一半的距离处,当所有点都已确定时,可以使用 moveTo() 和lineTo() 序列。这种方法应该适用于使用控制点的二次曲线和贝塞尔曲线。问题只存在于这些数学计算中。

【问题讨论】:

  • 您可以尝试在数学 SE 上寻求帮助。
  • 好的,我也去那里找个答案:)
  • 那么你想要一种在简化版中找到垂直线公式的方法吗?
  • 不,我需要得到蓝点的坐标,我只是解释了如何在逻辑上确定它们,现在我需要知道如何在数学上确定它们
  • 相关帖子stackoverflow.com/a/8462037/380384。如何偏移多边形。

标签: javascript html html5-canvas


【解决方案1】:

我在 math.stackexchange here 上找到了解决方案,此解决方案仅适用于线条,但适用于经过一些特定修改的曲线和折线。首先,我们需要确定通过两个初始点的线的公式:

第一步

我们的观点:P1(x1, y1) 和 P2(x2, y2)

点与相邻点之间的距离:d

一般形式:Ax + By + C = 0

其中:A = y2 - y1; B = x1 - x2; C = x2y1 - x1y2。

之后,需要将这个公式定义为简写形式:

第 2 步

缩写:y = mx +n

其中:m = - A / B; n = - C / B.(当 B != 0 时)

如果 A == 0,那么我们有公式:y = C(当我们有一条水平线时)

如果 B == 0,那么我们有公式:x = C(当我们有一条垂直线时)

当我们有直线的斜率时,我们需要它上面的垂直线的斜率:

第 3 步

垂线斜率:m2 = - 1 / m

如果 A == 0 或 B == 0 转到第 4 步

现在我们需要获取两个初始点的相邻点:

第四步

我将相邻点记为 P1N1,第一个点为 P1N2,第二个点为 P2N1 和 P2N2

对于特殊情况(水平线和垂直线,当 A == 0 或 B == 0 时)我们将有:

对于 A == 0(水平线):

P1N1(x1, y1 - d / 2); P1N2(x1, y1 + d / 2); P2N1(x2, y2 + d / 2); P2N2(x2, y2 - d / 2)。

对于 B == 0(垂直线):

P1N1(x1 - d / 2, y1); P1N2(x1 + d / 2, y1); P2N1(x2 + d / 2, y2); P2N2(x2 - d / 2, y2)。

对于其他情况(A != 0 和 B != 0):

P1N1:

x = (d / 2) / Math.sqrt(1 + Math.pow(m2, 2)) + x1;

y = (m2 * (d / 2)) / Math.sqrt(1 + Math.pow(m2, 2)) + y1;

P1N2:

x = - (d / 2) / Math.sqrt(1 + Math.pow(m2, 2)) + x1;

y = - (m2 * (d / 2)) / Math.sqrt(1 + Math.pow(m2, 2)) + y1;

P2N1:

x = (d / 2) / Math.sqrt(1 + Math.pow(m2, 2)) + x2;

y = (m2 * (d / 2)) / Math.sqrt(1 + Math.pow(m2, 2)) + y2;

P2N2:

x = - (d / 2) / Math.sqrt(1 + Math.pow(m2, 2)) + x2;

y = - (m2 * (d / 2)) / Math.sqrt(1 + Math.pow(m2, 2)) + y2;

如果您想在应用程序中实现这些公式,您应该缓存一些结果以提高性能。

【讨论】:

    【解决方案2】:

    您是否尝试过使用 Canvas 2D API 的 .isPointInStroke() 方法:

    ctx.isPointInStroke(x, y);
    ctx.isPointInStroke(path, x, y);
    

    看看: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInStroke

    【讨论】:

    • 问这个问题时ctx.isPointInStroke()不是Canvas API标准的一部分,问题是要计算xy的值,而不是检查点是不是路径/笔划的一部分
    【解决方案3】:

    如果你的贝塞尔曲线是以下形式。

    x(t) = x0 + x1*t + x2*t*t + x3*t*t*t
    y(t) = y0 + y1*t + y2*t*t + y3*t*t*t
    

    然后你必须compute the derivatives它,这将给出任意点的切线。

    x'(t) = x1 + 2*x2*t + 3*x3*t*t
    y'(t) = y1 + 2*y2*t + 3*y3*t*t
    

    和任何一点的法线。法线是任何一点的垂线,是两点的支撑。

    (-y'(t), x'(t))
    ((y'(t), -(x'(t))
    

    【讨论】:

      猜你喜欢
      • 2013-02-14
      • 1970-01-01
      • 2017-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-04
      • 1970-01-01
      • 2014-09-14
      相关资源
      最近更新 更多