计算机图形学中的拉格朗日插值算法

本文介绍了拉格朗日插值的基本原理,该方法能够直接计算通过任意n+1个点的n次曲线,而无需预先求解方程系数。为解决实际应用中大量点的计算问题,文中提出了一种通过引入参数t并限定最高三次方程的方法,以减少计算复杂度。同时提供了一个具体的程序实例。
摘要由CSDN通过智能技术生成

大家都知道,通过两个点的一次曲线,有且只有一条,通过三个点的二次曲线,有且仅有一条。概括来讲,通过n+1个点的n次曲线,有且仅有一条。那么给定n+1个点,如何确定这个n次方程的n+1个系数呢?即已知这n+1个点的坐标,求x到y的映射。因为这里有n+1个未知数,n+1个等式,我们可以利用矩阵解方程来求解这些系数,但这计算量很大。拉格朗日提出了一个方法,不需要实现求解任何系数即可直接带入运算来求解。简单来讲就是,

。(我们可以理解为表示在结果中占的权重)

但在实际应用中,点的数量可能非常巨大,最后会导致方程次数非常高,所以通常选定3次方程作为上限,然后每次处理4个点。采用这个思想,我们可以建立y与x之间的映射,然后依次求解。但这时候仍然有个问题,每次面对不同的4个点的时候,必须重新去更新的值。

为了解决这个问题,我们给空间在增加一个维度t(事实上我们可以假定t即表示点的顺序),然后分别建立x到t和y到t的映射,即。因为我们每次都是选用的4个点,我们可以每次都给他们指定,这样 的值是不变的,也就是说我们在计算出来后就不必再去更新它了。

 

下面的程序代码是我根据校内教材上的源码修改的,更改了函数接口,并修正了其中的一个边界BUG。

(程序中指定

ContractedBlock.gif ExpandedBlockStart.gif Code
void Lugrange(int coordinate[][2],int k, int l_section,CDC *pDC)//coordinate控制点坐标k点数量l_section相邻点之间描绘曲线时的中间点数量

ExpandedBlockStart.gifContractedBlock.gif
{

     
float blend[4][50];

     
float f_blend[4][50];

     
float l_blend[4][50];

     
float xsm[4];

     
float ysm[4];

     
float x=0,y=0;

     
for(int i=0;i<l_section;i++)

ExpandedSubBlockStart.gifContractedSubBlock.gif     
{

         
float u=(float)i/(float)l_section;//根据l_section指定步长

         blend[
0][i]=u*(u-1)*(u-2)/(-6);//用于中间段的插值

         blend[
1][i]=(u+1)*(u-1)*(u-2)/2.0;

         blend[
2][i]=(u+1)*u*(u-2)/(-2);

         blend[
3][i]=(u+1)*u*(u-1)/6.0;

        

         
float v=u-1;

         f_blend[
0][i]=v*(v-1)*(v-2)/(-6);//用于首段的插值

         f_blend[
1][i]=(v+1)*(v-1)*(v-2)/2.0;

         f_blend[
2][i]=(v+1)*v*(v-2)/(-2);

         f_blend[
3][i]=(v+1)*v*(v-1)/6.0;

 

         
float w=u+1;

        l_blend[
0][i]=w*(w-1)*(w-2)/(-6.0);//用于末端的插值

         l_blend[
1][i]=(w+1)*(w-1)*(w-2)/2.0;

         l_blend[
2][i]=(w+1)*w*(w-2)/(-2);

         l_blend[
3][i]=(w+1)*w*(w-1)/6.0;

     }


     
for(int i=0;i<4;i++)

ExpandedSubBlockStart.gifContractedSubBlock.gif     
{      

         xsm[i]
=coordinate[i][0];    

         ysm[i]
=coordinate[i][1];    

     }


     pDC
->MoveTo(coordinate[0][0],coordinate[0][1]);//计算首段

     
for(int j=0;j<l_section;j++)

ExpandedSubBlockStart.gifContractedSubBlock.gif     
{

         x
=y=0;

         
for(int i=0;i<4;i++)

ExpandedSubBlockStart.gifContractedSubBlock.gif         
{      

              x
+=xsm[i]*f_blend[i][j];    

              y
+=ysm[i]*f_blend[i][j];    

         }


         pDC
->LineTo(x,y);

     }


     
for(int m=4;m<=k;m++)//每次往后移一个点,取个点计算中间段曲线

ExpandedSubBlockStart.gifContractedSubBlock.gif     
{

         
for(int j=0;j<=l_section;j++)//4个点计算中间段曲线

ExpandedSubBlockStart.gifContractedSubBlock.gif         
{

              x
=y=0;

            
for(int i=0;i<4;i++)

ExpandedSubBlockStart.gifContractedSubBlock.gif              
{

                   x
+=xsm[i]*blend[i][j]; 

                   y
+=ysm[i]*blend[i][j]; 

              }


              pDC
->LineTo(x,y);

         }


         
if(m==k) break;

         
for(int i=0;i<3;i++)//往后移一个点

ExpandedSubBlockStart.gifContractedSubBlock.gif         
{

              xsm[i]
=xsm[i+1];   

              ysm[i]
=ysm[i+1];

         }


         xsm[
3]=coordinate[m][0];    

         ysm[
3]=coordinate[m][1];

     }


     
for(int j=0;j<l_section;j++)//计算末端

ExpandedSubBlockStart.gifContractedSubBlock.gif     
{

         x
=y=0;

         
for(int i=0;i<4;i++)

ExpandedSubBlockStart.gifContractedSubBlock.gif         
{

              x
+=xsm[i]*l_blend[i][j];    

              y
+=ysm[i]*l_blend[i][j];    

         }


         pDC
->LineTo(x,y);

     }


     pDC
->LineTo(xsm[3],ysm[3]);

}

转载于:https://www.cnblogs.com/logicnut/archive/2009/06/07/1497979.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值