多边形的扫描转换
这是我的第一篇csdn博客,算是出于对计算机图形学的热情,在这门课程已经结束一个学期之际,重新联系写图形学算法,当然这都是“黑发不知勤学早”的结果了,之前在找相关算法的时候感觉网上其他博主写的都太过教科书化,毕竟算法的实现跟理论还是差那边么一点点的,于是就把我个人一丢丢小思路结合理论写一下,希望对新入坑的同学起到帮助,如果有不完美之处也请指正。
多边形扫描转换算法主要是从图形的顶点表示入手的。
扫描线算法
扫描线多边形区域填充算法是按照扫描线顺序,计算扫描线与多边形相交区间,再用要求的颜色填充满要填充的区域。
理论思想
求交,计算扫描线于多边形各边的交点。
排序,把所有交点按照x值的递增顺序排序
配对,将第一个与第二个,第三个与第四个(以此类推)配对
填色,把相交区间之间填充上指定颜色。
数据定义
X
dx
ymax
next
x:活性边的x值dx:y值加一对应的x值增量
ymax: 此活性边对应的y的最大值
next : 下一点的地址
数据结构
活性边表
图示
#include <GL/freeglut.h> #include <windows.h> using namespace std; const int POINTNUM = 7; typedef struct XET { float x; float dx, ymax; XET* next; }AET, NET; struct point { float x; float y; } polypoint[POINTNUM] = { 250,50,550,150,550,400,250,250,100,350,100,100,120,30 }; void PolyScan() { int MaxY = 0; int i; for (i = 0; i < POINTNUM; i++) { if (polypoint[i].y > MaxY) MaxY = polypoint[i].y; } AET *pAET = new AET; pAET->next = NULL; NET *pNET[1024]; for (i = 0; i <= MaxY; i++) { pNET[i] = new NET; pNET[i]->next = NULL; } glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 0.0); glBegin(GL_POINTS); for (i = 0; i < MaxY; i++) { for (int j = 0; j < POINTNUM; j++) { if (polypoint[j].y == i) { if (polypoint[(j + 1 + POINTNUM) % POINTNUM].y > polypoint[j].y) { NET *p = new NET; p->x = polypoint[j].x; p->ymax = polypoint[(j + 1 + POINTNUM) % POINTNUM].y; p->dx = (polypoint[(j + 1 + POINTNUM) % POINTNUM].x - polypoint[j].x) / (polypoint[(j + 1 + POINTNUM) % POINTNUM].y - polypoint[j].y); p->next = pNET[i]->next; pNET[i]->next = p; } if (polypoint[(j - 1 + POINTNUM) % POINTNUM].y > polypoint[j].y) { NET *p = new NET; p->x = polypoint[j].x; p->ymax = polypoint[(j - 1 + POINTNUM) % POINTNUM].y; p->dx = (polypoint[(j - 1 + POINTNUM) % POINTNUM].x - polypoint[j].x) / (polypoint[(j - 1 + POINTNUM) % POINTNUM].y - polypoint[j].y); p->next = pNET[i]->next; pNET[i]->next = p; } } } } glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 0.0); glBegin(GL_POINTS); for (i = 0; i <= MaxY; i++) { AET *p = new AET; p = pAET->next; AET *n = new AET; //将新边表中的活性边按照从左到右的顺序排序 if (pNET[i]->next && pNET[i]->next->next) { if (pNET[i]->next->dx > 0) { NET *t = new NET; t = pNET[i]->next; n = pNET[i]->next->next; t->next = NULL; n->next = NULL; pNET[i]->next = n; n->next = t; } } //更新活性边表中的活性边x坐标的值 while (p) { p->x = p->x + p->dx; p = p->next; } p = pAET->next; n = pAET; //删掉扫描线高度等同于ymax的废弃点 while (p){ if (p->ymax == i) { n->next = p->next; free(p); p = n->next; } else { p = p->next; n = n->next; } } //插入新点,按照顺序插入 p = pAET->next; n = pAET; NET *a = new NET; a = pNET[i]->next; if (a) { NET *b = new NET; b = a; while (b->next) { b = b->next; } if (!pAET->next) { pAET->next = a; } else { while (p) { if (a->x < p->x) { b->next = p; n->next = a; break; } if (!p->next) { p->next = a; break; } n = n->next; p = p->next; } } } //填充2 p = pAET->next; while (p && p->next) { for (float j = p->x; j <= p->next->x; j++) { glVertex2i(static_cast<int>(j), i); } p = p->next->next; } } glEnd(); glFlush(); } void init(void) { glClearColor(1.0, 1.0, 1.0, 0.0); glMatrixMode(GL_PROJECTION); gluOrtho2D(0.0, 600.0, 0.0, 450.0); } void main(int argc, char* argv) { glutInit(&argc, &argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowPosition(50, 100); glutInitWindowSize(400, 300); glutCreateWindow("An Example OpenGL Program"); init(); glutDisplayFunc(PolyScan); glutMainLoop(); }