HTML Canvas quadraticCurveTo() 不准确吗?

问题描述

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

我知道这是非常冒昧的。但我正在开发一个 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,W)
        && !Common.isLineIntersectingLine(A,W))
        return null

    let alpha = Point.add(Point.subtract(A,Point.multiply(B,2)),C)
    let beta = Point.add(Point.multiply(A,-2),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
}

希望有人能帮助我。

莉娜

解决方法

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

enter image description here

其中涉及一个涉及 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,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) 坐标”。