C#,三次样条曲线插值的基本原理及源代码

C#,三次样条曲线插值的基本原理及源代码_第1张图片

 

发文初心

样条曲线插值应用挺多的,其实这方面的代码不少。

不过都有一些缺憾,大家使用起来不便利,因而特意改编一个供初学者使用。

本文的程序改编自:

三次样条曲线插值的基本原理及其C#实现_仿真专家的博客-CSDN博客_三次样条曲线声明:本人空间的所有文章,若无特别声明,皆为本人原创,可自由转载,但要注明原作者和原始出处,不可作为商业用途。 下面的内容是直接从Word文档复制粘贴出来的,有很多内容丢失,完整的PDF版本可到百度网盘下载:链接:https://pan.baidu.com/s/1aEc0htnERV3I75hLq4fFsA 密码:wf6t三次样条曲线插值的基本原理及其C#实现作...https://blog.csdn.net/simxpert/article/details/80330256

上面的算法与程序有很大的局限性:

(1)仅仅适用于相对简单的、只能从左到右、不能折弯的曲线插值,比如 ECharts 内的曲线插值。

(2)仅限于二维;

(3)计算效率比较低;

(4)数据点分布比较复杂的时候无法计算;

工业化的插值应该选用更好的、更高效的算法与代码,比如双三次B样条,T样条及 NURBS 等等。

C#,三次样条曲线插值的基本原理及源代码_第2张图片

 

三次样条曲线插值的算法与源代码

using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;

namespace Legalsoft.Truffer
{
    /// 
    /// 三次样条曲线插值(2D)
    /// 
    public class Spline_Interpolation
    {
        private double[] Xi { get; set; }
        private double[] Yi { get; set; }
        private double[] A { get; set; }
        private double[] B { get; set; }
        private double[] C { get; set; }
        private double[] H { get; set; }
        private double[] Lamda { get; set; }
        private double[] Mu { get; set; }
        private double[] G { get; set; }
        private int N { get; set; } = 0;
        private int n { get; set; } = 0;
        private double[] M;

        public Spline_Interpolation()
        {
        }

        /// 
        /// 应用演示代码
        /// 
        public static void Drive()
        {
            #region 构建实验数据
            Random rnd = new Random();
            int num = 10;
            double[] xx = new double[num];
            double[] yy = new double[num];
            for (int i = 0; i < num; i++)
            {
                xx[i] = i + rnd.NextDouble() * 0.1;
                yy[i] = rnd.NextDouble();
            }
            #endregion

            #region 曲线插值与绘制
            Spline_Interpolation spline = new Spline_Interpolation();
            spline.Initialize(xx, yy);
            double xv = xx[0];
            double last_xv = xv;
            double last_yv = yy[0];
            while (xv < xx[num - 1])
            {
                double yv = spline.Interpolate(xv);
                if (last_xv > xv)
                {
                    // 绘制线段
                    //g.DrawLine(pen, last_xv, last_yv, xv, yv);
                }
                last_xv = xv;
                last_yv = yv;
                xv += 0.01;
            }
            #endregion
        }

        public bool Initialize(double[] Xi, double[] Yi)
        {
            if (Xi.Length != Yi.Length)
            {
                return false;
            }
            if (Xi.Length == 0)
            {
                return false;
            }

            // 根据给定的Xi,Yi元素的数目来确定N的大小。
            N = Xi.Length;
            n = N - 1;

            // 根据实际大小给各个成员变量分配内存
            A = new double[N - 1];
            B = new double[N];
            C = new double[N - 1];

            this.Xi = new double[N];
            this.Yi = new double[N];

            H = new double[N - 1];
            Lamda = new double[N - 1];
            Mu = new double[N - 1];

            G = new double[N];

            // 把输入数据点的数值赋给成员变量。
            for (int i = 0; i <= n; i++)
            {
                this.Xi[i] = Xi[i];
                this.Yi[i] = Yi[i];
            }

            // 求出hi,Lamda(i),Mu(i),gi
            GetH();
            GetLamda_Mu_G();
            GetABC();

            // 调用追赶法求出系数矩阵M
            Chasing_Solver chase = new Chasing_Solver();
            if (chase.Initialize(A, B, C, G))
            {
                if (chase.Solve(out M))
                {
                    return true;
                }
            }
            return false;
        }

        private void GetH()
        {
            for (int i = 0; i < n; i++)
            {
                H[i] = Xi[i + 1] - Xi[i];
            }
        }

        private void GetLamda_Mu_G()
        {
            for (int i = 1; i < n; i++)
            {
                Lamda[i] = H[i] / (H[i] + H[i - 1]);
                Mu[i] = 1.0 - Lamda[i];

                double t1 = (Yi[i] - Yi[i - 1]) / H[i - 1];
                double t2 = (Yi[i + 1] - Yi[i]) / H[i];
                G[i] = 3.0 * (Lamda[i] * t1 + Mu[i] * t2);
            }
            G[0] = 3.0 * (Yi[1] - Yi[0]) / H[0];
            G[n] = 3.0 * (Yi[n] - Yi[n - 1]) / H[n - 1];
            Mu[0] = 1.0;
            Lamda[0] = 0.0;
        }

        private void GetABC()
        {
            for (int i = 1; i < n; i++)
            {
                A[i - 1] = Lamda[i];
                C[i] = Mu[i];
            }
            A[n - 1] = 1.0;
            C[0] = 1.0;
            for (int i = 0; i <= n; i++)
            {
                B[i] = 2.0;
            }
        }

        private double fai0(double x)
        {
            double t1 = 2.0 * x + 1.0;
            double t2 = (x - 1.0) * (x - 1.0);
            return t1 * t2;
        }

        private double fai1(double x)
        {
            return x * (x - 1.0) * (x - 1.0);
        }

        private int GetSection(double x)
        {
            for (int i = 0; i < n; i++)
            {
                if (x <= Xi[i])
                {
                    return i - 1;
                }
            }
            return -999999;// iNum;
        }

        /// 
        /// 按x值计算y值(插值计算)
        /// 
        /// 
        /// 
        public double Interpolate(double x)
        {
            double t = x;
            int iNum = GetSection(x);
            if (iNum == -1)
            {
                return Yi[0];
            }
            else if (iNum == -999999)
            {
                return Yi[n];
            }
            double P1 = (t - Xi[iNum]) / H[iNum];
            double P2 = (Xi[iNum + 1] - t) / H[iNum];
            return Yi[iNum] * fai0(P1) +
                Yi[iNum + 1] * fai0(P2) +
                M[iNum] * H[iNum] * fai1(P1) -
                M[iNum + 1] * H[iNum] * fai1(P2);
        }

    }
}

求解严格对角占优的对角方程组的追赶法

using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;

namespace Legalsoft.Truffer
{
    /// 
    /// 求解严格对角占优的对角方程组的追赶法
    /// 
    public class Chasing_Solver
    {
        /// 
        /// Dimension of Martrix Ax=d
        /// 
        private int N { get; set; }
        /// 
        /// Ax=d
        /// 
        private double[] d { get; set; }
        /// 
        /// a in A
        /// 
        private double[] Aa { get; set; }
        /// 
        /// b in A
        /// 
        private double[] Ab { get; set; }
        /// 
        /// c in A
        /// 
        private double[] Ac { get; set; }
        /// 
        /// LU-->L
        /// 
        private double[] L { get; set; }
        /// 
        /// LU-->U
        /// 
        private double[] U { get; set; }
        /// 
        /// store the result
        /// 
        private double[] S { get; set; }

        public Chasing_Solver()
        {
        }

        /// 
        /// 数据初始化
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public bool Initialize(double[] a, double[] b, double[] c, double[] d)
        {
            int na = a.Length;
            int nb = b.Length;
            int nc = c.Length;
            int nd = d.Length;

            if (nb < 3)
            {
                return false;
            }
            N = nb;

            if (na != N - 1 || nc != N - 1 || nd != N)
            {
                return false;
            }
            S = new double[N];
            L = new double[N - 1];
            U = new double[N];

            Aa = new double[N - 1];
            Ab = new double[N];
            Ac = new double[N - 1];
            this.d = new double[N];

            for (int i = 0; i <= N - 2; i++)
            {
                Ab[i] = b[i];
                this.d[i] = d[i];
                Aa[i] = a[i];
                Ac[i] = c[i];
            }

            Ab[N - 1] = b[N - 1];
            this.d[N - 1] = d[N - 1];
            return true;
        }

        /// 
        /// 追赶法求解器
        /// 
        /// 
        /// 
        public bool Solve(out double[] R)
        {
            #region A=LU
            R = new double[Ab.Length];
            U[0] = Ab[0];
            for (int i = 2; i <= N; i++)
            {
                // L[i] = Aa[i] / U[i - 1];
                L[i - 2] = Aa[i - 2] / U[i - 2];
                //U[i]=Ab[i]-Ac[i-1]*L[i];
                U[i - 1] = Ab[i - 1] - Ac[i - 2] * L[i - 2];
            }
            #endregion

            #region Ly=d
            double[] Y = new double[d.Length];
            Y[0] = d[0];

            for (int i = 2; i <= N; i++)
            {
                //Y[k]=d[k]-L[k]*Y[k-1];
                Y[i - 1] = d[i - 1] - (L[i - 2]) * (Y[i - 2]);

            }
            #endregion

            #region Ux=Y
            //X[n]=Y[n]/U[n];
            R[N - 1] = Y[N - 1] / U[N - 1];
            //X[k]=(Y[k]-C[k]*X[k+1])/U[k];(n-1,,.....1)
            for (int i = N - 1; i >= 1; i--)
            {
                R[i - 1] = (Y[i - 1] - Ac[i - 1] * R[i]) / U[i - 1];
            }
            #endregion

            for (int i = 0; i < R.Length; i++)
            {
                if (double.IsInfinity(R[i]) || double.IsNaN(R[i]))
                {
                    return false;
                }
            }
            return true;
        }
    }
}

C#,三次样条曲线插值的基本原理及源代码_第3张图片

 

你可能感兴趣的:(C#计算几何,Graphics,Recipes,c#,开发语言,样条曲线插值)