贝塞尔曲线的小故事
众所周知,贝塞尔曲线就是贝塞尔(Pierre Bézier)发明的曲线。。。。。。其实并不严格。
Pierre Bézier一直从事数学建模,其博士论文也是和参数化曲线有关。他在雷诺工作期间一直想将数值控制应用到车身模型上,并在60年代开发了初代CAD(Unisurf)。贝塞尔曲线的初次应用就是在这款CAD中,它让工程师们能够在计算机上构建复杂曲线。
1962年Bézier公开了贝塞尔曲线的算法,不过贝塞尔曲线历史还可以再往前追溯一些,其算法根源于1912年的伯恩多项式,贝塞尔曲线是其在在数学建模领域的一个应用。
1959年,在雪铁龙工作的保尔·德·卡斯特里奥(Paul de Castelijau)实现了与贝塞尔曲线相似的算法,不过直到80年代才公开发表,因此错过了冠名的机会。
贝塞尔曲线的推导过程
要理解贝塞尔曲线的公式,可以从一次贝塞尔曲线,也就是直线开始。
如何用公式表示直线绘制?如果有两点P0和P1,用t表示绘制进度,则对任意t,绘制的的直线上的点的位置为:
这个公式本质上就是最简单的线性插值。
由此,如果有三个点,P0,P1,P2,连接P0和P1得到直线L1,连接P1和P2得到直线L2,根据上述公式,对任意t,分别可得这两条直线上的点,连接这两个点,得到直线L3,根据一次贝塞尔公式,同样可得L3上任意t时的点P,将所有P点连接起来,刚好是一个曲线,因此我们得到了P点的公式——二次贝塞尔曲线:
同理,可以推导出三次贝塞尔曲线:
贝塞尔曲线的特性
贝塞尔曲线使人类能够以参数化的形式描述一段曲线,并且几乎所有的曲线都可以由多段贝塞尔曲线拟合。
贝塞尔曲线是平滑曲线,具体看曲线上的任意一点,刚好是控制点辅助线与曲线的切点,因此可以绘制多段平滑的贝塞尔曲线。
绘制多段光滑贝塞尔曲线
绘制两端光滑的贝塞尔曲线,至少具备的条件有两个:
- 两段线有一个连接点G
- 两端线在连接点G的切线方向一致。
对任意多个点绘制多段光滑的贝塞尔曲线,难点就是如何计算控制点,实现思路可以参考echarts中的drawSegment:
github.com/apache/echa…
实现大致思路如下:假设对x1,y1、x2,y2、x3,y3三个点绘制两条三次贝塞尔曲线,能够在连接处光滑,则首先绘制x1,y1到x2,y2处的三次贝塞尔曲线,对首段曲线,令控制点cp0和x1,y1重合(三次贝塞尔退化为二次),只需要求出cp1。求出cp1后,下一段曲线的cp0,与前一段曲线的cp1和x2,y2共线,因此也容易求出。
贝塞尔曲线的应用
贝塞尔曲线诞生于汽车行业CAD软件中,至今已应用在诸如仿真,3D打印,游戏,可视化等方方面面。
在前端领域,除了动画的缓动函数可以用贝塞尔曲线表示外,SVG和Canvas分别都有对应的直接绘制贝塞尔曲线的方法:
- SVG path的C命令
<svg width="300" height="200">
<path
d="
M 50 150
C 100 50, 200 50, 250 150
"
fill="none"
stroke="black"
stroke-width="2"
/>
</svg>
- Canvas中的bezierCurveTo方法
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
ctx.beginPath()
ctx.moveTo(50, 150)
ctx.bezierCurveTo(
100, 50, // 控制点1
200, 50, // 控制点2
250, 150 // 终点
)
ctx.stroke()