B样条曲线曲面和NURBS曲线曲面C语言算法源程序 下载本文

学习小结:前面学习了Bezier曲线,B样条基函数和B样条曲线的一些基础知识。掌握关键问题是一条B样条曲线间的多段曲线的光滑连接。因为现在是用多段Bezier曲线来描绘一条B样条曲线,所以问题变为两段Bezier曲线间光滑连接。两段Bezier曲线段(3次)B1和B2光滑连接的条件:

0

(1).要求B1和B2有共同的连接点,即G连续。

1

(2).要求B1和B2在连接点处有成比例的一阶导数,即G连续。由端点处的一阶导数

B?1(1)?3(P3?P2),B?2(0)?3(Q1?Q0),为实现G1连续,则有:

B?2(0)?B?1(1) 即:Q1?Q0?P3?P2 这也表明,P2,P 3(Q0),Q1三点共线。如下图表示了一条3次B样条曲线的所有控制多边形: (P) P 3

P

41112

P (P) (P)

510

P P

069

P P P

78

P P 图5.3次B样条曲线和所有控制多边形

012

图5中,P0至P6为原始3次B样条曲线控制多边形顶点,P至P是计算后最终形成B样条曲线控制多边形顶点。

图6.双二次(2x2)B样条曲面

6.B样条曲线曲面和NURBS曲线曲面的C语言实现算法源程序

#ifndef _mynurbs_h #ifndef _MYNURBS_H

1

2

#include \#include \

//*-*-*-*-*-*-*-*-*-*-*-*-*-*-* B样条基函数计算部分 *-*-*-*-*-*-*-*-*-*-*-*-*-* //确定参数u所在的节点区间下标 //n=m-p-1

//m为节点矢量U[]的最大下标 //p为B样条函数次数

int FindSource(int n,int p,float u,float U[]) {

int low,high,mid;

if(u==U[n+1])//特殊情况 return n; //进行二分搜索 low=p; high=n+1;

mid=(int)(low+high)/2; while(uU[mid]) {

if(u

low=mid;

mid=(int)(low+high)/2;

if(u>=U[mid]&&u

return mid; //返回区间下标 }

//计算所有非零B样条基函数并返回其值 //i为参数u所在的节点区间下标

void BasisFunction(int i,int p,float u,float U[],float N[]) {

int j,di,dp,k;

float tul,tur,left,right; float tmpN[50][50];

for(k=0;k<=p;k++) { dp=0;

for(di=i+p-k;di>=i-k;di--) {

if(u>=U[di]&&u

tmpN[di][0]=1; else

tmpN[di][0]=0; dp+=1;

for(j=1;j

tul=U[di+j]-U[di]; tur=U[di+j+1]-U[di+1]; if(tul!=0)

left=(u-U[di])/tul; else

left=0; if(tur!=0)

right=(U[di+j+1]-u)/tur; else

right=0;

tmpN[di][j]=left*tmpN[di][j-1]+right*tmpN[di+1][j-1]; } }

N[i-k]=tmpN[i-k][p]; } }

//----------------------------------------------------------------------- //计算基函数的1阶导数并保存在NP[]中 //i为参数u所在的节点区间下标 //p为B样条函数次数P>2

void DerBasisFunc(int i,int p,float u,float U[],float NP[]) {

int j,di,dp,k;

float tul,tur,left,right,saved,dl,dr; float tmpN[50][50];

for(k=0;k<=p;k++) { dp=0;

for(di=i+p-k;di>=i-k;di--) {

if(u>=U[di]&&u

tmpN[di][0]=0; dp+=1;

for(j=1;j