opengl 鼠标控制三点完成BezierCurve(学习笔记-仅供参考)

#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;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值