根据de Castel jau的递推算法实现Bezier曲线的绘制

de Castel jau的递推算法

(1)原理

在这里插入图片描述

(2)这么说很难看懂,举个例子结合理解:

在这里插入图片描述
首先画出控制点:
在这里插入图片描述
然后取两条曲线的1/3处的点并连线:
p01 中1表示第一层,也就是第一次取等比例的点,0表示这一层的第0个点,其他同理
在这里插入图片描述
在这里插入图片描述
再取连线上的1/3处的点:
在这里插入图片描述
显然p02 已经是最后一个可以取等比例处的曲线的点了,所以曲线上t=1/3处的点就是p02 ,同理可以求t=1/2、1/4.。。。处的点进而绘制出一条抛物线:
在这里插入图片描述

(3)根据上面的例子推导计算公式:

这样t=1/3处的点坐标就可以求出来:
在这里插入图片描述
把1式2式代入3式即可得出:
在这里插入图片描述
进而我们可以推出:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
k=0的时候也就是控制点
这就是著名的de Castel jau的递推算法,很便于求Bezier曲线上的一个点P(t);,这个算法稳定可靠,编程简单,是计算Bezier曲线的基本算法和标准算法。

下面是编程实现

效果:
在这里插入图片描述
一定要把递推式改成坐标分量式,也就是把P拆成x,y,z分别乘进去。

先给出这个算法的灵魂,也就是递推的实现

//用来获得参数t处对应曲线上点的坐标
void GetPointPr(GLfloat t,Pt3D *Pt,GLint ControlN,Pt3D *ControlP)
{//t是参数值,Pt是存某点坐标,ControlN是控制点个数,ControlP中存有控制点坐标
	GLint i,k,n=ControlN;
	Pt3D Pki[4][4];//存递推的各项的值
	for(i=0;i<n;i++){//K=0的情况,也就是控制点
		Pki[0][i].x=ControlP[i].x;
		Pki[0][i].y=ControlP[i].y;
	}
	//开始递推
	for(k=1;k<n;k++){
		for(i=0;i<n-k;i++){
			Pki[k][i].x=(1-t)*Pki[k-1][i].x+t*Pki[k-1][i+1].x;
			Pki[k][i].y=(1-t)*Pki[k-1][i].y+t*Pki[k-1][i+1].y;
		}
	}
	//对应曲线上的点的坐标就是k=n-1时的坐标
	Pt->x=Pki[n-1][0].x;
	Pt->y=Pki[n-1][0].y;
}

完整代码:

#include <GL/freeglut.h>
#include <math.h>
class Pt3D{
	public:
		GLfloat x,y,z;
};//坐标类

void myinit(void)
{
    glClearColor(1.0f,1.0f,1.0f,1.0f);
}
void myReshape(GLsizei w, GLsizei h)
{
	//设定视区
    glViewport(0, 0, w, h);

	//设定透视方式
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
	gluOrtho2D(-100.0,100.0,-100.0,100.0);
}
//计算曲线上某点的坐标
void GetPointPr(GLfloat t,Pt3D *Pt,GLint ControlN,Pt3D *ControlP)
{//t是参数值,Pt是存某点坐标,ControlN是控制点个数,ControlP中存有控制点坐标
	GLint i,k,n=ControlN;
	Pt3D Pki[4][4];//存递推的各项的值
	for(i=0;i<n;i++){//K=0的情况,也就是控制点
		Pki[0][i].x=ControlP[i].x;
		Pki[0][i].y=ControlP[i].y;
	}
	//开始递推
	for(k=1;k<n;k++){
		for(i=0;i<n-k;i++){
			Pki[k][i].x=(1-t)*Pki[k-1][i].x+t*Pki[k-1][i+1].x;
			Pki[k][i].y=(1-t)*Pki[k-1][i].y+t*Pki[k-1][i+1].y;
		}
	}
	Pt->x=Pki[n-1][0].x;
	Pt->y=Pki[n-1][0].y;
}
//根据控制点,画曲线上的500个点
void Bezierdraw(GLint m,GLint ControlN,Pt3D *ControlP)
{
	Pt3D CurvePt;//保存当前点坐标
	glColor3f(1.0,0.0,0.0);
	glPointSize(3);//曲线画粗点和控制图形区分
	glBegin(GL_POINTS);
	for(int i=0;i<=m;i++){
		GetPointPr((GLfloat)i/m,&CurvePt,ControlN,ControlP);
		glVertex2f(CurvePt.x,CurvePt.y);
	}
	glEnd();
}
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
	GLint ControlN=4;//4个控制点
	GLint m=500;//曲线由500个点绘制而成
	Pt3D ControlP[4]={{-80.0,-40.0,0.0},{-10.0,90.0,0.0},{10.0,-90.0,0.0},{80.0,40.0,0.0}};//控制点坐标
	//画曲线
	Bezierdraw(m,ControlN,ControlP);
	//画控制图形
	glColor3f(0.0,0.0,0.0);
	glBegin(GL_LINE_STRIP);
		for(int i=0;i<ControlN;i++){
			glVertex3f(ControlP[i].x,ControlP[i].y,ControlP[i].z);
		}
	glEnd();
	//交换前后缓冲区
	glutSwapBuffers();
}
int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	//初始化OPENGL显示方式
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA);
	//设定OPENGL窗口位置和大小
	glutInitWindowSize (500, 500); 
	glutInitWindowPosition (100, 100);
	//打开窗口
	glutCreateWindow ("递推算法");
	//调用初始化函数
    myinit();
	//设定窗口大小变化的回调函数
	glutReshapeFunc(myReshape);
	//开始OPENGL的循环
	glutDisplayFunc(display); 
	glutMainLoop();

	return 0;
}
  • 5
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值