多边形的扫描转换算法——扫描线算法(计算机图形学)

Efia ·
更新时间:2024-09-21
· 822 次阅读

扫描线算法是扫描转换多边形的常用算法,它充分利用了相邻像素之间的连贯性,避免了逐点判断和反复求交计算,达到了减少计算量和提高算法效率的目的。

处理对象:非自交多边形 (边与边之间除了顶点外无其它交点)。开发和利用相邻象素之间的连贯性是光栅图形学算法的重要技巧。

扫描线算法综合利用了区域的连贯性、扫描线的连贯性和边的连贯性等三种形式的连贯性。

**区域的连贯性:**相邻两条扫描线构成一个水平长方形区域,并被多边形的边分割为若干梯形(一类位于多边形的内部;另一类在多边形的外部,且间隔排列)。只需知道该区域内任一梯形中一点关于多边形的内外关系,即可确定区域内所有梯形关于多边形的内外关系。

**扫描线的连贯性:**区域的连贯性在一条扫描线上的反映;

**边的连贯性:**某条边与当前扫描线相交,也可能与下一条扫描线相交。可通过与当前扫描线的交点计算与下一扫描线的交点(利用斜率)。(区域的连贯性在相邻两扫描线上的反映)

算法的具体实现步骤: **求交点:**求出扫描线与多边形所有边的交点 **交点排序:**把这些交点按x坐标值以升序排列 **配对:**对排序后的交点进行奇偶配对 **填色:**对每一对交点间的区域进行填充 数据结构:

与当前扫描线相交的边称为活性边(Active Edge),把它们按与扫描线交点x坐标递增的顺序存入一个链表中,称为活性边表AET (AEL, Active Edge List)。它记录了多边形边沿扫描线的交点序列。
新边表(NET)存放在一条扫描线中第一次出现的边。若某边的较低端点为ymin,则该边就放在扫描线ymin的新边表中。
AET,NET存放信息:
ymax:边所交的最高扫描线;
x:当前扫描线与边的交点;
Δx:从当前扫描线到下一条扫描线之间的x增量

扫描转换如下三角形:顶点为:(80,120),(20,30),(150,50)。(扫描线算法)
代码来源:多边形的扫描转换算法

#include #include #include const int POINTNUM = 3; //链表的实现 typedef struct XET { float x; float dx, ymax; XET* next; }AET, NET; //结构体对于某一个点的实现 struct point { float x; float y; } void PolyScan() { int MaxY = 0; int i; for (i = 0; i MaxY) MaxY = polypoint[i].y; } //选出最大的顶点所对应的y值 AET* pAET = new AET; pAET->next = NULL; NET* pNET[1024]; for (i = 0; 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 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; } } } } //把新边表net[i]中的边节点用插入排序法插入AET表,使之按照x的坐标递增顺序排序 for (i = 0; i next; while (p) { p->x = p->x + p->dx; p = p->next; } AET* tq = pAET; p = pAET->next; tq->next = NULL; while (p) { while (tq->next && p->x >= tq->next->x)//重新排序 tq = tq->next; NET* s = p->next; p->next = tq->next; tq->next = p; p = s; tq = pAET; } //遍历AET表,把配对交点的区间(左闭右开)上的像素(x,y) AET* q = pAET; p = q->next; while (p) { if (p->ymax == i) { q->next = p->next; delete p; p = q->next; } else { q = q->next; p = q->next; } } p = pNET[i]->next; q = pAET; while (p) { while (q->next && p->x >= q->next->x) q = q->next; NET* s = p->next; p->next = q->next; q->next = p; p = s; q = pAET; } p = pAET->next; while (p && p->next) { for (float j = p->x; j next->x; j++) { glVertex2i(static_cast(j), i);//改写像素的颜色值 } p = p->next->next; } } glEnd(); glFlush(); } void main(int argc, char* argv) { glutInit(&argc, &argv);//窗口的初始化 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//窗口谋模式的设定 glutInitWindowPosition(50, 100);//窗口位置的设定 glutInitWindowSize(400, 300);//窗口大小的设定 glutCreateWindow("多边形扫描转换算法"); glClearColor(1.0, 1.0, 1.0, 0.0); glMatrixMode(GL_PROJECTION); gluOrtho2D(0.0, 600.0, 0.0, 450.0); glutDisplayFunc(PolyScan);//调用函数 glutMainLoop(); }
作者:八爪鱼!



计算机图形学 算法

需要 登录 后方可回复, 如果你还没有账号请 注册新账号