学习小结:前面学习了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;