根据Bezier曲线的定义公式实现Bezier曲线的绘制

Bezier曲线的定义公式

在这里插入图片描述
Pi是曲线上点的坐标(x,y,(z=0)), Bi,n(t)伯恩斯坦公式,绘制Bezier曲线的第一种方法是根据这个公式来绘制。首先看看绘制的效果:
在这里插入图片描述

(1)计算定义中多项式的值

在这里插入图片描述
首先要求伯恩斯坦公式的多项式的值Cni,写成后面这种阶乘的形式方便用程序去表达了:

//计算定义中多项式的值
void GetCnk(GLint n,GLint *c)//n是控制点的个数,C用来存多项式值的数组
{
	GLint i,j;
	for(j=0;j<n;j++){//循环前先从n!中把i!消掉,注意体会
		c[j]=1;
		for(i=n-1;i>=j+1;i--)
			c[j]=c[j]*i;
		for(i=n-1-j;i>=2;i--)
			c[j]=c[j]/i;
	}
}

(2)计算曲线上点的坐标

在这里插入图片描述
Pi是曲线上点的坐标(x,y,(z=0)),所以我们可以把p(t)表示成三个坐标分量的形式:
在这里插入图片描述
在这里插入图片描述

//计算曲线上点的坐标
void GetPointPr(GLint *c,GLfloat t,Pt3D *Pt,GLint ControlN,Pt3D *ControlP)
{//c是存多项式值的数组,t是参数值,Pt是曲线上某点坐标,ControlN是控制点个数,ControlP是控制点坐标
	GLint i,n=ControlN;
	GLfloat Berstein;
	Pt->x=0.0;Pt->y=0.0;Pt->z=0.0;
	for(i=0;i<ControlN;i++){
		Berstein=c[i]*pow(t,i)*pow(1-t,n-1-i);
		Pt->x+=ControlP[i].x*Berstein;
		Pt->y+=ControlP[i].y*Berstein;
		Pt->z+=ControlP[i].z*Berstein;
	}
}

(3)根据求出的坐标绘制Bezier曲线

void Bezierdraw(GLint m,GLint ControlN,Pt3D *ControlP)
{//m是曲线上点的个数,ControlN是控制点个数,ControlP是控制点坐标
	GLint *C,i;
	Pt3D CurvePt;//保存当前点坐标
	C=new GLint[ControlN];//存多项式系数的数组C
	GetCnk(ControlN,C);
	glColor3f(1.0,0.0,0.0);
	glPointSize(3);//曲线画粗点和控制图形区分
	glBegin(GL_POINTS);
	for(i=0;i<=m;i++){
		GetPointPr(C,(GLfloat)i/m,&CurvePt,ControlN,ControlP);
		glVertex2f(CurvePt.x,CurvePt.y);
	}
	glEnd();
	delete [] C;
}

总的代码:

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

//计算定义中多项式的值
void GetCnk(GLint n,GLint *c)//n是控制点的个数,C用来存多项式值的数组
{
	GLint i,j;
	for(j=0;j<n;j++){//循环前先从n!中把i!消掉,注意体会
		c[j]=1;
		for(i=n-1;i>=j+1;i--)
			c[j]=c[j]*i;
		for(i=n-1-j;i>=2;i--)
			c[j]=c[j]/i;
	}
}

//计算曲线上点的坐标
void GetPointPr(GLint *c,GLfloat t,Pt3D *Pt,GLint ControlN,Pt3D *ControlP)
{//c是存多项式值的数组,t是参数值,Pt是曲线上某点坐标,ControlN是控制点个数,ControlP是控制点坐标
	GLint i,n=ControlN;
	GLfloat Berstein;
	Pt->x=0.0;Pt->y=0.0;Pt->z=0.0;
	for(i=0;i<ControlN;i++){
		Berstein=c[i]*pow(t,i)*pow(1-t,n-1-i);
		Pt->x+=ControlP[i].x*Berstein;
		Pt->y+=ControlP[i].y*Berstein;
		Pt->z+=ControlP[i].z*Berstein;
	}
}

//根据控制点,画曲线上的500个点
void Bezierdraw(GLint m,GLint ControlN,Pt3D *ControlP)
{//m是曲线上点的个数,ControlN是控制点个数,ControlP是控制点坐标
	GLint *C,i;
	Pt3D CurvePt;//保存当前点坐标
	C=new GLint[ControlN];//存多项式系数的数组C
	GetCnk(ControlN,C);
	glColor3f(1.0,0.0,0.0);
	glPointSize(3);//曲线画粗点和控制图形区分
	glBegin(GL_POINTS);
	for(i=0;i<=m;i++){
		GetPointPr(C,(GLfloat)i/m,&CurvePt,ControlN,ControlP);
		glVertex2f(CurvePt.x,CurvePt.y);
	}
	glEnd();
	delete [] C;
}
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 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 (400, 400); 
	glutInitWindowPosition (100, 100);
	//打开窗口
	glutCreateWindow ("根据定义");
	//调用初始化函数
    myinit();
	//设定窗口大小变化的回调函数
	glutReshapeFunc(myReshape);
	//开始OPENGL的循环
	glutDisplayFunc(display); 
	glutMainLoop();
	return 0;
}

不过这样做计算量很大,要用公式把所有曲线上的点都绘制出来,不适于工程,更加简单、快捷、效率高的是de Castel jau的递推算法实现Bezier曲线的绘制,我写在了另一篇文章中https://blog.csdn.net/derbi123123/article/details/105317678

  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值