为方便找代码的朋友直接看代码,先把代码和运行结果贴上:
point polypoint[POINTNUM]{ 250,50,550,150,550,400,250,250,100,350,100,100,120,30 };//多边形顶点
void GlAreaFilled::PolyScanner(void)
{
/******计算最高点的y坐标(扫描到此结束)****************************************/
int MaxY = 0;
int i;
for (i = 0; i < POINTNUM; i++)
if (polypoint[i].y > MaxY)
MaxY = polypoint[i].y;
/*******初始化AET表***********************************************************/
AET *pAET = new AET;
pAET->next = NULL;
/******初始化NET表************************************************************/
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);
/******扫描并建立NET表*********************************************************/
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;
}
}
}
/******建立并更新活性边表AET*****************************************************/
for (i = 0; i <= MaxY; i++)
{
//计算新的交点x,更新AET
NET *p = pAET->next;
while (p)
{
p->x = p->x + p->dx;
p = p->next;
}
//更新后新AET先排序*************************************************************/
//断表排序,不再开辟空间
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表中删除ymax==i的结点****************************************/
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;
}
}
//将NET中的新点加入AET,并用插入法按X值递增排序**********************************/
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 <= p->next->x; j++)
glVertex2i(static_cast<int>(j), i);
p = p->next->next;//考虑端点情况
}
}
glEnd();
glFlush();
}
void GlAreaFilled::Init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
// 窗口颜色设置为白色
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, 600.0, 0.0, 450.0);
}
void GlAreaFilled::PolyGLProEnter(int argc, char* argv)
{
glutInit(&argc, &argv); // 初始化Glut
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); //设置显示模式:单个缓存和使用RGB模型
glutInitWindowPosition(50, 100); //设置窗口的顶部和左边位置
glutInitWindowSize(400, 300); //设置窗口的高度和宽度
glutCreateWindow("An Example OpenGL Program"); //创建显示窗口
Init(); //调用初始化过程
glutDisplayFunc(PolyScan); //图形的定义传递给我window.
glutMainLoop(); //显示所有的图形并等待
}
多边形的扫描转换和区域填充这个问题是怎么样在离散的像素集上,表示一个连续的二维图形。
多边形有两种重要的表示形式:顶点表示与点阵表示,具体如下:
顶点表示是用多边形的顶点序列来表示多边形。这种表示直观、几何意义强、占内存少,易于进行几何变换。
但由于它没有明确指出哪些象素在多边形内,故不能直接用于面着色。
点阵表示是用位于多边形内的象素集合来刻画多边形。这种表示丢失了许多几何信息(如边界、顶点等),
但它却是光栅显示系统显示时所需的表示形式。因为需要通过记录每个点的像素具体设置的值来点亮显示器。
我们就可以思考两个问题:
光栅图形的一个基本问题是把多边形的顶点表示转换为点阵表示。这种转换称为多边形的扫描转换。
X-扫描线算法填充多边形的基本思想是按扫描线顺序,计算扫描线与多边形的相交区间。
再用要求的颜色显示这些区间的像素,即完成填充工作。
区间的端点可以通过计算扫描线与多边形边界线的交点获得。
排序、配对、填色总是要的!最理想的算法是不求交!
扫描转换算法重要意义是提出了图形学里两个重要的思想:
那么求交点的时候能不能也采取增量的方法?每条扫描线的 y y 值都知道,关键是求 x x 的值。 x x 是什么?
我们可以从三个方面来考虑如何改进该算法:
为了避免求交运算,需要引进一套特殊的数据结构。
void polyfill (polygon, color)
int color; 多边形 polygon;
{
for (各条扫描线i )
{
初始化新边表头指针NET[i];
把ymin = i 的边放进边表NET[i];
}
y = 最低扫描线号;
初始化活性边表AET为空;
for (各条扫描线i )
{
把新边表NET[i] 中的边结点用插入排序法插入AET表,使之按x坐标递增顺序排列;
遍历AET表,把配对交点区间(左闭右开)上的象素(x,y),用putpixel(x,y,color) 改写象素颜色值;
遍历AET表,把ymax= i 的结点从AET表中删除,并把ymax>i结点的x值递增x;
若允许多边形的边自相交,则用冒泡排序法对AET表重新排序;
}
} /* polyfill */
point polypoint[POINTNUM]{ 250,50,550,150,550,400,250,250,100,350,100,100,120,30 };//多边形顶点
void GlAreaFilled::PolyScanner(void)
{
/******计算最高点的y坐标(扫描到此结束)****************************************/
int MaxY = 0;
int i;
for (i = 0; i < POINTNUM; i++)
if (polypoint[i].y > MaxY)
MaxY = polypoint[i].y;
/*******初始化AET表***********************************************************/
AET *pAET = new AET;
pAET->next = NULL;
/******初始化NET表************************************************************/
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);
/******扫描并建立NET表*********************************************************/
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;
}
}
}
/******建立并更新活性边表AET*****************************************************/
for (i = 0; i <= MaxY; i++)
{
//计算新的交点x,更新AET
NET *p = pAET->next;
while (p)
{
p->x = p->x + p->dx;
p = p->next;
}
//更新后新AET先排序*************************************************************/
//断表排序,不再开辟空间
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表中删除ymax==i的结点****************************************/
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;
}
}
//将NET中的新点加入AET,并用插入法按X值递增排序**********************************/
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 <= p->next->x; j++)
glVertex2i(static_cast<int>(j), i);
p = p->next->next;//考虑端点情况
}
}
glEnd();
glFlush();
}
void GlAreaFilled::Init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
// 窗口颜色设置为白色
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, 600.0, 0.0, 450.0);
}
void GlAreaFilled::PolyGLProEnter(int argc, char* argv)
{
glutInit(&argc, &argv); // 初始化Glut
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); //设置显示模式:单个缓存和使用RGB模型
glutInitWindowPosition(50, 100); //设置窗口的顶部和左边位置
glutInitWindowSize(400, 300); //设置窗口的高度和宽度
glutCreateWindow("An Example OpenGL Program"); //创建显示窗口
Init(); //调用初始化过程
glutDisplayFunc(PolyScan); //图形的定义传递给我window.
glutMainLoop(); //显示所有的图形并等待
}