拉格朗日(Lagrange)曲线插值

作者:追风剑情 发布于:2017-4-27 23:33 分类:Algorithms

  已知若干个离散点的位置值和导数值,求经过这些点的插值多项式,是数学上熟知的Hermite插值问题。这一问题的明确提法是:已知函数f(t)在k+1个点{ti}处的函数值和导数值{f(j)(ti)},i=0,1,,k,j=0,1,,mi1要求确定一个N=m0+m1++mk1次的多项式P(t),满足下面的插值条件: P(j)(ti)=f(j)(ti)

  这样的多项式P(t)就是对于函数f(t)的Hermite插值多项式。数学上已经证明,这样的多项式是存在且唯一的。

一、Lagrange插值公式

  当j=0,m0=m1==mk=1时,f(j)(ti)为函数f(t)本身,这个问题就是熟知的Lagrange插值问题,即已知f(t)在k+1个点上的函数值f(ti),求一个k次多项式使之满足P(ti)=f(ti),i=0,1,,k

222222.png

式中,gi(t)是混合函数。

333333.png

使用此混合函数,使t=ti时,曲线P(t)通过给定的型值点f(ti)

任何类型的曲线都可以通过其控制点的线性组合来表示。

例如,当k=2,m0=m1=m2=1时,已知函数f(t)在三个点t0、t1和t2的函数值f(t0)、f(t1)和f(t2),则二次多项式P(t)为

P(t)=f(t0)g0(t)+f(t1)g1(t)+f(t2)g2(t)

式中,混合函数如下: {g0(t)=(tt1)(tt2)(t0t1)(t0t2)g1(t)=(tt0)(tt2)(t1t0)(t1t2)g2(t)=(tt0)(tt1)(t2t0)(t2t1)

  再如,设表示一条曲线的某个函数f(t)在四点t0t1t2t3的函数值f(t0)f(t1)f(t2)f(t3)。根据Lagrange插值法,则三次多项式P(t)可表示为 P(t)=f(t0)g0(t)+f(t1)g1(t)+f(t2)g2(t)+f(t3)g3(t) 式中 {g0(t)=(tt1)(tt2)(tt3)(t0t1)(t0t2)(t0t3)g1(t)=(tt0)(tt2)(tt3)(t1t0)(t1t2)(t1t3)g2(t)=(tt0)(tt1)(tt3)(t2t0)(t2t1)(t2t3)g3(t)=(tt0)(tt1)(tt2)(t3t0)(t3t1)(t3t2)

一般地,对于k+1个点Pi(i=0,1,,k),若曲线 P(t)=i=0kPigi(t) 表达式中gi(t)满足
1)gi(t)(i=0,1,,k)是连续的;
2)i=0kgi(t)=1
gi(t)(i=0,1,,k)称为混合(调和)函数或基函数,k+1个点Pi(i=0,1,,k)称为控制点。如果混合函数gi(t)(i=0,1,,k)使曲线经过这k+1个点Pi(i=0,1,,k),则这k+1个点Pi(i=0,1,,k)也称为型值点。混合函数定义了如何把控制点的向量值混合在一起,为描述曲线提供了很好的抽象。这样的函数很多,例如,直线段方程P(t)=P0(1t)+P1tg0(t)=1tg1(t)=t就是混合函数,它定义了型值点的线性混合(加权平均)。任何类型的曲线都可以通过其控制点的线性组合来表示,其中权值可以作为关于自由参数的混合函数来计算。


代码实现(C#版)


  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Windows.Forms;
  10.  
  11. namespace TestLine
  12. {
  13. public partial class Form1 : Form
  14. {
  15. public Form1()
  16. {
  17. InitializeComponent();
  18. }
  19.  
  20. private void Form1_Load(object sender, EventArgs e)
  21. {
  22.  
  23. }
  24.  
  25. protected override void OnPaint(PaintEventArgs e)
  26. {
  27. LagrangeCurve curve = new LagrangeCurve();
  28. curve.input.Add(new Vector2(0, 0));
  29. curve.input.Add(new Vector2(10, 10));
  30. curve.input.Add(new Vector2(20, 20));
  31. curve.input.Add(new Vector2(30, 30));
  32. curve.input.Add(new Vector2(40, 40));
  33.  
  34. curve.input.Add(new Vector2(50, 40));
  35. curve.input.Add(new Vector2(60, 30));
  36. curve.input.Add(new Vector2(70, 20));
  37. curve.input.Add(new Vector2(80, 10));
  38. curve.input.Add(new Vector2(90, 0));
  39.  
  40. for (float x = 0; x <= 90; x++)
  41. {
  42. float y = curve.Lerp(x);
  43. PaintPoint(e, x, y);
  44. }
  45. }
  46.  
  47. public void PaintPoint(PaintEventArgs e, float x, float y)
  48. {
  49. Graphics g = e.Graphics;
  50. Pen myPen = new Pen(Color.Red, 2);
  51. g.DrawEllipse(myPen, x, y, 2, 2);
  52. }
  53. }
  54.  
  55. public class Vector2
  56. {
  57. public float x;
  58. public float y;
  59.  
  60. public Vector2(float x, float y)
  61. {
  62. this.x = x;
  63. this.y = y;
  64. }
  65. }
  66.  
  67. /// <summary>
  68. /// 拉格朗日曲线插值类
  69. /// </summary>
  70. public class LagrangeCurve
  71. {
  72. //输入点(即,曲线要经过的点)
  73. public List<Vector2> keyPoint = new List<Vector2>();
  74.  
  75. public float Lerp(float x)
  76. {
  77. float y = 0;
  78. //构建input.Count个混合函数
  79. for (int i = 0; i < keyPoint.Count; i++)
  80. {
  81. float yi = keyPoint[i].y;
  82. float xi = keyPoint[i].x;
  83. float yj = 1;
  84. //每个混合函数需要遍历所有输入点(根据混合函数公式)
  85. for (int j = 0; j < keyPoint.Count; j++)
  86. {
  87. if (i != j)
  88. {
  89. float xj = keyPoint[j].x;
  90. yj *= (x - xj) / (xi - xj);
  91. }
  92. }
  93. y += yi * yj;
  94. }
  95. return y;
  96. }
  97. }
  98. }


运行测试

1111111.png

Unity拉格朗日曲线插值

标签: Algorithms

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号