大家好,我是前端西瓜哥。
很多图形编辑器实现路径 path 编辑,只会用三阶贝塞尔和直线来表达。
不用二阶贝塞尔曲线,因为它相比三阶贝塞尔曲线,表达不够灵活自由,表达同一条路径需要更多段的曲线,所以我们一般不会使用它。
四阶则太复杂,而且大多数渲染引擎并不支持。
在一些场景下,我们需要把 二阶贝塞尔曲拟合为三阶贝塞尔。
比如导入了 SVG,里面给的是个二阶贝塞尔曲线,我们编辑器不支持,就需要转换一下。
或者编辑支持二阶贝塞尔的绘制方式,用符合二阶贝塞尔特征的方式绘制。
但绘制出来的图形数据还是三阶贝塞尔曲线,只是看着像二阶贝塞尔而已,之后用户编辑的时候就会发现其实它是个三阶贝塞尔,比如 Boxy SVG 编辑器。
二阶贝塞尔转为三阶贝塞尔
假设二阶贝塞尔(quadratic)的点已知依次为 Q0、Q1、Q2,需求的拟合三阶贝塞尔(cubic)的点依次为 C0、C1、C2、C3。
二阶贝塞尔曲线的参数方程,将 t 放到右边,为:
三阶贝塞尔曲线的参数方程为:
现在我们要用三阶等价二阶,也就是说对于同样的参数 t,得到的点是相同的。
所以我们可以认为这两个方程是等价的,结构一致,相同项的系数应该相等。
得到 4 个等式。
等式 1,直接得到 C0 为 Q0。
把 C0 的值带入到等式 2 中,可求 C1。然后再把 C0 和 C1 的值带入到等式 3,可求 C2。最后把它们都带入到等式 4,求出 C3。
最终解方程得到:
C0 = Q0
C1 = Q0 + (2 / 3) * (Q1 - Q0)
C2 = Q2 + (2 / 3) * (Q1 - Q2)
C3 = Q2
因为是基于两个方程的系数相等得到的值,而不是类似贝塞尔曲线拟合圆形做近似,所以可以说完美的拟合。
拟合出的三阶贝塞尔曲线,在平面几何上我们可以看到,起点和终点位置不变,两个控制点分别为之前二阶贝塞尔的起点和终点到控制点形成的控制线,其 2/3 插值处。
代码实现
const quadraticBezierToCubic = (p0, p1, p2) => {
return [
{ x: p0.x, y: p0.y },
{
x: p0.x + (2 / 3) * (p1.x - p0.x),
y: p0.y + (2 / 3) * (p1.y - p0.y),
},
{
x: p2.x + (2 / 3) * (p1.x - p2.x),
y: p2.y + (2 / 3) * (p1.y - p2.y),
},
{ x: p2.x, y: p2.y },
];
};
结尾
我是前端西瓜哥,关注我,学习更多解析几何知识。
相关阅读,