利用相邻像素之间的连贯性,提高算法效率。根据多边形内部点的连续性知:一条扫描线与多边形的交点中,入点和出点之间所有点都是多边形的内部点。所以,对所有的扫描线填充入点到出点之间所有的点就可填充多边形。
(1)处理对象:非自交多边形(边与边之间除了顶点外无其它交点)
判断扫描线上的点是否在多边形之内,根据多边形区域连续性,分为3个步骤:
– 把这些交点的x坐标值以升序排列;
– 对每一对交点间的区域进行填充。
– 第三个步骤是从奇数个交点出发到偶数个交点。如右图,对y=8的扫描线排序x坐标得到的表是(2,4,9,13),然后对交点2与4之间、9与13之间的所有象素点进行填充。
(2)几点规则:
边界上的象素:“左闭右开”,“下闭上开”(将左边界和下边界的点算为内部,而将右边界和上边界算为外部)
顶点:“上开下闭”。
(3)几种特殊情况:
1.扫描线交于一顶点,共享的两条边分另处于扫描线的两边,这时交点只取一个,如扫描线y=3,该点被填充一次。
2. 共享交点的两条边处于扫描线的上方,这时交点取二个,如扫描线y=1,该点被填充一次。
3.共享交点的两条边处于扫描线的下方,这时交点取0个,如扫描线y=9,无交点,不填充。
4.水平边在算法中不起任何作用,可不考虑。
活性边表(提高效率):
为了减少求交的计算量,要利用一条边与相继的两条扫描线的交点的连贯性。在处理一条扫描线时只对活性边(与它相交的多边形的边)进行求交运算。把交点按x增加方向存在一个链表(活性边表)中。
活性边:与当前扫描线相交的边。
活性边表(AEL):按交点x的增量顺序存放在一个链表中,该链表称作活性边表(AEL)。
源程序:
#include
#include
static int n;
static int y_max;
static int x_max;
typedef struct Point {
int x;
int y;
} Point1;
static Point1 seed;
Point *InitPoint() {
n = 8;
Point1 *tran = (Point*)malloc(n * sizeof(struct Point));
tran[0].x = 10; tran[0].y = 10;
tran[1].x = 90; tran[1].y = 10;
tran[2].x = 90; tran[2].y = 60;
tran[3].x = 140; tran[3].y = 60;
tran[4].x = 140; tran[4].y = 160;
tran[5].x = 80; tran[5].y = 160;
tran[6].x = 80; tran[6].y = 70;
tran[7].x = 10; tran[7].y = 70;
seed.x = 50; seed.y = 50;
return tran;
}
void setEdge(int x, int y, int **NumGroup) {
NumGroup[x][y] = 1;
}
void MidpointLine(int x0, int y0, int x1, int y1, int **NumGroup)
{
int a, b, d1, d2, d, x, y; float m;
if (x1= 0 && m <= 1) {
d = 2 * a + b; d1 = 2 * a, d2 = 2 * (a + b);
while (x= -1) {
d = 2 * a - b; d1 = 2 * a - 2 * b, d2 = 2 * a;
while (x0) { x++, y--, d += d1; }
else {
x++, d += d2;
}
setEdge(x, y, NumGroup);
}
}
else if (m>1) {
d = a + 2 * b; d1 = 2 * (a + b), d2 = 2 * b;
while (y0) {
x++, y++, d += d1;
}
else {
y++, d += d2;
}
setEdge(x, y, NumGroup);
}
}
else {
d = a - 2 * b; d1 = -2 * b, d2 = 2 * (a - b);
while (y>y1) {
if (d <= 0) {
x++, y--, d += d2;
}
else {
y--, d += d1;
}
setEdge(x, y, NumGroup);
}
}
}
void print(int **NumGroupMaxtrx, int x_num, int y_num) {
int i;
int j;
for (i = 0; i < x_num; i++) {
for (j = 0; j < y_num; j++) {
//如果是边界点
if (NumGroupMaxtrx[i][j] == 1) {
glVertex2i(i, j);
}
}
}
}
int **InitPointMatrixByPoint(Point *p) {
int i;
y_max = p[0].x;
x_max = p[0].y;
for (i = 0; i < n; i++) {
if (p[i].x>x_max)
x_max = p[i].x;
if (p[i].y > y_max)
y_max = p[i].y;
}
y_max++; x_max++;
int **NumGroup_Matrix = (int**)malloc(x_max * sizeof(int *));
for (i = 0; i < x_max; i++) {
NumGroup_Matrix[i] = (int*)malloc(y_max * sizeof(int));
}
int j;
for (i = 0; i < x_max; i++) {
for (j = 0; j < y_max; j++) {
//取值有-1,0,1三种情况分别表示无效,内点和边界点
NumGroup_Matrix[i][j] = -1;
}
}
for (i = 0; i < n; i++) {
if (i != n - 1)
MidpointLine(p[i].x, p[i].y, p[i + 1].x, p[i + 1].y, NumGroup_Matrix);
else
MidpointLine(p[i].x, p[i].y, p[0].x, p[0].y, NumGroup_Matrix);
}
return NumGroup_Matrix;
}
struct STACKNODE {
Point point;
struct STACKNODE *next;
};
typedef struct STACKNODE *PtrToNode;
typedef struct STACKNODE *Stack;
Stack createStack() {
Stack stack = (STACKNODE*)malloc(sizeof(struct STACKNODE));
stack->next = NULL;
return stack;
}
void *Push(Stack stack, Point point) {
PtrToNode tempNode = (STACKNODE*)malloc(sizeof(struct STACKNODE));
tempNode->point.x = point.x;
tempNode->point.y = point.y;
tempNode->next = stack->next;
stack->next = tempNode;
return 0;
}
Point *PopAndTop(Stack stack) {
PtrToNode ptr = stack->next;
stack->next = stack->next->next;
return &ptr->point;
}
int IsNull(Stack s) {
if (s->next == NULL)
return 1;
else
return 0;
}
void scanLineFixArea(int **numGroupMatrix) {
Stack s = createStack();
Push(s, seed);
Point *tempPoint;
Point left, right;
int i;
while (!IsNull(s)) {
tempPoint = PopAndTop(s);
glVertex2i(tempPoint->x, tempPoint->y); numGroupMatrix[tempPoint->x][tempPoint->y] = 0;
left.y = tempPoint->y;
right.y = tempPoint->y;
left.x = tempPoint->x;
right.x = tempPoint->x;
while (numGroupMatrix[left.x][left.y] != 1) {
glVertex2i(left.x, left.y); numGroupMatrix[left.x][left.y] = 0;
left.x--;
}
while (numGroupMatrix[right.x][right.y] != 1) {
glVertex2i(right.x, right.y); numGroupMatrix[right.x][right.y] = 0;
right.x++;
}
for (i = right.x; i >= left.x; i--) {
if (numGroupMatrix[i][right.y + 1] == -1) {
right.y++;
right.x = i;
Push(s, right);
break;
}
}
right.y = tempPoint->y;
for (i = right.x; i >= left.x; i--) {
if (numGroupMatrix[i][right.y - 1] == -1) {
right.y--;
right.x = i;
Push(s, right);
break;
}
}
}
}
void ProcessExcute() {
//1.初始化待填充区域的边界线段端点和种子坐标
Point *p = InitPoint();
//2.栅格化边界线段端点表示的待填充区域到像素阵列数组里
int **numGroupMatrix = InitPointMatrixByPoint(p);
//3.用扫描线算法进行区域填充:
scanLineFixArea(numGroupMatrix);
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glColor3d(1.0, 1.0, 1.0);
glBegin(GL_POINTS);
ProcessExcute();
glEnd();
glFlush();;
}
void Init() {
glClearColor(0, 0, 0, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//定义裁剪区域
gluOrtho2D(0, 240, 0, 240);
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(300, 300);
glutInitWindowSize(400, 400);
glutCreateWindow("扫描线区域填充算法");
Init();
glutDisplayFunc(display);
glutMainLoop();
system("pause");
return 0;
}
要运行此代码,需要在编译器上自行导入OpenGL库哦!