栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

【Python】3次B样条曲线反求控制顶点

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Python】3次B样条曲线反求控制顶点

3次B样条曲线反求控制顶点 1. 说明
  • 代码不完善,因为方程组的边界条件不太清楚,总是有问题。。。。
2. 边界条件取二次样条在端点处切矢
  • 该边界条件指的是新增方程组条件,端点处的导数为二次样条在端点处的导数。
# 基函数
def N(i,k,T,t):  # 曲线N_ik
    if k == 0:
        if tT[i+1]:
            return 0
        else:
            return 1
    else:
        result = (t-T[i])/(T[i+k]-T[i])*N(i,k-1,T,t) + (T[i+k+1]-t)/(T[i+k+1]-T[i+1])*N(i+1,k-1,T,t)
        return result

def Inter_func(P,judge):  # 抛物线插值函数  传入参数为(坐标点,判断条件)    判断条件:0表示前三个,1表示后三个
    x = P.tolist()[0]
    y = P.tolist()[1]
    if judge == 0:
        value = 2*x[0]*((x[1]-x[2])*y[0]+(x[2]-x[0])*y[1]+(x[0]-x[1])*y[2])-np.power(x[1],2)*(y[0]-y[2])-np.power(x[2],2)*(y[1]-y[0])-np.power(x[0],2)*(y[2]-y[1])
        value = value/((x[0]-x[1])*(x[0]-x[2])*(x[1]-x[2]))
    else:
        value = 2*x[2]*((x[1]-x[2])*y[0]+(x[2]-x[0])*y[1]+(x[0]-x[1])*y[2])-np.power(x[1],2)*(y[0]-y[2])-np.power(x[2],2)*(y[1]-y[0])-np.power(x[0],2)*(y[2]-y[1])
        value = value/((x[0]-x[1])*(x[0]-x[2])*(x[1]-x[2]))
    return value


# 曲线绘制
def B_curve_inverse(k,n,P_,zero_num):
    P = P_
    # 取前三个插值点
    P_first = np.array(P)[:,:3]
    # 前三个插值点传入抛物线插值函数,返回一个在第一个点处的导数
    p0_diff = Inter_func(P_first,0)  # P0点的导数值
    p0 = (np.array([P_first[0][0],P_first[1][0]])-np.array([P_first[0][0],p0_diff])/3).tolist()
    P = np.insert(P,0,p0,axis=1)   #将该点的导数插入
    
    # 取后三个插值点
    P_last =  np.array(P)[:,-3:]
    # 后三个插值点传入抛物线插值函数,返回一个在最后一个点处的导数
    pn_diff = Inter_func(P_last,1)  # Pn点的导数值
    pn = (np.array([P_last[0][2],P_last[1][2]])+np.array([P_last[0][2],pn_diff])/3).tolist()
    P = np.insert(P,len(P[0]),pn,axis=1)   #将该点的导数插入
    
    # 获取系数矩阵
    coef = []
    for i in range(len(P[0])):
        
        if i == 0:
            col = [-1,1]+np.repeat(0,zero_num+1).tolist()# 将一行系数的0进行填充
            coef.append(col)
        elif i == len(P[0])-1:
            col = np.repeat(0,zero_num+1).tolist()+[-1,1]# 将一行系数的0进行填充
            coef.append(col)
        else:
#             print(zero_num-i+1)
            col = np.repeat(0,i-1).tolist()+[1/6,4/6,1/6]+np.repeat(0,zero_num-i+1).tolist()
            coef.append(col)
    
    coef1 = np.matrix(coef).I  # 系数矩阵取逆
    V = coef1*np.matrix(P).T   # 获得控制顶点
    V = V.T.tolist()          # 将控制顶点矩阵变为2*(n+2)的list
                              # 控制顶点的x=V[0],控制顶点的y=V[1]

    # 绘制曲线
    T = np.linspace(0,1,k+len(V[0])+1)  # T存储节点
    t_x = np.linspace(0,1,100) # t_x存储每一个t值
    X = V[0]
    Y = V[1]
    x = [] # 用来存储曲线的x值
    y = [] # 用来存储曲线的y值
    for i in range(len(V[0])-k):  # for循环用作获取第几条曲线段的数值
        result = pd.DataFrame(t_x,columns=['t'])
        for j in range(k+1):
            result1 = []
            for t in t_x:
                result1.append(N(i+j,k,T,t))
            result['N_{0}{1}'.format(i+j,k)] = result1  # 将N_ij存入dataframe
        # 把Dataframe中 T[i+k]<=t<=T[i+k+1] 的数据取出来 保存为 matrix, 然后用matrix*np.matrix(X[i:i+k+1]).T获取曲线的x值
        
        # lambda x: x>T[i+k] and x= 或 <= 曲线有时会有问题 比如 V = [[0,0,2,3,2,1],[1,3,3,2,1,1]]
        Ni_matrix = np.matrix(result[result['t'].apply(lambda x: x>=T[i+k] and x<=T[i+k+1])].iloc[:,1:]) # Ni_matrix 是一个 t_ba*j 维矩阵
        
        x = x+((Ni_matrix*np.matrix(X[i:i+k+1]).T).T).tolist()[0]
        y = y+((Ni_matrix*np.matrix(Y[i:i+k+1]).T).T).tolist()[0]
        

    fig = plt.figure()
#     plt.plot(V[0],V[1],marker='o',markerfacecolor='white')
#     print(V)
    plt.plot(P_[0],P_[1],'o')
    plt.plot(x,y)
    plt.show()
    return coef

# 参数传入

# P = np.array([[0,1,10,12,15],[0,10,8,6,1]]).astype(float).tolist()  # 插值点
P = np.array([[1,2,3,4,4,5,7,8],[1,2,5,2,1.5,1,0.5,-1.5]]).astype(float).tolist()  # 插值点
# P = np.array([[1,2,3,4,5],[0,10,8,6,1]]).astype(float).tolist()  # 插值点
n =len(P[0]) # 插值点个数
k = 3  # 样条曲线次数
zero_num = n+2-k  # 矩阵需要补0的个数
# print(zero_num)
coef = B_curve_inverse(k,n,P,zero_num)
3. 边界条件取0
  • 该边界条件指的是新增方程组条件,使得 P 0 = P 1 , P n − 1 = P n P_0=P_1,P_{n-1}=P_n P0​=P1​,Pn−1​=Pn​。
# 基函数
def N(i,k,T,t):  # 曲线N_ik
    if k == 0:
        if tT[i+1]:
            return 0
        else:
            return 1
    else:
        result = (t-T[i])/(T[i+k]-T[i])*N(i,k-1,T,t) + (T[i+k+1]-t)/(T[i+k+1]-T[i+1])*N(i+1,k-1,T,t)
        return result

def Inter_func(P,judge):  # 抛物线插值函数  传入参数为(坐标点,判断条件)    判断条件:0表示前三个,1表示后三个
    x = P.tolist()[0]
    y = P.tolist()[1]
    if judge == 0:
        value = 2*x[0]*((x[1]-x[2])*y[0]+(x[2]-x[0])*y[1]+(x[0]-x[1])*y[2])-np.power(x[1],2)*(y[0]-y[2])-np.power(x[2],2)*(y[1]-y[0])-np.power(x[0],2)*(y[2]-y[1])
        value = value/((x[0]-x[1])*(x[0]-x[2])*(x[1]-x[2]))
    else:
        value = 2*x[2]*((x[1]-x[2])*y[0]+(x[2]-x[0])*y[1]+(x[0]-x[1])*y[2])-np.power(x[1],2)*(y[0]-y[2])-np.power(x[2],2)*(y[1]-y[0])-np.power(x[0],2)*(y[2]-y[1])
        value = value/((x[0]-x[1])*(x[0]-x[2])*(x[1]-x[2]))
    return value


# 曲线绘制
def B_curve_inverse(k,n,P_,zero_num):
    P = P_
    # 取前三个插值点
    P_first = np.array(P)[:,:3]
    # 前三个插值点传入抛物线插值函数,返回一个在第一个点处的导数
    p0_diff = Inter_func(P_first,0)  # P0点的导数值
    p0 = (np.array([P_first[0][0],P_first[1][0]])-np.array([P_first[0][0],p0_diff])/3).tolist()
#     P = np.insert(P,0,p0,axis=1)   #将该点的导数插入
    P = np.insert(P,0,[0,0],axis=1)
    
    # 取后三个插值点
    P_last =  np.array(P)[:,-3:]
    # 后三个插值点传入抛物线插值函数,返回一个在最后一个点处的导数
    pn_diff = Inter_func(P_last,1)  # Pn点的导数值
    pn = (np.array([P_last[0][2],P_last[1][2]])+np.array([P_last[0][2],pn_diff])/3).tolist()
#     P = np.insert(P,len(P[0]),pn,axis=1)   #将该点的导数插入
    P = np.insert(P,len(P[0]),[0,0],axis=1)
    
    # 获取系数矩阵
    coef = []
    for i in range(len(P[0])):
        
        if i == 0:
            col = [-1,1]+np.repeat(0,zero_num+1).tolist()# 将一行系数的0进行填充
            coef.append(col)
        elif i == len(P[0])-1:
            col = np.repeat(0,zero_num+1).tolist()+[-1,1]# 将一行系数的0进行填充
            coef.append(col)         
        else:
#             print(zero_num-i+1)
            col = np.repeat(0,i-1).tolist()+[1/6,4/6,1/6]+np.repeat(0,zero_num-i+1).tolist()
            coef.append(col)
    
    coef1 = np.matrix(coef).I  # 系数矩阵取逆
    V = coef1*np.matrix(P).T   # 获得控制顶点
    V = V.T.tolist()          # 将控制顶点矩阵变为2*(n+2)的list
                              # 控制顶点的x=V[0],控制顶点的y=V[1]
#     V = [[1,1.5,3,3.8,3.2,5,8],[0,2.6,3,2.2,-0.3,-0.8,2]]
    # 绘制曲线
    T = np.linspace(0,1,k+len(V[0])+1)  # T存储节点
    t_x = np.linspace(0,1,100) # t_x存储每一个t值
    X = V[0]
    Y = V[1]
    x = [] # 用来存储曲线的x值
    y = [] # 用来存储曲线的y值
    for i in range(len(V[0])-k):  # for循环用作获取第几条曲线段的数值
        result = pd.DataFrame(t_x,columns=['t'])
        for j in range(k+1):
            result1 = []
            for t in t_x:
                result1.append(N(i+j,k,T,t))
            result['N_{0}{1}'.format(i+j,k)] = result1  # 将N_ij存入dataframe
        # 把Dataframe中 T[i+k]<=t<=T[i+k+1] 的数据取出来 保存为 matrix, 然后用matrix*np.matrix(X[i:i+k+1]).T获取曲线的x值
        
        # lambda x: x>T[i+k] and x= 或 <= 曲线有时会有问题 比如 V = [[0,0,2,3,2,1],[1,3,3,2,1,1]]
        Ni_matrix = np.matrix(result[result['t'].apply(lambda x: x>=T[i+k] and x<=T[i+k+1])].iloc[:,1:]) # Ni_matrix 是一个 t_ba*j 维矩阵
        
        x = x+((Ni_matrix*np.matrix(X[i:i+k+1]).T).T).tolist()[0]
        y = y+((Ni_matrix*np.matrix(Y[i:i+k+1]).T).T).tolist()[0]
        

    fig = plt.figure()
#     plt.plot(V[0],V[1],marker='o',markerfacecolor='white')
# #     print(V)
    plt.plot(P_[0],P_[1],'o')
    plt.plot(x,y)
    plt.show()
    return coef,V,np.matrix(P).T

# 参数传入

# P = np.array([[0,1,2,3,4],[0,2,6,4.5,3]]).astype(float).tolist()  # 插值点
P = np.array([[1,2,3,4,4.5,5,7,8],[1,2,5,2,1.3,1,0.5,-1.5]]).astype(float).tolist()  # 插值点
# P = np.array([[1,2,3,4,5],[0,10,8,6,1]]).astype(float).tolist()  # 插值点
n =len(P[0]) # 插值点个数
k = 3  # 样条曲线次数
zero_num = n+2-k  # 矩阵需要补0的个数
# print(zero_num)
coef,V,p = B_curve_inverse(k,n,P,zero_num)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/932474.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号