将二次贝塞尔曲线转换为三次贝塞尔曲线

发布于 2024-09-08 09:13:23 字数 48 浏览 5 评论 0原文

将二次贝塞尔曲线(有 3 个点)转换为三次贝塞尔曲线(有 4 个点)的算法是什么?

What is the algorithm to convert a quadratic bezier (with 3 points) to a cubic one (with 4 points)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

尘世孤行 2024-09-15 09:13:23

来自 https://fontforge.org/docs/techref/bezier。 html#converting-truetype-to-postscript

任何二次样条都可以表示为三次样条(其中三次项为零)。三次方程的端点与二次方程的端点相同。

CP0 = QP0
CP3 = QP2

立方体的两个控制点是:

CP1 = QP0 + 2/3 *(QP1-QP0)
CP2 = QP2 + 2/3 *(QP1-QP2)

...由于舍入而引入了一个轻微的错误,但不太可能被注意到。

From https://fontforge.org/docs/techref/bezier.html#converting-truetype-to-postscript:

Any quadratic spline can be expressed as a cubic (where the cubic term is zero). The end points of the cubic will be the same as the quadratic's.

CP0 = QP0
CP3 = QP2

The two control points for the cubic are:

CP1 = QP0 + 2/3 *(QP1-QP0)
CP2 = QP2 + 2/3 *(QP1-QP2)

...There is a slight error introduced due to rounding, but it is unlikely to be noticeable.

夜唯美灬不弃 2024-09-15 09:13:23

只是为已接受的答案提供证明。

二次贝塞尔曲线表示为:

Q(t) = Q0 (1-t)² + 2 Q1 (1-t) t + Q2

三次方贝塞尔曲线表示为:

C(t) = C0 (1-t)³ + 3 C1 (1-t)² t + 3 C2 (1-t) t² + C3

要使这两个多项式相等,它们的所有多项式系数必须相等。通过展开表达式(例如:(1-t)² = 1 - 2t + t²),然后对 1、t、t² 和 t³ 中的所有项进行因式分解来获得多项式系数:

Q(t) = Q0 + (-2Q0 + 2Q1) t + (Q0子> - 2Q1 + Q2) t²

C(t) = C0 + (-3C0 + 3C1) t + (3C0子> - 6C<子>1 + 3C<子>2) t² + (-C<子>0 + 3C<子>1 -3C<子>2 + C3) t³

因此,我们得到以下4个方程:

C0 = Q0

-3C0 + 3C1 = -2Q0 + 2Q1

3C0 - 6C1 + 3C2 = Q0 - 2Q1 + Q<子>2

-C0 + 3C1 -3C2 + C3 = 0

我们可以通过简单地将第二行中的 C0 替换为 Q0 来求解 C1 ,这给出:

C1 = Q0 + (2/3) (Q1 - Q0)< /p>

那么,我们可以要么继续替代求解 C2,然后求解 C3,或者更优雅地注意到变量 t' = 1- 变化下原始方程的对称性t,并得出结论:

C0 = Q0

C1 = Q0 + (2/3) (Q1 - Q0)< /p>

C2 = Q2 + (2/3) (Q1 - Q2)< /p>

C3 = Q2

Just giving a proof for the accepted answer.

A quadratic Bezier is expressed as:

Q(t) = Q0 (1-t)² + 2 Q1 (1-t) t + Q2

A cubic Bezier is expressed as:

C(t) = C0 (1-t)³ + 3 C1 (1-t)² t + 3 C2 (1-t) t² + C3

For those two polynomials to be equals, all their polynomial coefficients must be equal. The polynomial coefficents are obtained by developing the expressions (example: (1-t)² = 1 - 2t + t²), then factorizing all terms in 1, t, t², and t³:

Q(t) = Q0 + (-2Q0 + 2Q1) t + (Q0 - 2Q1 + Q2) t²

C(t) = C0 + (-3C0 + 3C1) t + (3C0 - 6C1 + 3C2) t² + (-C0 + 3C1 -3C2 + C3) t³

Therefore, we get the following 4 equations:

C0 = Q0

-3C0 + 3C1 = -2Q0 + 2Q1

3C0 - 6C1 + 3C2 = Q0 - 2Q1 + Q2

-C0 + 3C1 -3C2 + C3 = 0

We can solve for C1 by simply substituting C0 by Q0 in the 2nd row, which gives:

C1 = Q0 + (2/3) (Q1 - Q0)

Then, we can either continue to substitute to solve for C2 then C3, or more elegantly notice the symmetry in the original equations under the change of variable t' = 1-t, and conclude:

C0 = Q0

C1 = Q0 + (2/3) (Q1 - Q0)

C2 = Q2 + (2/3) (Q1 - Q2)

C3 = Q2

打小就很酷 2024-09-15 09:13:23

作为参考,我基于 上面 Owen 的回答为 NSBezierPath (macOS Swift 4) 实现了 addQuadCurve

extension NSBezierPath {
    public func addQuadCurve(to qp2: CGPoint, controlPoint qp1: CGPoint) {
        let qp0 = self.currentPoint
        self.curve(to: qp2,
            controlPoint1: qp0 + (2.0/3.0)*(qp1 - qp0),
            controlPoint2: qp2 + (2.0/3.0)*(qp1 - qp2))
    }
}

extension CGPoint {
    // Vector math
    public static func +(left: CGPoint, right: CGPoint) -> CGPoint {
        return CGPoint(x: left.x + right.x, y: left.y + right.y)
    }
    public static func -(left: CGPoint, right: CGPoint) -> CGPoint {
        return CGPoint(x: left.x - right.x, y: left.y - right.y)
    }
    public static func *(left: CGFloat, right: CGPoint) -> CGPoint {
        return CGPoint(x: left * right.x, y: left * right.y)
    }
}

For reference, I implemented addQuadCurve for NSBezierPath (macOS Swift 4) based on Owen's answer above.

extension NSBezierPath {
    public func addQuadCurve(to qp2: CGPoint, controlPoint qp1: CGPoint) {
        let qp0 = self.currentPoint
        self.curve(to: qp2,
            controlPoint1: qp0 + (2.0/3.0)*(qp1 - qp0),
            controlPoint2: qp2 + (2.0/3.0)*(qp1 - qp2))
    }
}

extension CGPoint {
    // Vector math
    public static func +(left: CGPoint, right: CGPoint) -> CGPoint {
        return CGPoint(x: left.x + right.x, y: left.y + right.y)
    }
    public static func -(left: CGPoint, right: CGPoint) -> CGPoint {
        return CGPoint(x: left.x - right.x, y: left.y - right.y)
    }
    public static func *(left: CGFloat, right: CGPoint) -> CGPoint {
        return CGPoint(x: left * right.x, y: left * right.y)
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文