区域填充之扫描线算法

       利用相邻像素之间的连贯性,提高算法效率。根据多边形内部点的连续性知:一条扫描线与多边形的交点中,入点和出点之间所有点都是多边形的内部点。所以,对所有的扫描线填充入点到出点之间所有的点就可填充多边形。

(1)处理对象:非自交多边形(边与边之间除了顶点外无其它交点)

判断扫描线上的点是否在多边形之内,根据多边形区域连续性,分为3个步骤:

– 求出扫描线与多边形所有边的交点;区域填充之扫描线算法_第1张图片

– 把这些交点的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库哦!

你可能感兴趣的:(C/C++)