前言
记录一次三维计算机图形学的作业,用于以后复习。也方便各位有相同需求的同学们。程序仍有问题待解决,欢迎大佬在评论区指点。以后会尽量更新新的学习记录贴,在CSDN与广大码农共进步。
可使用鼠标交互的多项式曲线
一、功能简介
通过点击鼠标左键确定四个型值点位置,再次点击左键完成多项式曲线曲线的绘制
二、代码片段
代码如下,一共353行,还包括注释,请慢慢阅读,理解整体架构以后再尝试运行:
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace std;
struct Point { //Point结构体
int x, y;
};
Point pt[4]; //存放点信息的数组,计算曲线时用到
vector<Point> vpt; //存放点的向量,输入数据时用到
bool bDraw; //是否绘制曲线,false则确定没有开始绘制曲线
int nInput; //点的数量
bool mouseLeftIsDown = false; //是否点击鼠标左键
bool mouseRightIsDown = false; //是否点击鼠标右键
int caculateSquareDistance(int x,int y, Point b) //计算鼠标与点的位置
{
return (x - b.x) * (x - b.x) + (y - b.y);
}
void ControlPoint(vector<Point> vpt) //绘制目标点
{
glPointSize(5); //点的大小
for (int i = 0; i < vpt.size(); i++)
{
glBegin(GL_POINTS);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2i(vpt[i].x, vpt[i].y); //点为红色
glEnd();
}
}
void ReControlPoint(int x, int y) //绘制修改的目标点
{
glPointSize(5); //点的大小
glBegin(GL_POINTS);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2i(x, y); //点为红色
glEnd();
}
void PolylineGL(Point* pt, int num) //绘制多项式曲线
{
//glBegin(GL_LINE_STRIP);
glBegin(GL_POINTS);
//glColor3f(1.0f, 0, 0);
glPointSize(15.0f);
/*glVertex2i(points[0].x, points[0].y);
glVertex2i(points[1].x, points[1].y);
glVertex2i(points[2].x, points[2].y);
glVertex2i(points[3].x, points[3].y);*/
glVertex2i(pt[0].x, pt[0].y);
glVertex2i(pt[1].x, pt[1].y);
glVertex2i(pt[2].x, pt[2].y);
glVertex2i(pt[3].x, pt[3].y);
glEnd();
double x, y;
glBegin(GL_LINE_STRIP);
glColor3f(0, 1.0f, 1.0f);
//应用已确定的多项式曲线的公式,可以参考以前的代码。更改这里的公式能够绘制其他类型的曲线
int c0x = pt[0].x;
int c1x = (-19 * pt[0].x + 24 * pt[1].x - 8 * pt[2].x + 3 * pt[3].x) / 3;
int c2x = (32 * pt[0].x - 56 * pt[1].x + 40 * pt[2].x - 16 * pt[3].x) / 3;
int c3x = (-16 * pt[0].x + 32 * pt[1].x - 32 * pt[2].x + 16 * pt[3].x) / 3;
int c0y = pt[0].y;
int c1y = (-19 * pt[0].y + 24 * pt[1].y - 8 * pt[2].y + 3 * pt[3].y) / 3;
int c2y = (32 * pt[0].y - 56 * pt[1].y + 40 * pt[2].y - 16 * pt[3].y) / 3;
int c3y = (-16 * pt[0].y + 32 * pt[1].y - 32 * pt[2].y + 16 * pt[3].y) / 3;
float Px, Py;
for (double t = 0; t <= 1; t += 0.01) { //微分,计算100个小点组成曲线
Px = c0x + c1x * t + c2x * t * t + c3x * t * t * t;//x方向曲线坐标
Py = c0y + c1y * t + c2y * t * t + c3y * t * t * t;//y方向曲线坐标
glVertex2d(Px, Py);
}
glEnd();
//glFlush();
//glutSwapBuffers();
}
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT); //清空颜色
glColor3f(1.0f, 1.0f, 1.0f);
if (vpt.size() > 0) {
ControlPoint(vpt); //绘制鼠标点击的点
}
if (bDraw)
{
glColor3f(1.0f, 1.0f, 0.0f);
PolylineGL(pt, 4); //render curve
}
/*if (bDraw == true && nInput == 4) {
glColor3f(1.0f, 1.0f, 0.0f);
PolylineGL(pt, 4);
}*/
glFlush();
glutSwapBuffers();
}
void Init()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
printf("Please Click left button of mouse to input control point of Curve!\n");
}
void Reshape(int w, int h) //适应窗口
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w, h, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void mouse(int button, int state, int x, int y) //鼠标点击事件,参考了大佬的代码
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
mouseLeftIsDown = true;
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
{
mouseLeftIsDown = false;
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
mouseRightIsDown = true;
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP)
{
mouseRightIsDown = false;
}
switch (button)
{
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
{
if (nInput == 0)
{
pt[0].x = x;
pt[0].y = y;
nInput = 1;//第一个点
vpt.clear();//清空栈
vpt.push_back(pt[0]); //将vpt的数据发送到pt点的数组之中
bDraw = false; //对于点击数量不足4,全部不允许绘制多项式曲线
glutPostRedisplay();//重新构图
}
else if (nInput == 1) //第二个点
{
pt[1].x = x;
pt[1].y = y;
vpt.push_back(pt[1]);
nInput = 2;
glutPostRedisplay();//重新构图
}
else if (nInput == 2)//第三个点
{
pt[2].x = x;
pt[2].y = y;
vpt.push_back(pt[2]);
nInput = 3;
glutPostRedisplay();
}
else if (nInput == 3)//第四个点
{
pt[3].x = x;
pt[3].y = y;
bDraw = true;
vpt.push_back(pt[3]);
nInput = 4;
glutPostRedisplay();
}
else if (nInput == 4)//第四个点
{
ReControlPoint(x,y); //绘制鼠标点击的点//pt[0].x =x; pt[0].y = y;
}
}
break;
default:
break;
}
}
void motion(int x, int y) //移动点
{
if (mouseLeftIsDown) //左键移动控制点
{
if (caculateSquareDistance(x, y, pt[0]) < 40) //防止鼠标移动过快点位无法及时读取,经测试,40为一个较适合的值
{
pt[0].x = x;
pt[0].y = y;
}
else if (caculateSquareDistance(x, y, pt[1]) < 40)
{
pt[1].x = x;
pt[1].y = y;
}
else if (caculateSquareDistance(x, y, pt[2]) < 40)
{
pt[2].x = x;
pt[2].y = y;
}
else if (caculateSquareDistance(x, y, pt[3]) < 40)
{
pt[3].x = x;
pt[3].y = y;
}
}
else if (mouseRightIsDown) { //有需要的话,在这里更改按下鼠标右键的事件
// Display(points);
// Display(p0, p1, p2, p3);
}
glFlush();
glutSwapBuffers();
glutPostRedisplay(); //重新构图
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv); //启动
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
//glutInitWindowPosition(100, 100);
glutInitWindowPosition(argc, argc);
glutInitWindowSize(500, 500);
glutCreateWindow("三次多项式曲线");//绘图窗口名
Init(); //自定义的启动函数,在这里更改代码行里的提示信息
glutDisplayFunc(myDisplay);//以下是应用自定义的显示函数等等
glutReshapeFunc(Reshape);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutMainLoop(); //启动glut主循环
return 0;
}