- 寫在開頭:
相關實驗是學校開設課程的相關實驗,本人所作較爲粗淺,若有同校師弟瀏覽,望看懂借鑑而非照搬全抄。
- 實驗目的:
利用鼠標、鍵盤,菜單等方式對圖元進行交互操作
- 實驗內容:
1、用鼠標拖動畫直線,線段終點始終跟隨鼠標移動;
2、使用菜單界面修改直線的顏色;
3、利用鍵盤控制直線在屏幕上移動;
- 實現效果及步驟(或流程)
實現效果:
1.鼠標左鍵選取直線,通過鍵盤的方向鍵對直線進行移動
2.繪製折線,鼠標右鍵開始折線繪製,單擊鍵盤Q鍵,結束本次繪製
3.鼠標中鍵彈出菜單按鈕,選擇顏色對直線進行修改
實現步驟:
- 相關功能實現方法
- 繪製折線
相關代碼在方法mousePlot、drawLines、quitLinePlot中
#include <GL/glut.h>
#include <vector>
#include <iostream>
void mouseMovePtPlot(GLint xMouse, GLint yMouse);
GLsizei winWidth = 400, winHeight = 300;
GLint point[2][2];
bool ptCtr = true;
bool lineCtr = false;
GLenum fillMode = GL_SMOOTH; // Initial polygon fill: color interpolation.
float color[1][3] = {0.0,0.0,0.0};
int tag;//記錄選取的點在數組中的位置
std::vector<GLint> points;//用於存儲線段
void init(void) {
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, 200.0, 0.0, 150.0);
}
void displayFcn() {
glColor3f(0.0, 0.0, 0.0);
glPointSize(3.0);
}
//繪製已保存的線段
void drawLines() {
int length = points.size();
glColor3fv(color[0]);
glBegin(GL_LINES);
for (GLint i = 0; i <length - 3 ; i+=2) {
if (points[i + 2] == points[i] && points[i + 3] == points[i + 1]) {
i += 2;//跳過下一個點
std::cout << "斷點(" << points[i] << "," << points[i + 1] << ") " << std::endl;
continue;
}
glVertex2i(points[i], points[i+1]);
glVertex2i(points[i+2], points[i + 3]);
}
glVertex2i(points[length - 2], points[length - 1]);
glVertex2iv(point[1]);//該點是鼠標移動過程中的點,是一個暫時的點,鼠標右鍵擡起時纔會保存
glEnd();
}
void drawChangedLines() {
glClear(GL_COLOR_BUFFER_BIT);
int length = points.size();
glColor3fv(color[0]);
glBegin(GL_LINES);
for (GLint i = 0; i < length - 3; i += 2) {
if (points[i + 2] == points[i] && points[i + 3] == points[i + 1]) {
i += 2;//跳過下一個點
std::cout << "斷點(" << points[i] << "," << points[i + 1] << ") " << std::endl;
continue;
}
glVertex2i(points[i], points[i + 1]);
glVertex2i(points[i + 2], points[i + 3]);
}
glEnd();
glFlush();
}
void winReshapeFcn(GLint newWidth, GLint newHeight) {
glViewport(0, 0, newWidth, newHeight);
glLoadIdentity();
gluOrtho2D(0.0, GLdouble(newWidth), 0.0, GLdouble(newHeight));
winWidth = newWidth;
winHeight = newHeight;
}
//退出折線繪製
void quitLinePlot(GLubyte curvePlotKey, GLint xMouse, GLint yMouse)
{
GLint x = xMouse;
GLint y = winHeight - yMouse;
switch (curvePlotKey)
{
case 'q':
ptCtr = true;
points.push_back(point[1][0]);
points.push_back(point[1][1]);
break;
default:
break;
}
glFlush();
}
void mouseMoveLinePlot(GLint xMouse, GLint yMouse) {
if (lineCtr) {
glClear(GL_COLOR_BUFFER_BIT);
point[1][0] = xMouse;
point[1][1] = winHeight - yMouse;
drawLines();
//plotLine(point);
glFlush();
}
}
//鼠標事件回調函數
void mousePlot(GLint button, GLint action, GLint xMouse, GLint yMouse) {
//獲得起始點座標
if (button == GLUT_LEFT_BUTTON && action == GLUT_DOWN)
{
if (points.size() != 0) {
GLint x = xMouse;
GLint y = winHeight - yMouse;
for (GLint i = 0; i < points.size() - 3; i += 2) {
if (points[i + 2] == points[i] && points[i + 3] == points[i + 1]) {
i += 2;//跳過下一個點
std::cout << "斷點(" << points[i] << "," << points[i + 1] << ") " << std::endl;
continue;
}
GLint x1, y1, x2, y2;
x1 = points[i];
y1 = points[i + 1];
x2 = points[i + 2];
y2 = points[i + 3];
int k = x2 * y - x1 * y - y2 * x + y1 * x - x2 * y1 + x1 * y2;
if (k + 1000 > 0 && k - 1000 < 0) {
tag = i;
}
}
}
}
else if (button == GLUT_RIGHT_BUTTON && action == GLUT_DOWN) {
lineCtr = true;
if (ptCtr) {
point[0][0] = xMouse;
point[0][1] = winHeight - yMouse;
glutMotionFunc(mouseMoveLinePlot);
points.push_back(point[0][0]);
points.push_back(point[0][1]);
ptCtr = false;
}else {
point[1][0] = xMouse;
point[1][1] = winHeight - yMouse;
glutMotionFunc(mouseMoveLinePlot);
}
}
else if (button == GLUT_RIGHT_BUTTON && action == GLUT_UP) {
point[0][0] = point[1][0];
point[0][1] = point[1][1];
std::cout << "線段終點(" << point[0][0]<< "," << point[0][1] << ") " << std::endl;
points.push_back(point[1][0]);
points.push_back(point[1][1]);
for (int i = 0; i < points.size() - 1; i+=2) {
std::cout << "(" << points[i] << "," << points[i+1] << ") ";
}
std::cout << std::endl;
lineCtr = false;
}
}
//菜單事件回調函數
void colorOption(GLint selectedOption)
{
switch (selectedOption) {
case 1:
color[0][0] = 1.0;
color[0][1] = color[0][2] = 0.0;
break;
case 2:
color[0][1] = 1.0;
color[0][0] = color[0][2] = 0.0;
break;
case 3:
color[0][2] = 1.0;
color[0][0] = color[0][1] = 0.0;
break;
default:
break;
}
drawChangedLines();
}
//特殊鍵位移動直線
void moveLine(GLint reductionKey, GLint xMouse, GLint yMouse)
{
switch (reductionKey)
{
case GLUT_KEY_UP:
points[tag + 1] += 20;
points[tag + 3] += 20;
drawChangedLines();
break;
case GLUT_KEY_DOWN:
points[tag + 1] -= 20;
points[tag + 3] -= 20;
drawChangedLines();
break;
case GLUT_KEY_LEFT:
points[tag] -= 20;
points[tag + 2] -= 20;
drawChangedLines();
break;
case GLUT_KEY_RIGHT:
points[tag] += 20;
points[tag + 2] += 20;
drawChangedLines();
break;
default:
break;
}
}
void main(int argc, char ** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(100, 100);
glutInitWindowSize(winWidth, winHeight);
glutCreateWindow("CGLab2_CAIYIPEI");
init();
glutDisplayFunc(displayFcn);
glutReshapeFunc(winReshapeFcn);
glutMouseFunc(mousePlot);
glutKeyboardFunc(quitLinePlot);
glutCreateMenu(colorOption); // Create pop-up menu.
glutAddMenuEntry("RED", 1);
glutAddMenuEntry("GREEN", 2);
glutAddMenuEntry("BLUE", 3);
glutSpecialFunc(moveLine);
/* Select a menu option using the right mouse button. */
glutAttachMenu(GLUT_MIDDLE_BUTTON);
glutMainLoop();
}