说明: 主要参考了 维基百科 , 建议将其和本文对照阅读。
应用场景
贝塞尔曲线在数学和图形学以及设计中都发挥了重要作用,原因就是它能够“作为一种多项式逼近在[ a, b ] 区间上所有的连续函数,并且收敛性很强,也就是一致收敛。” 用人话说呢,就是一种多项式曲线,能够用最少的参数来模拟任意曲线,并且模拟效果普遍极好。
所以各种设计软件,包括Processing, Illustrater等对其进行了广泛使用,从而实现对于曲线数据的数据压缩。
公式
下图选自维基:
可以看出,n次贝塞尔曲线需要n+1个点来确定,而这n+1个点中都包括了曲线起点和曲线终点。其具体形式和二项式公式有很大的相似性。
公式还是不太好理解,还好这个曲线还有一种图形化的描述,先来大概看看吧:
这就很容易理解了,首先我们定义函数k平均:
def kmean(pa, pb, k):
pax, pay = pa
pbx, pby = pb
return pax*k+pbx*(1-k), pay*k+pby*(1-k)
这个函数将两个点A, B的坐标按 k :(1-k)进行平均。图中的P0和P1之间的绿点就是P0和P1的k平均点,而k是一个从0到1的变量(也就是插图中的t)。
那么一次贝塞尔曲线就是:参数点(2个)之间的k平均点(1个)的轨迹。
二次贝塞尔曲线就是:参数点(3个)之间的k平均点(2个), 之间的k平均点(1个)的轨迹。
三次贝塞尔曲线就是:参数点(4个)之间的k平均点(3个) , 之间的k平均点(2个), 之间的k平均点(1个)的轨迹。
不知道熟练“套娃之术”的你有没有豁然开朗了呢?
Processing中验证
代码:
p0 = (100.0, 400.0)
p1 = (20.0, 100.0)
p2 = (400.0, 100.0)
p3 = (500.0, 400.0)
ps = []
for p in (p0, p1, p2, p3):
ps.extend(p)
def kmean(pa, pb, k):
pax, pay = pa
pbx, pby = pb
return pax*k+pbx*(1-k), pay*k+pby*(1-k)
def line_points(ps):
beginShape()
for p in ps:
vertex(*p)
circle(p[0], p[1], 12)
endShape()
def setup():
size(600, 600)
def draw():
background(255)
noFill()
bezier(*ps)
k = float(frameCount)/1000 - frameCount/1000
stroke(200, 0, 0)
line_points((p0, p1, p2, p3))
p01 = kmean(p0, p1, k)
p12 = kmean(p1, p2, k)
p23 = kmean(p2, p3, k)
stroke(200, 100, 0)
line_points((p01, p12, p23))
p012 = kmean(p01, p12, k)
p123 = kmean(p12, p23, k)
stroke(200, 150, 0)
line_points((p012, p123))
p1234 = kmean(p012, p123, k)
stroke(200,220, 0)
line_points((p1234,))
一点扩展
其实贝塞尔曲线概念本身就是极漂亮的,那么想一想下面的这种效果在Processing中是如何实现的呢?
更多资料
互动在线书:贝塞尔曲线的入门书
MIT出版:计算机辅助设计中的图形查询