利用AET表对扫描线进行存储
利用C++实现,VS2019测试通过,使用了glut库
#include<GL/glut.h>
#include<iostream>
#include<math.h>
#include<stdlib.h>
using namespace std;
#define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 400
//AET表数据结构
typedef struct tEdge
{
int ymax;//扫描线的最大值
float xi, dx;//当前x值和导数dx
struct tEdge* next;
} Edge;
//点坐标的数据结构
struct Point
{
int x;
int y;
}point;
//初始化窗口函数
void init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);//设置背景颜色为白色
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, 400.0, 0.0, 400.0);//投影视图
glLineWidth(12.0f); //直线宽度
}
//画点函数
void setPixel(GLint x, GLint y)
{
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
glFlush();
}
void insertEdge(Edge* list, Edge* edge)
{
Edge* p, * q = list;
p = q->next;
while (p != NULL)
{
if (edge->xi < p->xi)
p = NULL;
else
{
q = p;
p = p->next;
}
}
edge->next = q->next;
q->next = edge;
}
int yNext(int k, int cnt, Point* pts)
{
int j;
if ((k + 1) > (cnt - 1))
j = 0;
else
j = k + 1;
while (pts[k].y == pts[j].y)
{
if ((j + 1) > (cnt - 1))
j = 0;
else
j++;
return (pts[j].y);
}
}
void makeEdgeRec(Point lower, Point upper,int yComp, Edge* edge, Edge* edges[])
{
edge->dx = (float)(upper.x - lower.x) / (upper.y - lower.y);
edge->xi = lower.x;
if (upper.y < yComp)
{
edge->ymax = upper.y - 1;
}
else
edge->ymax = upper.y;
insertEdge(edges[lower.y], edge);
}
void buildEdgeList(int num, Point* pts, Edge* edges[])
{
Edge* edge;
Point v1, v2;
int i, yPrev = pts[num - 2].y;
v1.x = pts[num - 1].x;
v1.y = pts[num - 1].y;
for (i = 0; i < num; i++)
{
v2 = pts[i];
if (v1.y != v2.y)
{
edge = new Edge[num];
if (v1.y < v2.y)
{
makeEdgeRec(v1, v2, yNext(i, num, pts), edge, edges);
}
else
makeEdgeRec(v2, v1, yPrev, edge, edges);
}
yPrev = v1.y;
v1 = v2;
}
}
void buildActiveList(int scan, Edge* active, Edge* edges[])
{
Edge* p, * q;
p = edges[scan]->next;
while (p)
{
q = p->next;
insertEdge(active, p);
p = q;
}
}
void fillScan(int scan, Edge* active)
{
Edge* p1, * p2;
int i;
p1 = active->next;
while (p1)
{
p2 = p1->next;
for (i = p1->xi; i < p2->xi; i++)
{
setPixel((int)i, scan);
}
p1 = p2->next;
}
}
void deleteAfter(Edge* q)
{
Edge* p = q->next;
q->next = p->next;
delete(p);
}
void updateActiveList(int scan, Edge* active)
{
Edge* q = active, * p = active->next;
while (p)
{
if (scan >= p->ymax)
{
p = p->next;
deleteAfter(q);
}
else
{
p->xi = p->xi + p->dx;
q = p;
p = p->next;
}
}
}
void resortActiveList(Edge* active)
{
Edge* q, * p = active->next;
active->next = NULL;
while (p)
{
q = p->next;
insertEdge(active, p);
p = q;
}
}
void scanFill(int num, Point* pts)
{
Edge* edges[WINDOW_HEIGHT], * active;
int i, scan;
for (i = 0; i < WINDOW_HEIGHT; i++)
{
edges[i] = new Edge[num];
edges[i]->next = NULL;
}
buildEdgeList(num, pts, edges);
active = new Edge;
active->next = NULL;
for (scan = 0; scan < WINDOW_HEIGHT; scan++)
{
buildActiveList(scan, active, edges);
if (active->next)
{
fillScan(scan, active);
updateActiveList(scan, active);
resortActiveList(active);
}
}
}
void myDraw(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 0.0, 0.0);
//修改顶点坐标
Point pts[] = { {100,40},{220,140},{280,80},{350,300},{200,380},{50,280},{100,40} };
scanFill(4, pts);
glFlush();
}
void main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(200, 200);
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
glutCreateWindow("扫描线算法");
init();
glutDisplayFunc(myDraw);
glutMainLoop();
}
测试结果: