#define NDEBUG
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace std;
struct XPoint { // 定义顶点,为避免与Point名称冲突,改为XPoint
int x, y;
XPoint()//构造函数,无参数
{
x = 0;
y = 0;
}
XPoint(int ptx, int pty)//构造函数
{
x = ptx;
y = pty;
}
};
vector<XPoint> cpt, bzpt; // cpt:控制点集, bzpt:Bezier曲线点集
bool bDraw; // 是否显示Bezier曲线
int nInput; // 输入控制顶点的数量,全局变量默认值为0
// 计算Bezier曲线上点的坐标
void CalcBZPoints()
{
float a0, a1, a2, a3, b0, b1, b2, b3;
//cpt[0]是第一个点P0,cpt[1]是第二个点P1...
a0 = cpt[0].x;//a0,常数项
a1 = -3 * cpt[0].x + 3 * cpt[1].x;//a1,t的系数
a2 = 3 * cpt[0].x - 6 * cpt[1].x + 3 * cpt[2].x;//a2,t^2的系数
a3 = -cpt[0].x + 3 * cpt[1].x - 3 * cpt[2].x + cpt[3].x;//a3,t^3的系数
b0 = cpt[0].y;
b1 = -3 * cpt[0].y + 3 * cpt[1].y;
b2 = 3 * cpt[0].y - 6 * cpt[1].y + 3 * cpt[2].y;
b3 = -cpt[0].y + 3 * cpt[1].y - 3 * cpt[2].y + cpt[3].y;
int num = 10; // 曲线分段数量
float dt = 1 / (float)num;
bzpt.resize(num + 1); //改变容器容量,扩容元素默认为0
float t = 0;
for (unsigned int i = 0; i < bzpt.size(); i++)//生成Bezier曲线上的各个点
{
bzpt[i].x = a0 + a1 * t + a2 * t * t + a3 * t * t * t;
bzpt[i].y = b0 + b1 * t + b2 * t * t + b3 * t * t * t;
t = t + dt;
}
}
void ControlPoint(vector<XPoint> cpt)//画点
{
glPointSize(3);
glBegin(GL_POINTS);
for (unsigned int i = 0; i < cpt.size(); i++)
glVertex2i(cpt[i].x, cpt[i].y);
glEnd();
}
void PolylineGL(vector<XPoint> cpt)//画折线
{
glBegin(GL_LINE_STRIP);
for (unsigned int i = 0; i < cpt.size(); i++)
glVertex2i(cpt[i].x, cpt[i].y);
glEnd();
}
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
//glColor3f(0.0f, 0.0f, 0.0f);
glPointSize(10);
glBegin(GL_POINTS);
glColor3f(1.0f, 1.0f, 0.0f); glVertex2i(0, 0);// 显示坐标原点位置
glEnd();
if (cpt.size() > 0) {//cpt.size容器中点的数量
glColor3f(1.0f, 1.0f, 1.0f);
ControlPoint(cpt);//画点
PolylineGL(cpt);//画折线
}
if (bDraw)//bDraw为true,画Bezier曲线
{
CalcBZPoints();//生成Bezier曲线上的各个点
glColor3f(1.0f, 0.0f, 0.0f);
PolylineGL(bzpt);//画Bezier曲线
}
glFlush();
}
void Init()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);//控制绘制指定顶点间颜色的过渡模式,GL_SMOOTH渐变
printf("Please Click left button of mouse to input control Point of Bezier Curve...\n");
}
void Reshape(int w, int h)
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);//视区函数,(0,0)左下角坐标,w宽,h高
glMatrixMode(GL_PROJECTION);//投影矩阵
glLoadIdentity();//单位矩阵
gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h);//平行投影,X:0.0~w, Y:0.0~h,y坐标从下到大增大,x坐标从左向右增大
}
void mouse(int button, int state, int x, int y)//y坐标从上到下增大,x坐标从左向右增大
{
//XPoint pt;
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
switch (nInput)//nInput计算鼠标点击的次数
{
case 0://鼠标未曾点击,或者,开始新的一轮点击
cpt.clear();//将cpt容器清空
cpt.push_back(XPoint(x, 480 - y));//新入的点加入在后面
nInput++;//鼠标点击次数加1
bDraw = false;//是否显示曲线,false,不显示
glutPostRedisplay();//窗口重新绘制,调用绘制函数
break;
case 1://已经点击过1次
cpt.push_back(XPoint(x, 480 - y));
nInput++;
glutPostRedisplay();
break;
case 2://已经点击过2次
cpt.push_back(XPoint(x, 480 - y));
nInput++;
glutPostRedisplay();
break;
case 3://已经点击过3次
cpt.push_back(XPoint(x, 480 - y));
nInput = 0;//nInput为0,为新一轮点击作准备
bDraw = true;//表示显示曲线
glutPostRedisplay();
break;
default:
break;
}
}
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(100, 100);
glutInitWindowSize(640, 480);
glutCreateWindow("Hello Bezier Curve");
Init();
glutDisplayFunc(myDisplay);
glutReshapeFunc(Reshape);
glutMouseFunc(mouse);//响应鼠标
/*
void glutMouseFunc(void(*func)(int button,int state,int x,int y));
button: 哪个鼠标键被按下或松开,GLUT_LEFT_BUTTON,GLUT_MIDDLE_BUTTON,GLUT_RIGHT_BUTTON
state: 鼠标状态,是被按下或松开,GLUT_DOWN,GLUT_UP
x,y: 鼠标在当前窗口坐标
*/
glutMainLoop();
return 0;
}
opengl 鼠标控制三点完成BezierCurve(学习笔记-仅供参考)
最新推荐文章于 2021-05-17 21:38:10 发布