# 扫描线填充算法（2）

// FillPolygon.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <cstdio>
#include <malloc.h>
#include <cmath>
#include <vector>
#include <GL/glut.h>
#include <iostream>
#include <list>
using namespace std;

#define MAX_VERTECES 100
#define WINDOWWIDTH 400
#define WINDOWHEIGHT 400
#define ACCURACY 0.1
#define max(x,y) (x)>(y)?(x):(y)
#define min(x,y) (x)<(y)?(x):(y)
#define drawLine(x1,y1,x2,y2) glBegin(GL_LINES);glVertex2i((x1),(y1));glVertex2i((x2),(y2));glEnd();

typedef struct Edge{
int ymax;
float xi, dx;
}Edge;

typedef struct Point{
GLint x, y;
}Point;

typedef struct Polygon{
Point pts[MAX_VERTECES];
int polycnt;
}Polygon;

int ymin, ymax;

GLint verteces[MAX_VERTECES][2];
GLint pointn = 0;
GLint windowwidth = WINDOWWIDTH, windowheight = WINDOWHEIGHT;
GLint finish_picking_points = GL_FALSE;
GLint begin_to_draw = GL_FALSE;

list<Edge> slNet[WINDOWHEIGHT];
list<Edge> aet;

Polygon py;

void newPloygon()
{
py.polycnt = pointn;
ymin = 10000000;
ymax = 0;
for (int i = 0; i < pointn; i++)
{
py.pts[i].x = verteces[i][0];
py.pts[i].y = verteces[i][1];
ymin = min(ymin, verteces[i][1]);
ymax = max(ymax, verteces[i][1]);
}
}

void initScanLineNewEdgeTable()
{
for (int i = 0; i < WINDOWHEIGHT; i++)
{
slNet[i].clear();
}
Edge e;

for (int i = 0; i < py.polycnt; i++)
{
const Point & ps = py.pts[i];
const Point & pe = py.pts[(i + 1) % py.polycnt];
const Point & pee = py.pts[(i + 2) % py.polycnt];
const Point & pss = py.pts[(i - 1 + py.polycnt) % py.polycnt];

if (pe.y != ps.y)
{
e.dx = (double)(pe.x - ps.x) / (double)(pe.y - ps.y);
if (pe.y > ps.y)
{
e.xi = ps.x;
if (pee.y >= pe.y)
{
e.ymax = pe.y - 1;
}
else
{
e.ymax = pe.y;
}
slNet[ps.y].push_front(e);
}
else
{
e.xi = pe.x;
if (pss.y >= ps.y)
{
e.ymax = ps.y - 1;
}
else
{
e.ymax = ps.y;
}
slNet[pe.y].push_front(e);
}
}
}
}

void HorizonEdgeFill()
{
int id1, id2;
int x1, x2, y1, y2;
for (int i = 0; i < py.polycnt; i++)
{
id1 = i;
id2 = (i + 1) % py.polycnt;
if (py.pts[id1].y == py.pts[id2].y)
{
x1 = py.pts[id1].x;
y1 = py.pts[id1].y;
x2 = py.pts[id2].x;
y2 = py.pts[id2].y;
drawLine(x1, y1, x2, y2);
}
}
glFlush();
}
bool EdgeXiComparator(Edge& e1, Edge& e2)
{
return e1.xi < e2.xi;
}
void InsertNetListToAet(int y)
{
for (list<Edge>::iterator it1 = slNet[y].begin(); it1 != slNet[y].end(); ++it1)
{
//cout << it1->xi << " " << it1->dx << " " << it1->ymax << endl;
aet.push_back(*it1);
}
aet.sort(EdgeXiComparator);
}

void FillAetScanLine(int y)
{
bool flag;
flag = true;
list<Edge>::iterator it1;
for (list<Edge>::iterator it = aet.begin(); it != aet.end(); it++)
{
it1 = it;
it1++;
if (it1 == aet.end())
{
break;
}
if (flag)
{
drawLine(it->xi, y, it1->xi, y);
}
flag = !flag;
}
glFlush();
}

//bool IsEdgeOutOfActive(Edge e, int y)
//{
//  return (e.ymax == y);
//}

void ProcessScanLineFill()
{
aet.clear();
for (int y = ymin; y <= ymax; y++)
{
InsertNetListToAet(y);
FillAetScanLine(y);
//删除非活动边
for (list<Edge>::iterator it = aet.begin(); it != aet.end();)
{
if (it->ymax == y)
{
it = aet.erase(it);
}
else
{
it++;
}
}

//更新活动边表中每项的xi值，并根据xi重新排序
//更新xi
for (list<Edge>::iterator iter = aet.begin(); iter != aet.end(); iter++)
iter->xi += iter->dx;
//根据xi从小到大重新排序
aet.sort(EdgeXiComparator);
}
}
void draw()
{
initScanLineNewEdgeTable();
HorizonEdgeFill();
ProcessScanLineFill();
}
void init()
{
//glClearColor(0.0, 0.0, 0.0, 0.0);
}
void display()
{
int k;
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_POINTS);
for (k = 0; k < pointn; k++)
{
glVertex2i(verteces[k][0], verteces[k][1]);
}
glEnd();
if (begin_to_draw == GL_TRUE)
{
glColor3f(0.0, 1.0, 1.0);
draw();
}
glutSwapBuffers();
//glFlush();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key){
case 'r':
case 'R':
pointn = 0;
finish_picking_points = GL_FALSE;
begin_to_draw = GL_FALSE;
break;
case 'b':
case 'B':
begin_to_draw = GL_FALSE;
break;
case 'n':
case 'N':
begin_to_draw = GL_TRUE;
break;
};
glutPostRedisplay();
}

//测试使用
//int xx[4] = { 0, 4, 10 };
//int yy[4] = { 0, 6, 4 };

void mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
if (finish_picking_points == GL_FALSE)      //如果是按下鼠标左键
{
verteces[pointn][0] = x;                //记录按下的点的x坐标
verteces[pointn][1] = windowheight - y; //记录按下的点的y坐标，由于坐标系原点一个是在左上角，一个是在左下角，所以要用windowheight-y。
/*verteces[pointn][0] = xx[pointn];
verteces[pointn][1] = yy[pointn];*/
pointn++;
}
}
else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) //如果是按下鼠标右键
{
newPloygon();   //构建多边形
finish_picking_points = GL_TRUE; //停止画点
begin_to_draw = GL_TRUE; //开始填充
}
glutPostRedisplay();
}

void reshape(int w, int h)
{
windowwidth = w;
windowheight = h;
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h);
}

int main(int argc, char ** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(windowwidth, windowheight);
glutInitWindowPosition(300, 300);
glutCreateWindow("扫描线算法");
//init();
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutReshapeFunc(reshape);
glutMainLoop();

return 0;
}


• 本文已收录于以下专栏：

## 多边形区域填充算法－－扫描线填充算法（有序边表法）

• u013044116
• 2015年11月09日 13:50
• 5876

## 扫描线填充多边形算法详解与代码

• qq_27161673
• 2016年10月30日 19:54
• 6003

## 扫描线填充算法（1）

• 2016年08月08日 18:00
• 685

## 计算机图形学（三）扫描线多边形填充算法讲解与源代码

• syx1065001748
• 2015年06月22日 16:28
• 5699

## 算法系列之十二：多边形区域填充算法－－扫描线填充算法（有序边表法）

• orbit
• 2012年03月19日 14:57
• 67434

## opengl实现直线扫描算法和区域填充算法

1、 采用直线扫描算法绘制一条线段，直线由离散点组成 2、 利用区域填充算法绘制多边形区域，区域由离散点组成...
• zjccoder
• 2014年11月15日 15:20
• 7520

## 【图像处理】边相关扫描线填充算法

• xiaowei_cqu
• 2012年07月03日 19:12
• 19758

## 种子填充算法，扫描线填充算法，带报告

• 2012年01月15日 13:07
• 1.91MB
• 下载

## 多边形区域填充算法－－扫描线种子填充算法

http://blog.csdn.net/orbit/article/details/7343236   1.3扫描线种子填充算法         1.1和1.2节介绍的两种种子填充算法的优点是...
• jiangxinyu
• 2012年08月27日 13:56
• 10647

## 关于扫描线的一些理解

• qq919017553
• 2015年12月27日 16:46
• 3846

举报原因： 您举报文章：扫描线填充算法（2） 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)