贝塞尔样条是一个允许用户控制节点处斜率的样条,是一种特殊的三次样条。
皮埃尔·贝塞尔在其为雷诺(Renault)汽车公司工作时有了这个创意。Paul de Casteljau在与雷诺竞争关系的汽车公司雪铁龙Citroen公司工作时也独立有了这个想法。这在两家公司都认为是工业秘密,事实上在贝塞尔发表了他的研究后,大家才知道两家公司都进行了相同的研究。今天贝塞尔曲线(Bézier curve)是计算机辅助设计和制造的奠基石。
平面贝塞尔样条的每一段由4个点 ( x 1 , y 1 ) , ( x 2 , y 2 ) , ( x 3 , y 3 ) , ( x 4 , y 4 ) (x_{1}, y_{1}), (x_{2}, y_{2}), (x_{3}, y_{3}),(x_{4}, y_{4}) (x1,y1),(x2,y2),(x3,y3),(x4,y4)所确定。第一个点和最后一个点是样条的起点和终点,中间的两个点是控制点,曲线以切线方向 ( x 2 − x 1 , y 2 − y 1 ) (x_{2}-x_{1}, y_{2}-y_{1}) (x2−x1,y2−y1)离开 ( x 1 , y 1 ) (x_{1}, y_{1}) (x1,y1),并以切线方向 ( x 4 − x 3 , y 4 − y 3 ) (x_{4}-x_{3}, y_{4}-y_{3}) (x4−x3,y4−y3)在 ( x 4 , y 4 ) (x_{4}, y_{4}) (x4,y4)点结束。
对于贝塞尔曲线,给定端点 ( x 1 , y 1 ) , ( x 4 , y 4 ) (x_{1}, y_{1}), (x_{4}, y_{4}) (x1,y1),(x4,y4)和控制点 ( x 2 , y 2 ) , ( x 3 , y 3 ) (x_{2}, y_{2}), (x_{3}, y_{3}) (x2,y2),(x3,y3),设
b x = 3 ( x 2 − x 1 ) c x = 3 ( x 3 − x 2 ) − b x d x = x 4 − x 1 − b x − c x b y = 3 ( y 2 − y 1 ) c y = 3 ( y 3 − y 2 ) − b y d y = y 4 − y 1 − b y − c y b_{x}=3(x_{2}-x_{1})\\ c_{x}=3(x_{3}-x_{2})-b_{x}\\ d_{x}=x_{4}-x_{1}-b_{x}-c_{x}\\ b_{y}=3(y_{2}-y_{1})\\ c_{y}=3(y_{3}-y_{2})-b_{y}\\ d_{y}=y_{4}-y_{1}-b_{y}-c_{y} bx=3(x2−x1)cx=3(x3−x2)−bxdx=x4−x1−bx−cxby=3(y2−y1)cy=3(y3−y2)−bydy=y4−y1−by−cy
定义在 0 ≤ t ≤ 1 0\leq t \leq 1 0≤t≤1的贝塞尔曲线如下:
x ( t ) = x 1 + b x t + c x t 2 + d x t 3 y ( t ) = y 1 + b y t + c y t 2 + d y t 3 x(t) = x_{1}+b_{x}t+c_{x}t^{2}+d_{x}t^{3}\\ y(t) = y_{1}+b_{y}t+c_{y}t^{2}+d_{y}t^{3} x(t)=x1+bxt+cxt2+dxt3y(t)=y1+byt+cyt2+dyt3
应用1 绘制贝塞尔曲线
找出贝塞尔曲线(x(t), y(t))通过点(x,y)=(1, 1)和(2, 2),控制点为(1, 3)和(3, 3)。
Python实现程序如下:
# -*- coding: utf-8 -*-
# @Time : 2023/3/9 10:56
# @Author : Jclian91
# @File : Bezier_curve.py
# @Place : Xuhui, Shanghai
# solve Bézier curve with given four points
import matplotlib.pyplot as pltdef get_bezier_curve(pass_points, control_points):p_point1, p_point2 = pass_pointsx1, y1 = p_point1x4, y4 = p_point2c_point1, c_point2 = control_pointsx2, y2 = c_point1x3, y3 = c_point2# parameter in bezier curveb_x = 3 * (x2-x1)c_x = 3 * (x3-x2) - b_xd_x = x4 - x1 - b_x - c_xb_y = 3 * (y2 - y1)c_y = 3 * (y3 - y2) - b_yd_y = y4 - y1 - b_y - c_y# curven = 1000 # sample points in interval [0, 1]step = 1/nx_list, y_list = [], []t = 0for i in range(n):t += stepx_list.append(x1 + b_x * t + c_x * (t**2) + d_x * (t**3))y_list.append(y1 + b_y * t + c_y * (t ** 2) + d_y * (t ** 3))return x_list, y_list# plot bezier curve
def plot_bezier_curve(pass_points, control_points):x_list, y_list = get_bezier_curve(pass_points, control_points)plt.plot(x_list, y_list, label='bezier_curve', color='red')plt.title(f'Bezier Curve')plt.legend()# plt.show()plt.savefig(f"bezier_curve.png")if __name__ == '__main__':# example curvep_points = [(1, 1), (2, 2)]c_points = [(1, 3), (3, 3)]plot_bezier_curve(p_points, c_points)
绘制的贝塞尔曲线如下:
绘制计算机字符
在这个例子中,我们将解释如何使用二维贝塞尔曲线划出Times Roman字体的T字母。
Python实现程序如下:
# -*- coding: utf-8 -*-
# @Time : 2023/3/9 10:56
# @Author : Jclian91
# @File : Bezier_curve.py
# @Place : Xuhui, Shanghai
# solve Bézier curve with given four points
import matplotlib.pyplot as pltdef get_bezier_curve(pass_points, control_points):p_point1, p_point2 = pass_pointsx1, y1 = p_point1x4, y4 = p_point2c_point1, c_point2 = control_pointsx2, y2 = c_point1x3, y3 = c_point2# parameter in bezier curveb_x = 3 * (x2-x1)c_x = 3 * (x3-x2) - b_xd_x = x4 - x1 - b_x - c_xb_y = 3 * (y2 - y1)c_y = 3 * (y3 - y2) - b_yd_y = y4 - y1 - b_y - c_y# curven = 1000 # sample points in interval [0, 1]step = 1/nx_list, y_list = [], []t = 0for i in range(n):t += stepx_list.append(x1 + b_x * t + c_x * (t**2) + d_x * (t**3))y_list.append(y1 + b_y * t + c_y * (t ** 2) + d_y * (t ** 3))return x_list, y_list# plot character T in Times Roman Font
def plot_t_in_times_roman_font():points = [[(237, 620), (237, 620), (237, 120), (237, 120)],[(237, 120), (237, 35), (226, 24), (143, 19)],[(143, 19), (143, 19), (143, 0), (143, 0)],[(143, 0), (143, 0), (435, 0), (435, 0)],[(435, 0), (435, 0), (435, 19), (435, 19)],[(435, 19), (353, 23), (339, 36), (339, 109)],[(339, 109), (339, 108), (339, 620), (339, 620)],[(339, 620), (339, 620), (339, 620), (339, 620)],[(339, 620), (507, 620), (529, 602), (552, 492)],[(552, 492), (552, 492), (576, 492), (576, 492)],[(576, 492), (576, 492), (570, 662), (570, 662)],[(570, 662), (570, 662), (6, 662), (6, 662)],[(6, 662), (6, 662), (0, 492), (0, 492)],[(0, 492), (0, 492), (24, 492), (24, 492)],[(24, 492), (48, 602), (71, 620), (183, 620)],[(183, 620), (183, 620), (237, 620), (237, 620)]]for point_list in points:pass_points, control_points = [point_list[0], point_list[-1]], point_list[1:3]x_list, y_list = get_bezier_curve(pass_points, control_points)plt.plot(x_list, y_list, color='black')plt.title('Bezier Curve')# plt.show()plt.savefig("T_in_Times_Roman_Font.png")if __name__ == '__main__':# T in Times Roman Font with Bézier Curveplot_t_in_times_roman_font()
运行结果如下:
当前使用贝塞尔曲线可以生成数百种不同字体的字符,显示在计算机屏幕或者打印机上。尽管字体信息很多年来都是一个秘密,但是现在一部分在网上已经公开。因此,今天贝塞尔曲线(Bézier curve)是计算机辅助设计和制造的奠基石。