Opengl Scan-Line Fill of Convex Polygons


#include "stdafx.h"
#include "stdlib.h"
#include "gl\glut.h"
#include "iostream"
#include "vector"
#include "algorithm"
using namespace std;
const unsigned int maxn = 700;
bool judge = false;
struct edge {
	float y2;   //当前边的较高的那个端点的y值
	float x1;   //当前边的较小的那个端点的x值
	float m;     //m是边的斜率的倒数
	edge *next;
	friend bool operator <(const edge&e1, const edge&e2) {
		return e1.x1 < e2.x1;
	}
};								//用vector 构建活化边表 
edge *edge_table[maxn];  //  edge_table
struct node {
	int x, y;
	node(int a, int b) {
		x = a, y = b;
	}
};
int flag[maxn];   //用于标记边那些特定的 要y-1的点
int visit[maxn];   //用于在寻找 特定点 时 标记删除掉的点
int point_amount = 0;   //顶点的个数(边的个数)
int  Point[maxn][2];
int EDGE_PRO[maxn][2][2];   //没有处理的边
int minx_y = INT_MAX;
void init() {
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glMatrixMode(GL_PROJECTION);
	gluOrtho2D(0.0, 700.0, 0.0, 700.0);
	for (int i = 0; i < maxn; i++) {
		edge_table[i] = NULL;
	}
}
bool empty_edge_table() {
	for (int i = minx_y; i < maxn; i++)
		if (edge_table[i] != NULL)
			return false;
	return true;
}
void filling(float a, float b, float c) {  //填充y值为c ,x值从a到b的区域	

	glColor3f(0.4, 0.4, 0.4);
	glBegin(GL_LINES);
	glVertex2i(a, c);
	glVertex2i(b, c);
	glEnd();
	glFlush();
	return;
}
void padding() {
	for (int i = 0; i < point_amount; i++) {   //寻找需要y-1的边 用flag记录  
		int mult1 = Point[i][1] - Point[(i + 1) % point_amount][1];
		int mult2 = Point[i][1] - Point[(i + point_amount - 1) % point_amount][1];
		if (mult1*mult2 < 0) {
			if (mult1 < 0)
				flag[(i + point_amount - 1) % point_amount] = 1;
			else
				flag[i] = 1;
		}
	}


	for (int i = 0; i < point_amount; i++) {  //建立edge_table       
		edge *p; edge *q;
		p = (edge*)malloc(sizeof edge);
		p->y2 = EDGE_PRO[i][1][1];
		if (flag[i])
			p->y2 = p->y2 - 1;
		p->x1 = EDGE_PRO[i][0][0];
		p->m = float(EDGE_PRO[i][1][0] - EDGE_PRO[i][0][0]) / float(EDGE_PRO[i][1][1] - EDGE_PRO[i][0][1]);
		p->next = NULL;

		q = edge_table[EDGE_PRO[i][0][1]];

		if (q == NULL) {
			q = p;
			edge_table[EDGE_PRO[i][0][1]] = q;
		}
		else {
			while (q->next != NULL)
				q = q->next;
			q->next = p;
		}

	}

	vector<edge>active_edge;  //声明活化边表  
	int y = minx_y;  //y从y值最小的扫描线开始   
	while (!active_edge.empty() || !empty_edge_table()) {  //当活化边表不会空 或者 edge_table 不为空就一直执行  
		if (edge_table[y] != NULL) {
			//判断扫描线+1后需不需要从edge_table中添加新的边到 活化边表中去  
			edge *q;
			q = edge_table[y];
			active_edge.push_back(*q);
			while (q->next != NULL) {
				q = q->next;
				active_edge.push_back(*q);
			}
			edge_table[y] = NULL;//将edge_table中的第y个置空  
		}
		sort(active_edge.begin(), active_edge.end());//将活化边表中的边按照x值从小到大排序  


		for (unsigned int i = 0; i < active_edge.size(); i++) {
			if (i + 1 == active_edge.size())
				break;
			float x_1 = active_edge[i].x1;
			float x_2 = active_edge[i + 1].x1;
			filling(x_1, x_2, y);
			i++;
		}
		y++;
		for (unsigned int i = 0; i < active_edge.size(); i++) {   //如果扫描线的y值+1后,活化边表中存在 不再会和扫描线相交的边 就将这条边从活化边表中删除  
			if (y > active_edge[i].y2) {
				active_edge.erase(active_edge.begin() + i);
				i--;
			}
			else {
				float x_1 = active_edge[i].x1 + active_edge[i].m;  //新加入的线段的最低点 没有考虑       
				active_edge[i].x1 = x_1;       //偶数对的获得扫描在图形内部的区域   
			}
		}
		cout << y << endl;
	}

}
void mydisplay() {

}
void display() {
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(0.4, 0.4, 0.4);
	glBegin(GL_LINES);
	for (int i = 0; i < point_amount; i++) {
		glVertex2i(Point[i][0], Point[i][1]);
		glVertex2i(Point[(i + 1) % point_amount][0], Point[(i + 1) % point_amount][1]);
	}
	glEnd();
	glFlush();
	padding();
}
void mymouse(int button, int state, int x, int y) {
	if (button == GLUT_LEFT_BUTTON)
		if (state == GLUT_DOWN) {  //如果点击左键 记录这是鼠标的坐标 为一个端点的坐标
			Point[point_amount][0] = x;
			Point[point_amount][1] = 700 - y;
			point_amount++;
			if (700 - y < minx_y)
				minx_y = 700 - y;
		}
	if (button == GLUT_RIGHT_BUTTON) {
		if (state == GLUT_DOWN) {
			printf("%d", point_amount);
			for (int i = 0; i < point_amount; i++) {
				if (Point[i][1] < Point[(i + 1) % point_amount][1]) {
					EDGE_PRO[i][0][0] = Point[i][0];       //存放边的两个顶点  将y值小的存放在EDGE_PRO[i][0][1]中
					EDGE_PRO[i][0][1] = Point[i][1];
					EDGE_PRO[i][1][0] = Point[(i + 1) % point_amount][0];
					EDGE_PRO[i][1][1] = Point[(i + 1) % point_amount][1];
				}
				else {
					EDGE_PRO[i][1][0] = Point[i][0];       //存放边的两个顶点 
					EDGE_PRO[i][1][1] = Point[i][1];        //将y值小的存放在EDGe_PRO[i][0[1]中 ,方便以后建立edge_table
					EDGE_PRO[i][0][0] = Point[(i + 1) % point_amount][0];
					EDGE_PRO[i][0][1] = Point[(i + 1) % point_amount][1];
				}
			}

			display();
		}
	}
}
int main(int argc, char **argv)
{
	memset(visit, 0, sizeof visit);
	memset(flag, 0, sizeof flag);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(20, 20);
	glutInitWindowSize(700, 700);
	glutCreateWindow("syp's window");
	init();
	glutDisplayFunc(mydisplay);

	glutMouseFunc(mymouse);
	glutMainLoop();
	return 0;
}


猜你喜欢

转载自blog.csdn.net/curtern/article/details/80516387