欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

计算机图形学 实验7 《复杂图形绘制-Bezier曲线与Hermite曲线》

程序员文章站 2024-01-16 21:37:10
...

计算机图形学 实验7 《复杂图形绘制-Bezier曲线与Hermite曲线》

一、实验目的

学习样条曲线的绘制。

二、实验内容

1、绘制Bezier曲线;
2、绘制Hermite曲线。

三、实验方法

Hermite曲线是给定曲线段的两个端点坐标以及两端点处的切线矢量来描述的曲线。平面上一条三次参数曲线可以表示为:

计算机图形学 实验7 《复杂图形绘制-Bezier曲线与Hermite曲线》

四、实验步骤

1、设定Bezier曲线的四个控制点的位置,结果存储在数组中;
2、根据样条法处端点不断拟合曲线;
3、将制作好的成果刷新在显示区域。

五、实验结果

实验输出图
1、Bezier曲线:

计算机图形学 实验7 《复杂图形绘制-Bezier曲线与Hermite曲线》

2、Hermite曲线

计算机图形学 实验7 《复杂图形绘制-Bezier曲线与Hermite曲线》

六、实验结论

1、Bezier曲线的绘制

代码:

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

GLfloat ctrlpoints[4][3] = {
	{ -4.0, -4.0, 0.0}, { -2.0, 4.0, 0.0}, 
	{2.0, -4.0, 0.0}, {4.0, 4.0, 0.0}};

void init(void) {
   glClearColor(0.0, 0.0, 0.0, 0.0);
   glShadeModel(GL_FLAT);
   
   glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]);
   
   glEnable(GL_MAP1_VERTEX_3);
}

void display(void) {
   int i;

   glClear(GL_COLOR_BUFFER_BIT);
   glColor3f(1.0, 1.0, 1.0);
   
   glBegin(GL_LINE_STRIP);
      for (i = 0; i <= 30; i++) 
         glEvalCoord1f((GLfloat) i/30.0);
   glEnd();
  
   /* The following code displays the control points as dots. */
   glPointSize(5.0);
   glColor3f(1.0, 1.0, 0.0);
   glBegin(GL_POINTS);
      for (i = 0; i < 4; i++) 
         glVertex3fv(&ctrlpoints[i][0]);
   glEnd();
   glFlush();
}

void reshape(int w, int h) {
   glViewport(0, 0, (GLsizei) w, (GLsizei) h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   if (w <= h)
      glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w, 
               5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0);
   else
      glOrtho(-5.0*(GLfloat)w/(GLfloat)h, 
               5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
}

void keyboard(unsigned char key, int x, int y) {
   switch (key) {
      case 27:
         exit(0);
         break;
   }
}

int main(int argc, char** argv) {
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
   glutInitWindowSize (500, 500);
   glutInitWindowPosition (100, 100);
   glutCreateWindow (argv[0]);
   init ();
   glutDisplayFunc(display);
   glutReshapeFunc(reshape);
   glutKeyboardFunc (keyboard);
   glutMainLoop();
   return 0;
}

2、Hermite曲线的绘制

代码:

#include <math.h>
#include <gl/glut.h>
#include <iostream>
using namespace std;

struct  Point2 {
	double x;
	double y;

	Point2(int px, int py) { x = px; y = py; }
};

Point2 P0(100, 200);
Point2 P1(350, 200);
Point2 derP0(200, 200);
Point2 derP1(200, 200);

bool mouseLeftDown = false;
bool mouseRightDown = false;

/* 计算Hermite曲线 */
void Hermit(int n) {
	float f1, f2, f3, f4;

	double deltaT = 1.0 / n;

	glBegin(GL_LINE_STRIP);
	for (int i = 0; i <= n; i++) {

		double T = i * deltaT;

		f1 = 2.0 * pow(T, 3) - 3.0 * pow(T, 2) + 1.0;
		f2 = -2.0 * pow(T, 3) + 3.0 * pow(T, 2);
		f3 = pow(T, 3) - 2.0 * pow(T, 2) + T;
		f4 = pow(T, 3) - pow(T, 2);

		glVertex2f(f1 * P0.x + f2 * P1.x + f3 * derP0.x + f4 * derP1.x,
			f1 * P0.y + f2 * P1.y + f3 * derP0.y + f4 * derP1.y);
	}
	glEnd();
}

/* 用鼠标进行绘制,完成后可改变控制点,拖动即可 */
void display() {
	glClear(GL_COLOR_BUFFER_BIT);

	glLineWidth(1.5);
	glColor3f(1.0, 0.0, 0.0);
	glBegin(GL_LINES);
	glVertex2f(P0.x, P0.y);
	glVertex2f(P0.x + derP0.x / 4, P0.y + derP0.y / 4);
	glVertex2f(P1.x, P1.y);
	glVertex2f(P1.x - derP1.x / 4, P1.y - derP1.y / 4);
	glEnd();

	glColor3f(0.0, 0.0, 1.0);
	glPointSize(10.0f);

	glBegin(GL_POINTS);
	glVertex2f(P0.x, P0.y);
	glVertex2f(P0.x + derP0.x / 4, P0.y + derP0.y / 4);
	glVertex2f(P1.x, P1.y);
	glVertex2f(P1.x - derP1.x / 4, P1.y - derP1.y / 4);
	glEnd();

	Hermit(20);

	glFlush();
	glutSwapBuffers();
}

void init() {
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glShadeModel(GL_FLAT);
}

void myReshape(int w, int h) {
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, (GLsizei)w, (GLsizei)h, 0.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void mouse(int button, int state, int x, int y) {
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
		mouseLeftDown = true;

	if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
		mouseLeftDown = false;

	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
		mouseRightDown = true;

	if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP)
		mouseRightDown = false;
}

double distance(int x1, int y1, int x2, int y2) {
	return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

void motion(int x, int y) {
	if (mouseLeftDown) {
		if (distance(P0.x + derP0.x / 4, P0.y + derP0.y / 4, x, y) < 20) {
			derP0.x = (x - P0.x) * 4;
			derP0.y = (y - P0.y) * 4;
		}

		if (distance(P1.x - derP1.x / 4, P1.y - derP1.y / 4, x, y) < 20) {
			derP1.x = (P1.x - x) * 4;
			derP1.y = (P1.y - y) * 4;
		}
	}

	glutPostRedisplay();
}

int  main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(450, 450);
	glutInitWindowPosition(200, 200);
	glutCreateWindow("Hermite");
	init();
	glutDisplayFunc(display);
	glutReshapeFunc(myReshape);
	glutMouseFunc(mouse);
	glutMotionFunc(motion);
	glutMainLoop();
	return 0;
}

七、实验小结

Bezier曲线只是B样条的一个特例,可以通过改变一个控制点的位置来改变曲线的形状,这种曲线生成方式比较直观和灵活,只需要放置控制点,然后调整控制点的位置来得到想要的曲线,这就避免了和复杂的数学方程打交道。对于Hermite曲线,最终的曲线在靠近第一个关键点的位置,会更接近第一个基函数加权的量,最终的曲线在靠近第二个关键点的位置,会更接近影响第二个基函数的值。