【问题标题】:Is HTML Canvas quadraticCurveTo() not exact?HTML Canvas quadraticCurveTo() 不准确吗?
【发布时间】:2021-06-14 20:10:04
【问题描述】:

编辑:我刚刚将控制点更改为交叉点。这就是它不再适合的原因。

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

  • 线性贝塞尔曲线:P=s(W-V)+V
  • 二次贝塞尔曲线:P=t²(A-2B+C)+t(-2A+2B)+A

因为WVABC 是点,所以我可以做两个等式。我将第一个方程重新排列为单独的 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
}

我希望有人可以帮助我。

莉娜

【问题讨论】:

    标签: javascript html5-canvas line intersection bezier


    【解决方案1】:

    曲线/直线相交问题与求根问题相同,在我们旋转所有坐标以使直线最终位于 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 值产生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

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

    【讨论】:

    • 天哪,我很尴尬!你的回答对迈克很有帮助,但以另一种方式。不知何故,我在你的计算中犯了一个错误,我意识到即使是我的曲线也改变了它的外观。所以我的计算没有错误,我只是将我的 controlPoint 更改为 Intersection。所以再也装不下了!但我真的很感谢你的回答,因为它给了我另一种计算方式。
    • 这就是贝塞尔曲线的好处。作为具有有意义的几何、代数和微积分表达式和解释的东西,有很多方法可以实现相同的目标。
    猜你喜欢
    • 2023-04-06
    • 1970-01-01
    • 2015-08-13
    • 1970-01-01
    • 2016-05-30
    • 1970-01-01
    • 2014-05-01
    • 1970-01-01
    • 2011-04-10
    相关资源
    最近更新 更多