如何将具有3个点的二次贝塞尔曲线转换为具有4个点的三次贝塞尔曲线的算法?
如何将具有3个点的二次贝塞尔曲线转换为具有4个点的三次贝塞尔曲线的算法?
来自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)
由于舍入引入了轻微误差,但不太可能引起注意。
仅为接受答案提供证明。
二次贝塞尔曲线表达式如下:
Q(t) = Q0 (1-t)² + 2 Q1 (1-t) t + Q2 t²
三次贝塞尔曲线表达式如下:
C(t) = C0 (1-t)³ + 3 C1 (1-t)² t + 3 C2 (1-t) t² + C3 t³
为了使这两个多项式相等,它们的所有多项式系数必须相等。这些多项式系数是通过展开表达式(例如:(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 - 6C1 + 3C2) t² + (-C0 + 3C1 -3C2 + C3) t³
因此,我们得到以下4个方程:
C0 = Q0
-3C0 + 3C1 = -2Q0 + 2Q1
3C0 - 6C1 + 3C2 = Q0 - 2Q1 + Q2
-C0 + 3C1 -3C2 + C3 = 0
我们可以通过在第二行中将C0替换为Q0来简单地解决C1,得到:
C1 = Q0 + (2/3) (Q1 - Q0)
然后,我们可以继续替换并解决C2和C3,或者更加优雅地注意到在变量t' = 1-t的变化下,原方程式具有对称性,从而得出以下结论:
C0 = Q0
C1 = Q0 + (2/3) (Q1 - Q0)
C2 = Q2 + (2/3) (Q1 - Q2)
C3 = Q2
供参考,我基于上面Owen的答案实现了NSBezierPath的addQuadCurve
函数(macOS Swift 4版本)。
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)
}
}
CP2 = CP1 + 1/3*(QP1-QP2)
的公式。但是根据我的数学计算,这似乎得出了不同的结果。(以点QP0=(0,0)
、QP1=(1,2)
和QP2=(3,0)
为例;我的公式得出CP2=(5/3,4/3)
,而Flavius的公式得出CP2=(0,2)
)。我通过将三次项系数设置为0并解出其余部分来验证了我的公式。Flavius,你的公式从哪里来? - Owen S.