1.具体任务其相关采用技术
学习和理解Bezier曲线与等距曲线的相关知识。通过调查分析,形成需求分析报告,确定系统框架。设计Bezier曲线与其给定距离的等距曲线算法,实现输入给定的Bezier曲线与等距距离,能够输出等距曲线。采用C语言完成程序的编写。
Bezier曲线是参数多项式曲线,它由一组控制多边形折现(控制多边形)顶点惟一地定义。如图所示,在控制多边形的各定点中,只有第一个和最后一个顶点在曲线上,其他的顶点则用以定义曲线的倒数、阶次和形状,改变多边形的顶点就会改变曲线的形状。Bezier曲线的数学基础是能在第一个和最后一个顶点之间进行插值的一个多项式混合函数。通常的参数方程表示如下:
其中,Pi构成该Bezier曲线的特征多边形,Bi,n(t)是n次Bernstein基函数:
00 =1, 0!=1
Bezier曲线实例如图1所示。
图1 三次Bezier曲线
等距曲线(offset curve)也称为平行或位差曲线,是其曲线沿法线向距离为常熟的点的轨迹。若在而为空间中已知一条曲线C,让C上每一点均沿C在相应点的法线方向移动同等距离d,得到一系列点,这些新点的轨迹C1就称为C的等距曲线,如图所示。常见的生成等距曲线的方法包括平行线法、临界值法和拟合法等。计算等距曲线广泛应用于CAD设计、数控加工刀具半径偏置计算等领域。
2、设计思想及实现过程
2、1 de Casteljau算法描述
计算Bezier曲线上的点,可用Bezier曲线方程,但使用de Casteljau提出的递推算法则要简单得多。
如图2所示,设P0、P02、P2是一条抛物线上顺序三个不同的点。过P0和P2点的两切线交于P1点,在P02点的切线交P0P1和P2P1于P01和P11,则如下比例成立:
这是所谓抛物线的三切线定理。
图2抛物线三切线定理
当P0,P2固定,引入参数t,令上述比值为t:(1-t),即有:
t从0变到1,第一、二式就分别表示控制二边形的第一、二条边,它们是两条一次Bezier曲线。将一、二式代入第三式得:
当t从0变到1时,它表示了由三顶点P0、P1、P2三点定义的一条二次Bezier曲线。并且表明:这二次Bezier曲线P02可以定义为分别由前两个顶点(P0,P1)和后两个顶点(P1,P2)决定的一次Bezier曲线的线性组合。依次类推,由四个控制点定义的三次Bezier曲线P03可被定义为分别由(P0,P1,P2)和(P1,P2,P3)确定的二条二次Bezier曲线的线性组合,由(n+1)个控制点Pi(i=0,1,...,n)定义的n次Bezier曲线P0n可被定义为分别由前、后n个控制点定义的两条(n-1)次Bezier曲线P0n-1与P1n-1的线性组合:
由此得到Bezier曲线的递推计算公式:
上式中:Pi0=Pi是定义Bezier曲线的控制点,P0n即为曲线P(t)上具有参数t的点。用这一递推公式,在给定参数下,求Bezier曲线上一点P(t)非常有效。是计算Bezier曲线的基本算法和标准算法。
当n=3时,de casteljau算法递推出的Pik呈直角三角形,对应结果如图3所示。从左向右递推,最右边点P03即为曲线上的点。
图3 n=3时,Pin的递推关系
这一算法可用简单的几何作图来实现。给定参数,就把定义域分成长度为t:(1-t)的两段。依次对原始控制多边形每一边执行同样的定比分割,所得分点就是第一级递推生成的中间顶点Pi1(i=0,1,...,n-1),对这些中间顶点构成的控制多边形再执行同样的定比分割,得第二级中间顶点Pi2(i=0,1,...,n-2)。重复进行下去,直到n级递推得到一个中间顶点P0n即为所求曲线上的点P(t),如图4所示。
图4几何作图法求Bezier曲线上一点(n=3,t=1/4)
2、2 实现过程
2、2、1 数据输入
程序运行后显示键入控制点的个数以及相应的坐标,键盘输入,存入数组以待后续操作。
2、2、2 数据处理
利用de Casteljau提出的递推法则对输入数据进行相应的处理。
函数原型:
float decas(float *p,float t, int n)
其中*p为当前点的横纵坐标值,以步长为0.001连续变化,n为输入的控制点的个数。
2、2、3 结果输出
利用计算出的各点p的值,利用line函数将各点连接起来形成Bezier曲线图像,在屏幕上显示输出。
3 编码实现
#include
#include
float decas(float *p,float t, int n) /*de Casteljau递推函数*/
{
int i, r;
float q[10];
for(i=0;i<=n;i++)
q[i]=p[i];
for(r=1;r<=n;r++)
{
for(i=0;i<=n-r;i++)
{
q[i]=(1-t)*q[i]+t*q[i+1];
}
}
return(q[0]);
}
main( )
{
int gdriver=DETECT,gmode,i,n;
float t,x,y,px[10],py[10];
initgraph(&gdriver,&gmode, "" "" ); /*屏幕模式初始化*/
printf(""ninput max_point:""); /*输入控制点的个数*/
scanf(""%d"",&n);
for(i=0;i<=n-1;i++) /*输入各控制点的坐标值*/
{
printf(""ninput %d:n"",i+1);
scanf(""%f,%f"",&px[i],&py[i]);
}
setcolor(RED);
for(i=0;i {
line(px[i],py[i],px[i+1],py[i+1]);
circle(px[i],py[i],5);
}
circle(px[n-1],py[n-1],5);
setcolor(BLUE);
for(t=0;t<=1;t+=0.001) /*以步长为0.001改变t值,调用decas*/
{
x=decas(px,t,n-1);
y=decas(py,t,n-1);
if(t==0)
moveto(x,y);
else
lineto(x,y);
}
getch();
closegraph();
}