三次樣條曲線(參數方程)python實現

參考

# -- coding: utf-8 --
"""
@Project: lecture
@Time : 2020/4/29 21:54
@Author : Yang xu
@Site : 
@File : parameter equation.py
@IDE: PyCharm
"""
import numpy as np
import matplotlib.pyplot as plt
from pylab import mpl


class SPLINE(object):
    def __init__(self, p, p_):
        self.p = p  # 型值點
        self.p_ = p_  # 端點矢切
        self.n = len(p)  # 型值點數
        self.s = self.n - 1  # 線段數
        self.t = np.zeros(self.s)
        self.m = np.zeros((self.n, self.n))
        self.C_y = []
        self.A = []
        self.B = []
        self.C = []
        self.D = []
        self.samples_t = []
        self.samples_s = []

    def caculate_t(self):
        # 線段數量
        # self.s = len(self.p)-1
        # self.t = np.zeros(self.s)
        for i in range(self.s):
            self.t[i] = np.sqrt((self.p[i+1][0]-self.p[i][0])**2 + (self.p[i+1][1]-self.p[i][1])**2)

        return self.t

    def caculate_matrix(self):
        # t = SPLINE.caculate_t(p)
        # n = len(p)
        # self.m = np.zeros((n, n))
        for i in range(self.n):
            for j in range(self.n):
                if i == 0 and j == 0 or i == self.n-1 and j == self.n-1:
                    self.m[i][j] = 1
                elif i == 0 and j == 1 or i == self.n-1 and j == self.n-2:
                    self.m[i][j] = 0
                elif i == j:  # i不可能等於0
                    self.m[i][j] = 2*(self.t[i]+self.t[i-1])
                elif i+1 == j:  # i不可能到n-1
                    self.m[i][j] = self.t[i]
                elif i-1 == j:  # i不可能等於0
                    self.m[i][j] = self.t[i-1]
        return self.m

    def caculate_C_y(self):
        # n = len(p)
        # C = np.zeros(n)
        for i in range(self.n):
            if i == 0:
                # self.C_y[i] = self.p_[i]
                self.C_y.append(self.p_[i])
            elif i == self.n-1:
                # self.C_y[i] = self.p_[self.n-1]
                self.C_y.append(self.p_[self.n-1])
            else:
                temp = self.t[i-1] * self.t[i] * \
                (3 * (self.p[i+1] - self.p[i]) / self.t[i] ** 2 + 3 * (self.p[i] - self.p[i-1]) / self.t[i-1] ** 2)
                self.C_y.append(temp)
        self.C_y = np.array(self.C_y)
        return self.C_y

    def caculate_vector_cut(self):
        temp = np.linalg.solve(self.m, self.C_y)
        self.p_ = np.array(temp)
        return temp

    def caculate_parameter(self):
        for i in range(self.s):
            A = 2*(self.p[i] - self.p[i + 1]) / self.t[i] ** 3 + (self.p_[i + 1] + self.p_[i]) / self.t[i] ** 2
            self.A.append(A)
            B = 3*(self.p[i+1]-self.p[i])/self.t[i]**2 - (2*self.p_[i] + self.p_[i+1])/self.t[i]
            self.B.append(B)
            C = self.p_[i]
            self.C.append(C)
            D = self.p[i]
            self.D.append(D)
        self.A = np.array(self.A)
        self.B = np.array(self.B)
        self.C = np.array(self.C)
        self.D = np.array(self.D)
        return self.A, self.B, self.C, self.D

    # def caculate_S_t(self, i, t):
    #     return self.A[i] * t**3 + self.B[i] * t**2 + self.C[i]*t + self.D[i]

    def grasp_sample(self):
        for i in range(self.s):
            sample_t = np.arange(0, self.t[i], 0.01)
            sample_s = []
            for t in sample_t:
                S_t = self.A[i] * t**3 + self.B[i] * t**2 + self.C[i]*t + self.D[i]
                sample_s.append(S_t)
            # sample_y = calculate(result[(i - 1) * 4:i * 4], sample_x)
            self.samples_t.extend(sample_t)
            self.samples_s.extend(sample_s)
        self.samples_t.append(self.t[-1])
        s_t = self.A[-1] * self.t[-1]**3 + self.B[-1] * self.t[-1]**2 + self.C[-1]*self.t[-1] + self.D[-1]
        self.samples_s.append(s_t)
        self.samples_t = np.array(self.samples_t)
        self.samples_s = np.array(self.samples_s)

    def show_view(self):
        plt.plot(self.samples_s[:,0], self.samples_s[:,1], label="擬合曲線", color="black")
        plt.scatter(self.p[:,0], self.p[:,1], label="離散數據", color="red")
        mpl.rcParams['font.sans-serif'] = ['SimHei']
        mpl.rcParams['axes.unicode_minus'] = False
        plt.title("三次樣條函數")
        plt.legend(loc="upper left")
        plt.show()

    def __str__(self):
        return "型值點數={}\n線段數={}\n型值點={}\n端點矢切={}\n線段長度={}\n求矢切的矩陣={}\n求矢切的C={}\n" \
               "參數A={}\n參數B={}\n參數C={}\n參數D={}\n繪圖t={}\n繪圖點={}\n".format(self.n, self.s, self.p, self.p_,
                self.t, self.m, self.C_y, self.A, self.B, self.C, self.D, self.samples_t, self.samples_s)

    __repr__ = __str__


if __name__ == '__main__':
    p = [[0,0],[0,2],[3,2]]
    p_ = [[-1,1],[],[2,-1]]  # 維度必須n*2
    p = np.array(p)
    p_ = np.array(p_)
    spline = SPLINE(p, p_)
    spline.caculate_t()
    spline.caculate_matrix()
    spline.caculate_C_y()
    spline.caculate_vector_cut()
    spline.caculate_parameter()
    spline.grasp_sample()
    spline.show_view()
    print(spline)

一個三次樣條曲線題目(需要設參數方程解)

擬合後的圖形

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章