贝塞尔曲线Bezier curve
现代机械设计方法,图形软件标准,样条曲线和曲面,图形变换
贝塞尔曲线
贝塞尔曲线简介
贝塞尔曲线(Bezier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。
特性:
- 使用
个(有序)控制点 来控制曲线的形状 - 曲线经过起点
和终点 ,但不经过中间点 - 贝塞尔曲线方程,方程的最高次数即是曲线的阶
应用:
- photoshop中的钢笔工具就是应用的三次贝塞尔曲线
贝塞尔曲线推导
- 二阶贝塞尔曲线的绘制
已知
这就是抛物线的三切线定理,最终形成的二级贝塞尔曲线(抛物线)被直线
上述方程使用点
阶贝塞尔曲线的绘制
- 已知
个不共线的控制点 - 相邻点连接成
条线段 ,并在各个线段上找到 阶动点 共 个动点 - 相邻点连接成
条线段 ,并在各个线段上找到 阶动点 共 个动点 - ……
- 相邻点连接成的最后
条线段 ,并在线段上找到 阶动点 共 个动点 - 这些动点
动点满足 : - 动点集合
就是 阶贝塞尔曲线
可视化例子
一阶(两个控制点),即直线,曲线方程为一次多项式
三阶(四个控制点),曲线方程为三次多项式:
五阶(六个控制点),曲线方程为五次次多项式:
代码实现
N=length(control_points);
ta=zeros(N,N);%%对数组进行初始化
%%杨辉三角左右两边的值赋1
%%贝塞尔曲线方程的系数
% 杨辉三角的数的规律
% 1
% 1 1
% 1 2 1
% 1 3 3 1
% 1 4 6 4 1
for i=1:N
ta(i,1)=1;
ta(i,i)=1;
end
%%从第二个数开始,也就是从第三行开始,等于前列的左边加上正上方的一个
for row=2:N
for col=2:row
ta(row,col)=ta(row-1,col-1)+ta(row-1,col);
end
end
%%曲线生成
for i=1:M
t=i/M;%%确定每一个点的比例
for k=0:N-1
c=k;%分别确定a,b,c三个系数
b=N-c-1;%分别确定a,b,c三个系数
a=ta(N,k+1);%分别确定a,b,c三个系数
p(i,1)=p(i,1)+a*(1-t)^b*t^c*control_points(k+1,1);%确定点的x坐标
p(i,2)=p(i,2)+a*(1-t)^b*t^c*control_points(k+1,2);%确定点的y坐标
end
end
import numpy as np
import matplotlib.pyplot as plt
from scipy.special import comb
def inputPoints():
controlPoints = []
num = 1
while True:
print('\nenter %dst control point:'%num)
x = input('x:')
y = input('y:')
#z = input('z:')
print('Point:[%f,%f]'%(float(x),float(y)))
i = input('Are you sure?(y or n)')
if i=='y' or i=='Y':
controlPoints.append([float(x),float(y)])
inp = input('continue entering points or not?(y or n)')
num = num + 1
if inp == 'n':
break
else:
continue
#print(controlPoints)
return controlPoints
def getInterpolationPoints(controlPoints, tList):
n = len(controlPoints)-1
interPoints = []
for t in tList:
Bt = np.zeros(2, np.float64)
for i in range(len(controlPoints)):
Bt = Bt + comb(n,i) * np.power(1-t,n-i) * np.power(t,i) * np.array(controlPoints[i])
interPoints.append(list(Bt))
return interPoints
if __name__ == '__main__':
# points = inputPoints()
points = [[1,1],[3,4],[5,5],[7,2]]
tList = np.linspace(0,1,50)
interPointsList = getInterpolationPoints(points, tList)
x = np.array(interPointsList)[:,0]
y = np.array(interPointsList)[:,1]
plt.plot(x,y,color='b')
plt.scatter(np.array(points)[:,0],np.array(points)[:,1],color='r')
plt.show()
B样条曲线
贝塞尔曲线方程是对
其中,
可以发现,单独的一个控制点对整体曲线影响较大,曲线阶次过高(阶次与控制节点数量相关)
本质上就是在控制点前增加一个权重函数,然后加和;对权重函数进行修改,并使得控制点仅仅能影响局部形状,这就是B样条曲线(basic spline curve)的设计思路
B样条曲线的数学描述
对于
其中,
显然,
B样条曲线的次数指基函数多项式
节点向量(kont vector)是一个一维单调非递减序列,元素
在节点向量中,若某节点
基函数
所以B样条曲线可视为若干段贝塞尔曲线的拼接,是贝塞尔曲线的推广,相邻贝塞尔曲线间存在若干重合节点,保留了对称性、几何不变性、变差伸缩性等优良特性。
B样条曲线分类
节点向量(kont vector)是一个一维单调非递减序列
根据节点分布的性质,可以将样条曲线进行分类
- 均匀 B 样条:节点均匀分布,所有节点区间等长
- 准均匀 B 样条:在开始和结束处的节点可重复,中间节点均匀分布;节点向量中的首末节点重复度为
,其余节点沿数轴方向等距均匀分布且重复度为1。当 时,B样条基函数 退化为伯恩斯坦多项式,即B样条曲线退化为贝塞尔曲线。 - 非均匀 B 样条:节点非均匀分布,可任意分布
- 分段贝塞尔曲线
- NURBS曲线:B样条无法描述圆锥曲线,为解决此问题,产生了非均匀有理B样条(non-uniform rational b-spline, NURBS)
(准/非)均匀B样条曲线
对于
其 k次均匀
例如,令
其 k次准均匀
例如,令
其 k次非均匀
例如,令
代码实现
import numpy as np
import matplotlib.pyplot as plt
# 计算在某一特定t下的 B_{i,k}
def getBt(controlPoints, knots, t):
# calculate m,n,k
m = knots.shape[0]-1
n = controlPoints.shape[0]-1
k = m - n - 1
# initialize B by zeros
B = np.zeros((k+1, m))
# get t region
tStart = 0
for x in range(m+1):
if t==1:
tStart = m-1
if knots[x] > t:
tStart = x-1
break
# calculate B(t)
for _k in range(k+1):
if _k == 0:
B[_k, tStart] = 1
else:
for i in range(m-_k):
if knots[i+_k]-knots[i]== 0:
w1 = 0
else:
w1 = (t-knots[i])/(knots[i+_k]-knots[i])
if knots[i+_k+1]-knots[i+1] == 0:
w2 = 0
else:
w2 = (knots[i+_k+1]-t)/(knots[i+_k+1]-knots[i+1])
B[_k,i] = w1*B[_k-1, i] + w2*B[_k-1, i+1]
return B
# 绘制 B_{i,k}(t)函数
def plotBt(Bt,num, i,k):
print(k,i)
Bt = np.array(Bt)
tt = np.linspace(0,1,num)
yy = [Bt[t,k,i] for t in range(num)]
plt.plot(tt, yy)
# 根据最后一列(最高阶次)的 B(t),即权重,乘以控制点坐标,从而求出曲线上点坐标
def getPt(Bt, controlPoints):
Bt = np.array(Bt)
ptArray = Bt.reshape(-1,1) * controlPoints
pt = ptArray.sum(axis = 0)
return pt
# 绘制出生成的样条曲线: useReg 表示是否使用曲线有效定义域[t_k, t_{m-k}]
def main1(useReg = False):
controlPoints = np.array([[50,50], [100,300], [300,100], [380,200], [400,600]])
knots = np.array([0,1/9,2/9,3/9,4/9,5/9,6/9,7/9,8/9,1])
m = knots.shape[0]-1
n = controlPoints.shape[0]-1
k = m - n - 1
print('n:',n)
print('m:',m)
print('k:',k)
for t in np.linspace(0,1,100):
if useReg and not(t >= knots[k] and t<= knots[n+1]):
continue
Bt = getBt(controlPoints, knots, t)
Pt = getPt(Bt[k, :n+1], controlPoints)
plt.scatter(Pt[0],Pt[1],color='b')
plt.scatter(controlPoints[:,0], controlPoints[:,1],color = 'r')
plt.show()
# 绘制 B_{i,k} 变化图:如果不给定{i,k}则显示所有B{i,k}(t)图像
def main2(i=-1,k=-1):
controlPoints = np.array([[50,50], [100,300], [300,100], [380,200], [400,600]])
knots = np.array([0,1/9,2/9,3/9,4/9,5/9,6/9,7/9,8/9,1])
m = knots.shape[0]-1
n = controlPoints.shape[0]-1
k = m - n - 1
print('n:',n)
print('m:',m)
print('k:',k)
B = []
num = 100 # 离散点数目
for t in np.linspace(0,1,num):
Bt = getBt(controlPoints, knots, t)
B.append(list(Bt))
figure1 = plt.figure('B_{i,k}')
if i==-1:
fig = []
for i in range(n+1):
for k in range(k+1):
plotBt(B,num, i,k)
fig.append('B_{%d,%d}'%(i,k))
else:
plotBt(B,num, i,k)
fig.append('B_{%d,%d}'%(i,k))
plt.legend(fig)
plt.show()
if __name__ == '__main__':
main1()
main2()
Nurbs曲线
ISO规定,PHIGS Plus的扩充部分,Bezier、有理Bezier、均匀B样条和非均匀B样条都被统一到NURBS 中。
B样条曲面、及其特例的Bezier曲面都不能精确表示除抛物面以外的二次曲面,而只能给出近似表示
在曲线曲面描述中,B样条方法更多地以非均匀类型出现,而均匀、准均匀、分段Bezier三种类型又被看成是非均匀类型的特例,所以习惯上称之为非均匀有理B样条(Non-Uniform Rational B-Splines)方法,简称为NURBS方法
NURBS方法提出的主要理由是,寻找与描述自由曲线曲面的B样条方法相统一的,而又能精确表示二次曲线曲面的数学方法
- 非均匀B样条采用分段参数整数多项式,而NURBS方法采用分子分母分别是分段参数多项式函数与分段多项式的分式表示,是有理的
- 与有理Bezier方法一样,NURBS方法引入了权因子和分母NURBS方法是在有理Bezier方法与非有理B样条方法的基础上发展起来的
NURBS的优点主要表现在以下几个方面:
- 将初等曲线曲面与自由曲线曲面的表达方式统一起来
- 增加了权因子,有利于对曲线曲面形状的控制和修改
- 非有理B样条、有理与非有理Bezier方法是NURBS的特例
- 在比例、旋转、平移、错切以及平行和透视投影变换下是不变的
NURBS曲线有三种表示方法:
- 分式表示是有理的由来,它说明:NURBS曲线是非有理与有理Bézier和非有理B样条曲线的推广:但却难以从中了解更多的性质。
- 在有理基函数表示形式中,可从有理基函数的性质清楚地了解NURBS曲线的性质。
- 齐次坐标表示形式说明:NURBS曲线是它的控制顶点的齐次坐标或带权控制点在高一维空间里所定义的非有理B样条曲线在
超平面上的投影。 - 不仅包含了明确的几何意义,而且也说明:非有理B样条曲线的大多数算法都可以推广应用于NURBS曲线。
核心是其精心设计的数据结构,包括控制点网格、权重数组、 knot向量等,利用NumPy进行数值计算,NURBS-Python库具有高度的兼容性和性能,NURBS-Python支持多种格式的导入和导出,如IGES和STEP
矢量函数
一条
式中,
节点矢量
为求简化,可令:
则
示例
7个控制点
则可计算出
Frenet框架
曲线的曲率和挠率,切矢量、法矢量、次法矢量
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)