首页 > 解决方案 > HTML Canvas quadraticCurveTo() 不准确吗?

问题描述

编辑:我刚刚将控制点更改为交叉点。这就是为什么它不能再适合了。

我知道这是非常冒昧的。但我正在开发一个 Web 应用程序,我需要计算与二次贝塞尔曲线和一条线的交点。

因为W, V, A, B, 和C是点,所以我可以做两个等式。我将第一个方程重新排列为单独的 s 来求解方程。我很确定我做对了,但我的路口不在线上。所以我想知道并通过正确的公式制作了我自己的二次贝塞尔曲线,我的交点达到了这条曲线。现在我想知道我做错了什么?

那是我的功能:

intersectsWithLineAtT(lineStartPoint, lineEndPoint)
{
    let result = []
    let A = this.startPoint, B = this.controlPoint, C = this.endPoint, V = lineStartPoint, W = lineEndPoint
    if (!Common.isLineIntersectingLine(A, B, V, W)
        && !Common.isLineIntersectingLine(B, C, V, W)
        && !Common.isLineIntersectingLine(A, C, V, W))
        return null

    let alpha = Point.add(Point.subtract(A, Point.multiply(B, 2)), C)
    let beta = Point.add(Point.multiply(A, -2), Point.multiply(B, 2))
    let gamma = A
    let delta = V
    let epsilon = Point.subtract(W, V)

    let a = alpha.x * (epsilon.y / epsilon.x) - alpha.y
    let b = beta.x * (epsilon.y / epsilon.x) - beta.y
    let c = (gamma.x - delta.x) * (epsilon.y / epsilon.x) - gamma.y + delta.y

    let underSquareRoot = b * b - 4 * a * c

    if (Common.compareFloats(0, underSquareRoot))
        result.push(-b / 2 * a)
    else if (underSquareRoot > 0)
    {
        result.push((-b + Math.sqrt(underSquareRoot)) / (2 * a))
        result.push((-b - Math.sqrt(underSquareRoot)) / (2 * a))
    }

    result = result.filter((t) =>
    {
        return (t >= 0 && t <= 1)
    })

    return result.length > 0 ? result : null
}

我希望有一个人可以帮助我。

莉娜

标签: javascripthtml5-canvaslineintersectionbezier

解决方案


曲线/直线相交问题与求根问题相同,在我们旋转所有坐标以使直线最终位于 x 轴顶部之后:

在此处输入图像描述

这涉及一个涉及atan2的快速技巧:

const d = W.minus(V);
const angle = -atan2(d.y, d.x);
const rotated = [A,B,C].map(p => p.minus(V).rotate(angle));

假设您正在使用理解矢量操作的点类。{x, y}如果没有,使用标准对象很容易做到:

const rotated = [A,B,C].map(p => {
  p.x -= V.x;
  p.y -= V.y;
  return {
    x: p.x * cos(a) - p.y * sin(a),
    y: p.x * sin(a) + p.y * cos(a)
  };
});

然后我们只需要找出哪些t值 yield y=0,这(正如您也使用过的)只是应用二次公式。而且我们不需要为折叠维度而烦恼:我们已经将问题简化为仅在y维度中寻找解决方案,因此采取

const a = rotated[0].y;
const b = rotated[1].y;
const c = rotated[2].y;

并将其与我们知道的事实相结合,Py = t²(a-b+c)+t(-2a+2b)+a我们只是t = -b/2a +/- sqrt(b² - 4ac))/2a通过通常检查负、零和正判别式以及检查除以零来解决这个问题。

这为我们t的旋转情况下的 y=0 截距以及未旋转情况下曲线和直线之间的交点提供了零个或多个值。无需额外计算。当然,除了“评估 B(t) 以获得实际的 (x,y) 坐标”。


推荐阅读