/*输入点的个数是可以手动改动的,此程序中输入点的最大值设置为.
*同时,程序实现了键盘的交互,用来控制程序运行过程中的退出、重画等
*/
#include<GL/glut.h>
#include<stdlib.h>
int W,H; //屏幕的大小
int N =-1; //贝赛尔曲线的幂次
GLfloat Bfunc[15]={0.0}; //Bernstein多项式的值的数组
GLfloat point[15][2]={0.0}; //存储控制点的坐标
void Init()
{
//设置清除颜色为白色
glClearColor(1.0f,1.0f,1.0f,1.0f);
}
void ChangeSize(int w, int h)
{
GLfloat nRange = 1.0f;
if(h == 0) h = 1;
glViewport(0, 0, w, h);
W = w;
H = h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// 设置修剪空间
if (w <= h)
glOrtho (0.0, 0.0, -nRange*h/w, nRange*h/w, 0.0, 0.0);
else
glOrtho (-nRange*w/h, nRange*w/h, 0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void Bezier()
{
int i,j,t;
GLfloat u;
//使用的绘制点坐标
GLfloat DPoint1[2];
GLfloat DPoint2[2];
//先将第一个控制点赋给第二个点,为后面的循环做准备
for(i=0;i<2;i++)
DPoint2[i]=point[0][i];
glClear(GL_COLOR_BUFFER_BIT);
//设置控制点的颜色
glColor3f(1.0f,0.0f,0.0f);
//设置控制点的大小
glPointSize(5);
//绘制控制点
glBegin(GL_POINTS);
for(i=0;i<=N;i++)
{
glVertex2fv(point[i]);
}
glEnd();
//设置连接控制点线的颜色
glColor3f(0.0f, 0.0f, 0.0f);
//设置连线的宽度
glLineWidth(3);
//绘制连线
glBegin(GL_LINE_STRIP);
for(i=0;i<=N;i++)
glVertex2fv(point[i]);
glEnd();
//设置Bezier曲线的颜色
glColor3f(1.0f, 0.0f, 0.0f);
//设置线宽
glLineWidth(2);
for(i=0;i<=1000;i++)
{
//获得u值
u =i / 1000.0;
//初始化Bfunc数组
for(t=0;t<=N;t++)
Bfunc[t]=1.0;
//第一个点的坐标等于第二个点的坐标,方便下面的绘制
DPoint1[0]=DPoint2[0];
DPoint1[1]=DPoint2[1];
//将第二个坐标的x,y设置为
DPoint2[0]=0.0;
DPoint2[1]=0.0;
//循环、递推计算Bezier基函数的值
for(j=0;j<=N;j++)
{
if(j==0)
{
//V0处的Bezier基函数
Bfunc[j] = 1;
for(t=N;t>j;t--)
Bfunc[j] = Bfunc[j]*(1-u);
}
else
{
if(i != 1000)
Bfunc[j]=(1.0 * ( N - j + 1 ) / j ) * ( u / ( 1 - u ) ) * Bfunc[j-1];
else
{
//Bfunc[N]处的Bezier基函数
if(j == N)
for(t=0;t<N;t++)
Bfunc[j]=Bfunc[j]*u;
else
Bfunc[j]=0.0;
}
}
//获得第二个点的坐标值
DPoint2[0] = DPoint2[0]+Bfunc[j]*point[j][0];
DPoint2[1] = DPoint2[1]+Bfunc[j]*point[j][1];
}
//连接两点
if(N>=1)
{
glBegin(GL_LINES);
glVertex2fv(DPoint1);
glVertex2fv(DPoint2);
glEnd();
}
}
glFlush();
}
//鼠标事件获得控制点的坐标
void InitMouse(int button,int state,int x,int y)
{
//如果不是点击鼠标左键的状态,则不获得坐标值
if(button !=GLUT_LEFT_BUTTON||state !=GLUT_DOWN)
return;
if( N < 14 )
{
N++;
//获得鼠标点击的坐标
point[N][0] = (2.0*x)/(float)(W-1)-1.0;
point[N][1] = (2.0*(H-y))/(float)(H)-1.0;
//重绘
glutPostRedisplay();
}
}
//键盘响应
void keyboard(unsigned char key,int x,int y)
{
switch(key)
{
//退出运行系统
case'q':case'Q':
exit(0);
break;
//重画曲线
case'c':case'C':
N = 0;
glutPostRedisplay();
break;
//刷新
case'e':case'E':
glutPostRedisplay();
break;
}
}
void main(int argc,char* argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(50,100);
glutInitWindowSize(800,600);
glutCreateWindow("Bezier曲线绘制");
glutReshapeFunc(ChangeSize);
Init();
glutDisplayFunc(Bezier);
glutMouseFunc(InitMouse);
glutKeyboardFunc(keyboard);
glutMainLoop();
}
/*程序实现根据鼠标输入的点进行次B样条曲线的绘制,程序中鼠标
*输入点的个数是可以手动改动的,此程序中输入点的最大值设置为.
*同时,程序实现了键盘的交互,用来控制程序运行过程中的退出、重画等
*/
#include<GL/glut.h>
int W,H; //屏幕的大小
int N = -1; //控制点的个数
GLfloat point[25][2]={0.0}; //存储控制点坐标的数组
void Init()
{
//设置清除颜色为白色
glClearColor(1.0f,1.0f,1.0f,1.0f);
}
void ChangeSize(int w, int h)
{
GLfloat nRange = 1.0f;
if(h == 0) h = 1;
// 设置视区尺寸
glViewport(0, 0, w, h);
W = w;
H = h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// 设置修剪空间
if (w <= h)
glOrtho (0.0, 0.0, -nRange*h/w, nRange*h/w, 0.0, 0.0);
else
glOrtho (-nRange*w/h, nRange*w/h, 0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void BSpline()
{
int i;
glClear(GL_COLOR_BUFFER_BIT);
//设置控制点的颜色
glColor3f(1.0f, 0.0f, 0.0f);
//设置控制点的大小
glPointSize(5);
//绘制控制点
glBegin(GL_POINTS);
for(i=0;i<=N;i++)
glVertex2fv(point[i]);
glEnd();
//设置连接控制点的线的颜色
glColor3f(0.0f, 0.0f, 0.0f);
//设置连线的宽度
glLineWidth(3);
//绘制连线
glBegin(GL_LINE_STRIP);
for(i=0;i<=N;i++)
glVertex2fv(point[i]);
glEnd();
int j,k;
float a,b,c,d;
glColor3f(1.0,0.0,0.0);
//3次B样条曲线,由个控制点控制,循环画出每一段曲线
for(j=0;j<=N-3;j++)
{
glBegin(GL_LINE_STRIP);
for(k=0; k<=100;k++)
{
float x,y,t;
t = k/100.0;
//求基函数的值
a=(1-t)*(1-t)*(1-t)/6.0;
b=(3.0*t*t*t-6.0*t*t+4.0)/6.0;
c=(3.0*t*(1.0+t-t*t)+1.0)/6.0;
d=t*t*t/6.0;
//求出曲线上点的坐标
x=a*point[j][0]+b*point[j+1][0]+c*point[j+2][0]+d*point[j+3][0];
y=a*point[j][1]+b*point[j+1][1]+c*point[j+2][1]+d*point[j+3][1];
glVertex2f(x, y);
}
glEnd();
}
glFlush();
}
//鼠标事件获得点的坐标
void InitMouse(int button,int state,int x,int y)
{
if(button !=GLUT_LEFT_BUTTON||state !=GLUT_DOWN)
return;
if( N < 25 )
{
N++;
//获得鼠标点击的坐标
point[N][0] = (2.0*x)/(float)(W-1)-1.0;
point[N][1] = (2.0*(H-y))/(float)(H)-1.0;
//重绘
glutPostRedisplay();
}
}
//键盘响应
void keyboard(unsigned char key,int x,int y)
{
switch(key)
{
//退出运行系统
case'q':case'Q':
exit(0);
break;
//重画曲线
case'c':case'C':
N = 0;
glutPostRedisplay();
break;
//刷新
case'e':case'E':
glutPostRedisplay();
break;
}
}
void main(int argc,char* argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(50,100);
glutInitWindowSize(800,600);
glutCreateWindow("B样条绘制");
glutReshapeFunc(ChangeSize);
Init();
glutDisplayFunc(BSpline);
glutMouseFunc(InitMouse);
glutKeyboardFunc(keyboard);
glutMainLoop();
}