Кривая Безье на OpenGL

Curve_Bezier.jpg

В представленных программах с помощью программного интерфейса OpenGL пользователю предоставляется возможность
задавать, перемещать, удалять (с помощью мыши ) контрольные точки, по которым вычерчивается кривая Безье.

1 ) В первой программе кривая вычерчивается по интерполяционной формуле.
(для построения кривой необходимо чтобы пользователь задал хотя бы четыре точки)

2 ) Во второй программе кривая вычерчивается средствами OpenGL.

ВНИМАНИЕ! Для запуска программы необходимо установить библиотеку GLUT.
(Для Windows: скопировать файлы glut.dll, glut32.dll в папку C:\Windows\system)

Библиотека GLUT присутствует в архиве.

Инструкция (с картинками) по использованию OpenGL и GLUT в Visual Studio (Windows 7/XP) в архиве.

Используемая среда разработки: Microsoft Visual Studio 2010.

Кривая вычерчивается по интерполяционной формуле

#include <gl\glut.h>
 
struct point { float x, y; } P[350];
int n = 0, i, j;
bool tP = false;
 
void Draw( );
void Mouse(int button, int state, int x, int y);
void MenuChek(int v);
void CurveBezier( );
void Line( );
 
void main( ) {
//Инициализируем режим отображения окна OpenGL
//GLUT_DOUBLE - окно с двойной буферизацией
//GLUT_RGB - режим RGBA
	glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
	glutInitWindowSize(350,350); //устанавливаем размер окна
	glutCreateWindow("Кривая Безье"); //создаем окно с заголовком
	glutDisplayFunc(Draw); //устанавливаем функцию отрисовки
	glutMouseFunc(Mouse); //устанавливаем функцию обработки нажатий мыши
 
//Установить цвет и значение альфа, используемые при очистке буферов цвета 
	glClearColor(1,1,1,1); //цвет фона (RGBA)
	glMatrixMode(GL_PROJECTION); //Определяем стек матриц (матрица проекций)
	glLoadIdentity(); //установить текущую матрицу равной еденичной
 
	glOrtho(0,350,0,350,0,1); //Установить границы объема отсечения
	glColor3f(0,0,0); //Установить текущий цвет (R,G,B)
 
	glutCreateMenu(MenuChek); //Меню вызываемое нажатием ПКМ
	glutAddMenuEntry("Удалить последнюю точку", 0); //Пункт меню
	glutAddMenuEntry("Очистить", 1); //Пункт меню
	glutAttachMenu(GLUT_RIGHT_BUTTON);
 
	glutMainLoop(); //Запуск основного цикла обработки GLUT
}
 
void Draw( ) {
	glClear(GL_COLOR_BUFFER_BIT); //Очистка буфера цвета
	Line( );
	if (n > 3)
		CurveBezier();
	glutSwapBuffers(); //Переключить буферы в режиме двойной буферизации
}
 
void Mouse(int button, int state, int x, int y) {
	if (button == GLUT_LEFT_BUTTON) {
			if (tP && (x > 0 && x < 350)&& (350 > y && y < 700) ) { 
				P[j].x = x; 
				P[j].y = 350-y; 
			} else if (state == GLUT_DOWN && n != 0 && !tP)
				for (i = 0; i <= n; i++)
					if ((x<P[i].x+30 && x>P[i].x-30) && (320-y<P[i].y && 380-y>P[i].y)) {
						tP = true; 
						j = i; 
						break;
					}	
			if (state == GLUT_UP) {
				if (!tP) {
					P[n].x = x; 
					P[n].y = 350-y; 
					n++;
				}
				tP = false;
			}
	}
	glutPostRedisplay(); //Обновить текущее окно
}
 
void MenuChek(int v) {
	if (v == 0 && n > 0)
		n--; 
	else if (v == 1)
		n = 0;
	glutPostRedisplay(); //Обновить текущее окно
}
 
void Line ( ) {
	glPointSize(5);
	glColor3f(0,0,0);
 
//Контрольные точки
	glBegin(GL_POINTS);
		for (i = n-1; i >= 0; i--)
			glVertex2f(P[i].x, P[i].y);
	glEnd();
 
//Пунктирные линии
	glLineStipple(2,58360);
	glEnable(GL_LINE_STIPPLE);
	glBegin(GL_LINES);
		for (i = 0; i < n-1; i++) {
			glVertex2f(P[i].x, P[i].y);
			glVertex2f(P[i+1].x, P[i+1].y);
		}
	glEnd();
	glDisable(GL_LINE_STIPPLE);
	glPointSize(1);
}
 
void CurveBezier( ) {
	float px0,px1,px2,px3, py0,py1,py2,py3, xt, yt;
	for(i = 1; i < n-2; i++) {
		px0 = (P[i-1].x + 4*P[i].x + P[i+1].x) / 6.0;
		px1 = (-P[i-1].x + P[i+1].x) / 2.0;
		px2 = (P[i-1].x - 2*P[i].x + P[i+1].x) / 2.0;
		px3 = (-P[i-1].x + 3*P[i].x - 3*P[i+1].x + P[i+2].x) / 6.0;
 
		py0 = (P[i-1].y + 4*P[i].y + P[i+1].y) / 6.0;
		py1 = (-P[i-1].y + P[i+1].y) / 2.0;
		py2 = (P[i-1].y - 2*P[i].y + P[i+1].y) / 2.0;
		py3 = (-P[i-1].y + 3*P[i].y - 3*P[i+1].y + P[i+2].y) / 6.0;
 
		glColor3f(1,0,0);
		glPointSize(2);
		glBegin(GL_POINTS);
			for(float t = 0.0; t <= 1.0; t += 0.001) {
				xt = ((px3*t + px2)*t + px1)*t + px0;
				yt = ((py3*t + py2)*t + py1)*t + py0;
				glVertex3f(xt, yt, 0);
			}
		glEnd();
	}
}

Кривая вычерчивается средствами OpenGL.

#include <gl\glut.h>
 
float point[350][3];
int n = 0, i, j;
bool tP = false;
 
void Draw( );
void Mouse(int button, int state, int x, int y);
void MenuChek(int v);
void CurveBezier( );
void Line( );
 
void main( ) {
//Инициализируем режим отображения окна OpenGL
//GLUT_DOUBLE - окно с двойной буферизацией
//GLUT_RGB - режим RGBA
	glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
	glutInitWindowSize(350,350); //устанавливаем размер окна
	glutCreateWindow("Кривая Безье"); //создаем окно с заголовком
	glutDisplayFunc(Draw); //устанавливаем функцию отрисовки
	glutMouseFunc(Mouse); //устанавливаем функцию обработки нажатий мыши
 
//Установить цвет и значение альфа, используемые при очистке буферов цвета 
	glClearColor(1,1,1,1); //цвет фона (RGBA)
	glMatrixMode(GL_PROJECTION); //Определяем стек матриц (матрица проекций)
	glLoadIdentity(); //установить текущую матрицу равной еденичной
 
//Установить границы объема отсечения
	glOrtho(0,350,0,350,0,1);
	glColor3f(0,0,0); //Установить текущий цвет (R,G,B)
 
	glutCreateMenu(MenuChek); //Меню вызываемое нажатием ПКМ
	glutAddMenuEntry("Удалить последнюю точку", 0); //Пункт меню
	glutAddMenuEntry("Очистить", 1); //Пункт меню
	glutAttachMenu(GLUT_RIGHT_BUTTON);
 
	glutMainLoop(); //Запуск основного цикла обработки GLUT
}
 
void Draw( ) {
	glClear(GL_COLOR_BUFFER_BIT); //Очистка буфера цвета
	Line( );
	if (n > 1) 
		CurveBezier();
	glutSwapBuffers(); //Переключить буферы в режиме двойной буферизации
}
 
void Mouse(int button, int state, int x, int y) {
	if (button == GLUT_LEFT_BUTTON) {
			if (tP && (x > 0 && x < 350)&& (350 > y && y < 700) ) { 
				point[j][0] = x; 
				point[j][1] = 350-y; 
			} else if (state == GLUT_DOWN && n != 0 && !tP)
				for (i = 0; i <= n; i++)
					if ((x<point[i][0]+30 && x>point[i][0]-30) && (320-y<point[i][1] && 380-y>point[i][1])) {
						tP = true; 
						j = i; 
						break;
					}	
			if (state == GLUT_UP) {
				if (!tP) {
					point[n][0] = x; 
					point[n][1] = 350-y; 
					n++;
				}
				tP = false;
			}
	}
	glutPostRedisplay(); //Обновить текущее окно
}
 
void MenuChek(int v) {
	if (v == 0 && n > 0)
		n--; 
	else if (v == 1)
		n = 0;
	glutPostRedisplay();
}
 
void Line ( ) {
	glPointSize(5);
	glColor3f(0,0,0);
 
//Контрольные точки
	glBegin(GL_POINTS);
		for (i = n-1; i >= 0; i--)
			glVertex2fv(point[i]);
	glEnd();
 
//Пунктирные линии
	glLineStipple(2,58360);
	glEnable(GL_LINE_STIPPLE);
	glBegin(GL_LINES);
		for (i = 0; i < n-1; i++) {
			glVertex2fv(point[i]);
			glVertex2fv(point[i+1]);
		}
	glEnd();
	glDisable(GL_LINE_STIPPLE);
	glPointSize(1);
}
 
void CurveBezier( ) {
//glMap1f - Функция оценки, генерирующая координаты.
//Параметры: 
//  GL_MAP1_VERTEX_3 -	тип генерируемых данных, 
//  0.0f - нижняя граница параметра u (первая точка), 
//  100.0f - верхняя граница(последняя точка), 
//  3 - расстояние между точками данных, 
//  n - число точек, 
// &P[0][0] - массив контрольных точек
	glMap1f(GL_MAP1_VERTEX_3, 0.0f, 100.0f, 3, n, &point[0][0]);
	glEnable(GL_MAP1_VERTEX_3);
 
	glLineWidth(2);
	glColor3f(1.0f,0.0f,0.0f);
	glBegin(GL_LINE_STRIP); //точки соединяются ломанной линией
		for (i = 0; i <= 100; i++)
//Оценка кривой в точке. Функция принимает параметрическое значение, и вычисляет точку
			glEvalCoord1f(float(i)); 
	glEnd();
	glLineWidth(1);
}

Ключевые слова: 
кривая, безье, opengl, сплайн, интерполяция, curve, bezier
ВложениеРазмер
src.rar1.95 Мб