计算机图形学 实验四 AET算法
实验四:多边形的扫描转换与填充(实在是懒得贴SCAN了,SCAN不但没技术含量而且还死麻烦。代码太长了。所以就只贴AET了。)
实验目的: 了解多边形的表示方式,区域填充基本原理,掌握多边形的扫描转换算法
基本要求:
给定有序点对表示的多边形
实现 x 扫描线填充
实现改进的 x 扫描线填充(使用活性边表结构)
实现:
使用方法:右键开启菜单,点击AET,鼠标左键点击开始描点。完成后按回车键。如果想重新画可重复此步骤。
#define EXIT_SUCCESS 0 #include<stdio.h> #include <stdlib.h> #include<GL/glut.h> #include<math.h> #include<queue> #include<vector> #include<algorithm> #include "cross.h" #include<iostream> using namespace std; // later Edition int MODE = 0; // 模式代码:0-DAA算法,1-Bresenham算法,2-中点圆算法 bool mouseLeftDown; // 实时记录鼠标左键状态 bool mouseRightDown; // 实时记录鼠标左键状态 float mouseX, mouseY; // 实时记录鼠标位置,与下一次鼠标位置之间形成微分 bool status = false; // 标记当前是否为规划状态 int startX=0, startY=0, endX=0, endY=0; int start[2] = { 0 }; int end[2] = { 0 }; float red=1.0,green=1.0, blue=0.0; float PI = 3.415926535; Point sp, previous, now; bool start_pass = false; // 纯粹的交点模式,简单的交点判别法 vector<pair<Point,Point> > q;// 存储边集,在编辑中存储需要的数据 vector<vector<edge> > NET(501); vector<vector<edge> > AET(501);// 活性边 // 数据结构上,对于求交,需要以下几个数据结构 // 1.存储所有边,然后存储边的所有交集。对于边的所有交集,目前可以按照一个简单的有序队列的方式进行。 vector<vector<int> > t(501);// 存储所有扫描线与各个边的交点。 ostream& operator<<(ostream& output,const Point& p) { cout <<"("<< p.x << "," << p.y << ")"; return output; } void polygon() { for (int i = 1;i <= 500;i++) { AET[i].clear(); NET[i].clear(); } // now intialize the NET for (int i = 0;i < q.size();i++) { // NNNNNNNNNNEEEEEEEEEEEETTTTTTTTTTTT //cout<<q[i].first<<q[i].second<<endl; edge v((q[i].first.y > q[i].second.y) ? q[i].second.x : q[i].first.x, 1.0 * (q[i].first.x - q[i].second.x) / (q[i].first.y - q[i].second.y), max(q[i].first.y, q[i].second.y)); //cout<<v; // 然后将边插入到第一次出现的扫描线处,也就是说第一次的ymin的扫描线处。 NET[min(q[i].first.y, q[i].second.y)].push_back(v); }// 循环结束后,所有的边都已经进入了NET // 接下来将会进行正式的作画 for (int i = 1;i <= 500;i++) { // AAAAAAAAAAAEEEEEEEEEEEETTTTTTTTTT vector<int> temp; for (int a = 1;a <= 500;a++) { for (int b = 0;b < AET[a].size();b++) { temp.push_back(AET[a][b].start); } } sort(temp.begin(), temp.begin() + temp.size()); sort(NET[i].begin(), NET[i].end());// 提前排序不需要再进行插入排序 for (int j = 0;j < NET[i].size();j++) { AET[i].push_back(NET[i][j]);// 插入排序法将节点插入AET完成 } glColor3d(red, green, blue); glPointSize(1.0); glBegin(GL_POINTS); for (int l = 0;l < temp.size();l += 2) { for (int o = temp[l];o <= temp[l + 1];o++) { //cout << "draw(" << i << "," << o << ")、"; glVertex2d(o, i); } } //if (temp.size())cout << endl; glEnd(); for (int a = 1;a <= 500;a++) { for (int b = 0;b < AET[a].size();b++) { if (AET[a][b].ymax == i) { AET[a].erase(AET[a].begin() + b); } else if (AET[a][b].ymax > i) { AET[a][b].start += AET[a][b].dx; } } } } } int arr[500][500]; void init(void) { //glClearColor(0.0, 0.0, 0.0, 0.0);/* select clearing color */ // 设置背景颜色为黑色 //glMatrixMode(GL_MODELVIEW); glClearColor(0.0, 0.0, 0.0, 0.0); /* white background */ glColor3f(1.0, 0.0, 0.0); /* draw in red */ /* set up viewing: */ /* 500 x 500 window with origin lower left */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, 500.0, 0.0, 500.0); glMatrixMode(GL_MODELVIEW); } #define RED 1233 #define BLUE 1234 #define GREEN 1235 #define WHITE 12366 #define YELLOW 12367 #define SCAN_LINE 12368 #define AET 12369 void processMenuEvents(int option) { //option,就是传递过来的value的值。 switch (option) { case RED: red = 1.0; green = 0.0; blue = 0.0; break; case GREEN: red = 0.0; green = 1.0; blue = 0.0; break; case BLUE: red = 0.0; green = 0.0; blue = 1.0; break; case WHITE: red = 1.0; green = 1.0; blue = 1.0; break; case YELLOW: red = 1.0; green = 1.0; blue = 0.0;break; case SCAN_LINE: for (int i = 1;i <= 500;i++)t[i].clear(); q.clear(); sp.x = 0; glutPostRedisplay(); status = true; MODE = 0;break; case AET: MODE = 1;break; } } void createGLUTMenus() { int menu; // 创建菜单并告诉GLUT,processMenuEvents处理菜单事件。 menu = glutCreateMenu(processMenuEvents); //给菜单增加条目 glutAddMenuEntry("红色", RED); glutAddMenuEntry("蓝色", BLUE); glutAddMenuEntry("绿色", GREEN); glutAddMenuEntry("白色", WHITE); glutAddMenuEntry("黄色", YELLOW); glutAddMenuEntry("AET", SCAN_LINE); // 把菜单和鼠标右键关联起来。 glutAttachMenu(GLUT_RIGHT_BUTTON); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1-red, 1-green,1- blue); glLoadIdentity(); glPointSize(5.0); glBegin(GL_POINTS); if (status == true) { if(sp.x)glVertex2i(sp.x, sp.y); for (int i = 0;i < q.size();i++) { glVertex2i(q[i].second.x, q[i].second.y); } } glEnd(); glColor3f(red, green, blue); if(!status)polygon(); // Draw here glutSwapBuffers(); } int saveStack = 0; void keyboard(unsigned char key, int x, int y) { switch (key) { case 'q':case 'Q': exit(EXIT_SUCCESS); break; case 13: //for (int i = 1;i <= 500;i++)t[i].clear(); //q.clear(); if (start_pass == true&&status==true) { pair<Point, Point> v(now, sp); q.push_back(v); cout << "??" << now << sp << "?" << endl; // just initiate the graphic or just simply put the graphic drawing operation into the display function start_pass = false; } status = false; cout << "should display" << endl; glutPostRedisplay(); break; case 'r':case 'R': for (int i = 1;i <= 500;i++)t[i].clear(); q.clear(); glutPostRedisplay(); break; } } int ww, hh; void mouse_process(int button, int state, int x, int y) { mouseX = x; mouseY = y; printf("<%d,%d>\n", x, y); cout << "===============" << endl; for (int i = 0;i < q.size();i++) { cout << q[i].first <<"-"<< q[i].second << endl; } hh = glutGet(GLUT_WINDOW_HEIGHT); if (button == GLUT_LEFT_BUTTON) { if (state == GLUT_DOWN) { if (!mouseLeftDown) { startX = x;startY = hh-y; } now = Point(x, hh-y); if(status) if (previous == now); else { if (start_pass == false) { start_pass = true; sp = now; previous = now; } else { pair<Point, Point> v(previous, now); previous = now; q.push_back(v); } } glutPostRedisplay(); mouseLeftDown = true; } else if (state == GLUT_UP) { mouseLeftDown = false; } } else if (button == GLUT_RIGHT_BUTTON) { if (state == GLUT_DOWN) { mouseRightDown = true; } else if (state == GLUT_UP) mouseRightDown = false; } } void mouse_process_active(int x, int y) { if (mouseLeftDown){ endX = x;endY = hh - y; glutPostRedisplay(); } if(mouseRightDown) { } glutPostRedisplay(); } void mouse_process_passtive(int x, int y) {} int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(500, 500); glutCreateWindow(" 右键开启菜单"); init(); Point a(40, 40), b(150, 60), c(100, 100), d(10, 70); pair<Point, Point> v1(a, b), v2(b, c), v3(c, d), v4(d, a); q.push_back(v1);q.push_back(v2);q.push_back(v3);q.push_back(v4); glutDisplayFunc(display); // later Edition glutMouseFunc(mouse_process); glutMotionFunc(mouse_process_active); glutPassiveMotionFunc(mouse_process_passtive); createGLUTMenus(); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }