计算机图形学—利用OpenGL绘制贝塞尔(Bézier)曲线

#include <iostream>
#include <GL/glut.h>

int detection(int x, int y);
void myMovedMouse(int x, int y);
double p_t(int n, int x, GLdouble t);

const int screenWidth = 600;
const int screenHeight = 480;

//顶点个数
static int length = 0;
//被检测到的顶点的位置
static int point_n = 0;
//--------------------数据结构部分---------------------

class Points;

//顶点类
class Point {
	friend class Points;
public:
	Point() {
		this->x = NULL;
		this->y = NULL;
		this->next = NULL;
	}
	Point(GLfloat x, GLfloat y) {
		this->x = x;
		this->y = y;
		this->next = NULL;
	}
private:
	GLfloat x;
	GLfloat y;
	Point* next;
};

//单链表类
class Points {
public:
	Points() {
		this->first = NULL;
	}
	void Add(GLfloat x, GLfloat y);
	float Traverse(int n, int z);
	void Alter(GLfloat x, GLfloat y, int n);
private:
	Point* first;
};

//添加顶点
void Points::Add(GLfloat x, GLfloat y) {
	Point* newPoint = new Point(x, y);
	if (length == 0 || first == NULL) {
		first = newPoint;
		length++;
	}
	else
	{
		Point* q = first;
		for (int i = 1; i < length; i++) {
			q = q->next;
		}
		newPoint->next = q->next;
		q->next = newPoint;
		length++;
	}
}

//遍历顶点
float Points::Traverse(int n, int z) {
	if (n != 0) {
		Point* q = first;
		for (int i = 1; i < n; i++) {
			q = q->next;
		}
		if (z == 0) {
			//z=0时返回X
			return q->x;
		}
		else
		{
			//z!=0时返回Y
			return q->y;
		}
	}
}

//修改顶点
void Points::Alter(GLfloat x, GLfloat y, int n) {
	if (n != 0) {
		Point* q = first;
		for (int i = 1; i < n; i++) {
			q = q->next;
		}
		q->x = x;
		q->y = y;
	}
}

//-----------------------OpenGL部分--------------------------

static Points points;

//初始化
void SetupRC() {
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glPointSize(3.0);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(-(GLdouble)screenWidth / 2, (GLdouble)screenWidth / 2, -(GLdouble)screenHeight / 2, (GLdouble)screenHeight / 2);
}

//绘制曲线和顶点
void draw() {
	glColor3f(1.0f, 1.0f, 0.f);
	glBegin(GL_LINE_STRIP);
	for (int i = 1; i <= length; i++) {
		GLfloat x = points.Traverse(i, 0);
		GLfloat y = points.Traverse(i, 1);
		glVertex2i(x, y);
	}
	glEnd();
	glColor3f(1.0f, 0.0f, 0.0f);
	glBegin(GL_POINTS);
	for (int i = 1; i <= length; i++) {
		GLfloat x = points.Traverse(i, 0);
		GLfloat y = points.Traverse(i, 1);
		glVertex2i(x, y);
	}
	glEnd();
	glColor3f(0.0f, 1.0f, 1.0f);
	glBegin(GL_LINE_STRIP);
	for (GLdouble t = 0; t < 1; t = t + 0.01)
	{
		float x = p_t(length, 0, t);
		float y = p_t(length, 1, t);
		glVertex2i(x, y);
	}
	glEnd();
}

//渲染
void RenderScene() {
	glClear(GL_COLOR_BUFFER_BIT);
	draw();
	glFlush();
}

//鼠标交互
void myMouse(int button, int state, int x, int y) {
	if (state == GLUT_DOWN) {
		if (button == GLUT_LEFT_BUTTON) {
			if (point_n = detection(x - (GLdouble)screenWidth / 2, screenHeight / 2 - y)) {
				std::cout << "检测到顶点:" << point_n << std::endl;
				glutMotionFunc(myMovedMouse);
			}
			else if (!detection(x - (GLdouble)screenWidth / 2, screenHeight / 2 - y)) {
				points.Add(x - (GLdouble)screenWidth / 2, screenHeight / 2 - y);
				RenderScene();
			}
		}
	}
}

//拖拽顶点
void myMovedMouse(int x, int y) {
	points.Alter(x - (GLdouble)screenWidth / 2, screenHeight / 2 - y, point_n);
	RenderScene();
}

//检测顶点
int detection(int x, int y) {
	for (int i = 1; i <= length; i++) {
		GLfloat p_x = points.Traverse(i, 0);
		GLfloat p_y = points.Traverse(i, 1);
		if (x - 10 < p_x && p_x < x + 10) {
			if (y - 10 < p_y && p_y < y + 10) {
				return i;
			}
		}
	}
	return 0;
}

//De Casteljau算法
double p_t(int n, int z, GLdouble t) {
	double p[100][100];
	for (int i = 0; i <= n - 1; i++) {
		p[0][i] = points.Traverse(i + 1, z);
	}
	for (int r = 1; r <= n - 1; r++) {
		for (int i = n - 1; i >= r; i--) {
			p[r][i] = (1 - t) * p[r - 1][i - 1] + t * p[r - 1][i];
		}
	}
	return p[n - 1][n - 1];
}

int main(int argc, char** argv) {
	glutInit(&argc, argv);
	points.Add(0 * 20, 0 * 20);
	points.Add(2 * 20, 2 * 20);
	points.Add(2 * 20, -1 * 20);
	points.Add(4 * 20, 0 * 20);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	//设置初始窗口的位置(窗口左上角相对于桌面坐标(x, y))
	glutInitWindowPosition(100, 100);
	//设置初始窗口的大小
	glutInitWindowSize(screenWidth, screenHeight);
	glutCreateWindow("Mouse Sierpinski");
	glutMouseFunc(myMouse);
	glutDisplayFunc(RenderScene);
	SetupRC();
	glutMainLoop();
	return 0;
}

如有疑问+QQ:307647252 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值