Opengl Scan-Line Fill of Convex Polygons (方格)

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


#include "stdafx.h"
#include "iostream"
#include "vector"
#include "algorithm"
#include "GL/glut.h"
#define	 color_0 color(0,0,0)
#define  color_1 color(0.25,0.9,0.8)
#define  color_2 color(0.15,0.8,0.6)
#define color_3 color(1,0,0)
#define color_4 color(0,0,1)
#define color_5 color(1,1,0)
using namespace std;
const unsigned int maxn = 700;

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;
int setpoint_[maxn][maxn];

struct edge {
	float y2;
	float x1;
	float 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 ans = 0;
int time = 0;
int keytime = 0;
int time3 = 0;
float x1, y1_, x2, y2;		 //划线算法的 两个端点
float x3, y3, x4, y4, x5, y5, xmove0, ymove0, xmove1, ymove1;
float xr3, yr3;
float r1, c1, r2, c2;
int xpro, ypro;
int r;
float sf = 1;
int asn = 0;
bool determine = false;
bool check = true;
class color {
public:
	float r, g, b;

	color(float r_, float g_, float b_) {
		r = r_, g = g_, b = b_;
	}
	color() {};
};

class  screen
{
private:
	color p[maxn][maxn];
	int hight;
	int width;
	int length;
	int xo, yo;
public:
	screen(int a, int b, int c, int d, int e);
	void initscreen();
	void setpoint(int x, int y, color rgb);
	void reviselength(int  x);   //修改方格的长度
	int getlength();
	void newxoyo(int x, int y); //修改方格左下角的x,y
	int getxo();
	int getyo();
	int mapped_x(int x);
	int mapped_y(int y);
	void show();
	void filling(int a, int b, int c);

};

screen::screen(int a, int b, int c, int d, int e) {
	hight = a, width = b, length = c, xo = d, yo = e;
	for (int i = 0; i < width; i++)
		for (int j = 0; j < hight; j++) {
			p[i][j] = color_0;
		}
}

int screen::getlength() {
	return length;
}

void screen::initscreen() {
	memset(setpoint_, 0, sizeof setpoint_);
	for (int i = 0; i < width; i++)
		for (int j = 0; j < hight; j++) {
			p[i][j] = color_0;
		}
}

void screen::setpoint(int x, int y, color rgb) {
	if (x < 0 || y < 0 || x >= 700 || y >= 700)
		return;
	p[x][y] = rgb;
}

void screen::reviselength(int x) {
	length = length + x;
}

void screen::newxoyo(int x, int y) {
	xo = x;
	yo = y;
}

int screen::getxo() {
	return xo;
}

int screen::getyo() {
	return yo;
}

int screen::mapped_x(int x) {
	return int(float(x - xo) / float(length));
}

int screen::mapped_y(int y) {
	return int(float(700 - y - yo) / float(length));
}

void screen::show() {

	glColor3f(0.5, 0.5, 0.5);
	glBegin(GL_QUADS);
	glVertex2i(xo, yo);
	glVertex2i(xo, yo + hight*length);
	glVertex2i(xo + width*length, yo + hight*length);
	glVertex2i(xo + width*length, yo);
	glEnd();
	glFlush();
	glColor3f(0.4, 0.6, 0.7);
	glBegin(GL_LINES);
	for (int i = 0; i <= hight; i++) {
		glVertex2i(xo, yo + i*length);
		glVertex2i(xo + width*length, yo + i*length);
	}
	for (int i = 0; i <= width; i++) {
		glVertex2i(xo + i*length, yo);
		glVertex2i(xo + i*length, yo + hight*length);
	}
	glEnd();
	glFlush();
	glBegin(GL_QUADS);
	for (int i = 0; i < width; i++)
		for (int j = 0; j < hight; j++) {
			if (p[i][j].r != 0 || p[i][j].g != 0 || p[i][j].b != 0)
			{
				glColor3f(p[i][j].r, p[i][j].g, p[i][j].b);
				glVertex2i(xo + i*length, yo + j*length);
				glVertex2i(xo + i*length, yo + j*length + length);
				glVertex2i(xo + i*length + length, yo + j*length + length);
				glVertex2i(xo + i*length + length, yo + j*length);

			}
		}
	glEnd();
	glFlush();
}

void screen::filling(int a, int b, int c) {  //填充y值为c ,x值从a到b的区域	

	for (int i = a + 1 ; i < b ; i++) {
		if (setpoint_[i][c])
			 continue;
		else
		{
			p[i][c] = color_1;
		}
	}
	return;
}


screen matrix(50, 50, 14, 0, 0);

float fabs_(float a) {
	return a > 0 ? a : -a;
}
void reshape(int w, int h) {
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity(); 
	gluOrtho2D(0.0, w, 0.0, h);
}

void init() {
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glMatrixMode(GL_PROJECTION);
	gluOrtho2D(0.0, 700.0, 0.0, 700.0);
}

float sqrt_(float fToBeSqrted)
{
	double x = 1.0;
	while (fabs(x*x - fToBeSqrted) > 1e-5)
	{
		x = (x + fToBeSqrted / x) / 2;
	}
	return x;
}



void wheel_xy(int button ,int xe,int ye) {
	
	if (button == GLUT_WHEEL_UP) {
		 float xx = 3 / float(matrix.getlength());
		int rox = int(float(matrix.getxo()) -float(xe - matrix.getxo())*xx);
		int roy = int(float(matrix.getyo()) - float(700 - ye - matrix.getyo())*xx);
		matrix.newxoyo(rox, roy);
		matrix.reviselength(3);
	}
	else if (button == GLUT_WHEEL_DOWN) {
		float xx = 3 / float(matrix.getlength());
		int rox = int(float(matrix.getxo()) +  float(xe - matrix.getxo())*xx);
		int roy = int(float(matrix.getyo()) +  float(700 - ye - matrix.getyo())*xx);
		matrix.newxoyo(rox, roy);
		matrix.reviselength(-3);
	}
}



void mouse_drag(int button,int state,int x,int y) {
	if (button == GLUT_RIGHT_BUTTON)
	{
		if (state == GLUT_DOWN) {
			printf("?");
			determine = true;
			 xmove0 = x;
			ymove0 = 700 - y;
			xpro = matrix.getxo();
			ypro = matrix.getyo();
		}
		else
			determine = false;
	}

}

void setpoint(int x, int y, int x0, int y0) {
	matrix.setpoint(x0 + x, y0 + y, color_1);
	matrix.setpoint(x0 + y, y0 + x, color_1);
	matrix.setpoint(x0 - x, y0 - y, color_1);
	matrix.setpoint(x0 - y, y0 - x, color_1);
	matrix.setpoint(x0 + x, y0 - y, color_1);
	matrix.setpoint(x0 - x, y0 + y, color_1);
	matrix.setpoint(x0 - y, y0 + x, color_1);
	matrix.setpoint(x0 + y, y0 - x, color_1);
}

void middlecircle(int x, int y, int r) {
	int x0 = x, y0 = y;
	matrix.setpoint(r1, c1, color_1);
	matrix.setpoint(x, y, color_1);
	int p = 1 - r;
	setpoint(0, r, x0, y0);
	x = 0;
	y = r;
	while (x < y) {
		x++;
		if (p < 0)
			p += 2 * x + 1;
		else {
			y--;
			p += 2 * (x - y) + 1;
		}
		setpoint(x, y, x0, y0);
	}
}



void DDA() {
	float dx = x2 - x1;
	float dy = y2 - y1_;
	float  steps, k;
	float xincreament;
	float yincreament;

	if (fabs_(dx) > fabs_(dy))
		steps = fabs_(dx);
	else
		steps = fabs_(dy);

	xincreament = float(dx) / float(steps);
	yincreament = float(dy) / float(steps);
	float  xt = x1;
	float  yt = y1_;
	for (k = 1; k < steps; k++) {
		xt += xincreament;
		yt += yincreament;
		int x3 = int(xt + 0.5);
		int y3 = int(yt + 0.5);
		matrix.setpoint(x3, y3, color_2);
		setpoint_[x3][y3] = 1;
	}
	matrix.setpoint(int(x2), int(y2), color_2);
	setpoint_[int(x2)][int(y2)] = 1;

}
 
 
void mydisplay() {
	glClear(GL_COLOR_BUFFER_BIT);
	matrix.show();
	glutSwapBuffers();
	glutPostRedisplay();
}

bool empty_edge_table() {
	for (int i = minx_y; i < maxn; i++) {
		if (edge_table[i] != NULL)
			return false;
	}
	return true;
}


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;
			matrix.filling(int(x_1 + 0.5), int(x_2 + 0.5), 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 display() {  //扫描线算法的display
	for (int i = 0; i < point_amount; i++) {
		x1 = Point[i][0];
		y1_ = Point[i][1];
		x2 = Point[(i + 1) % point_amount][0];
		y2 = Point[(i + 1) % point_amount][1];
		DDA();
	}
	for (int i = 0; i < point_amount; i++) {
		x1 = Point[i][0];
		y1_ = Point[i][1];
		matrix.setpoint(x1, y1_, color_3 );
	}

}

void mymouse1(int button, int state, int x, int y) {		//画圆
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
		keytime++;
		if (keytime == 1) {
			matrix.initscreen();
			r1 = float(matrix.mapped_x(x));
			c1 = float(matrix.mapped_y(y));
			matrix.setpoint(r1, c1, color_1);
			matrix.show();
		}
		if (keytime == 2) {
			check = false;
			r2 = float(matrix.mapped_x(x));
			c2 = float(matrix.mapped_y(y));
			keytime = 0;
			r = int(sqrt_((r2 - r1)*(r2 - r1) + (c2 - c1)*(c2 - c1)) + 0.5);
			middlecircle(int(r1), int(c1), r);
			matrix.show();
			glutSwapBuffers();
		}
	}



	wheel_xy(button, x, y);

	mouse_drag(button, state, x, y);

}

void mymouse2(int button, int state, int x, int y) {   //移动划线
	if (button == GLUT_LEFT_BUTTON) {
		if (state == GLUT_DOWN) {
			time++;
			if (time == 1) {
				x1 = float(matrix.mapped_x(x));
				y1_ = float(matrix.mapped_y(y));
				matrix.setpoint(int(x1), int(y1_), color_2);
			}
			else if (time == 2) {
				check = false;
				time = 0;
				x2 = float(matrix.mapped_x(x));
				y2 = float(matrix.mapped_y(y));
				DDA();
				matrix.setpoint(int(x1), int(y1_), color_2);
				matrix.setpoint(int(x2), int(y2), color_2);
			}
		}
	}

	 
	wheel_xy(button, x, y);

	mouse_drag(button, state, x, y);
	 

}

/* void mymouse3(int button, int state, int x, int y) {

if (button == GLUT_LEFT_BUTTON)
if (state == GLUT_DOWN) {
time++;
if (time == 1) {
x3 = float(x / matrix.getlength());
y3 = float((700 - y) / matrix.getlength());
matrix.setpoint(x3, y3, 0.4, 0.4, 0.4);
}
else if (time == 2) {
x4 = float(x / matrix.getlength());
y4 = float((700 - y) / matrix.getlength());
matrix.setpoint(x4, y4, 0.4, 0.4, 0.4);
}
if (time == 3) {
time = 0;
x5 = float(x / matrix.getlength());
y5 = float((700 - y) / matrix.getlength());
matrix.setpoint(x5, y5, 0.4, 0.4, 0.4);

}
}

} */


void mymouse4(int button, int state, int x, int y) {   //扫描线填充算法
	if (button == GLUT_LEFT_BUTTON)
		if (state == GLUT_DOWN) {
			
			Point[point_amount][0] = matrix.mapped_x(x);
			Point[point_amount][1] = matrix.mapped_y(y);
			point_amount++;
			
			matrix.initscreen();
			matrix.setpoint(matrix.mapped_x(x), matrix.mapped_y(y),color_2);
			display();
			memset(setpoint_, 0, sizeof setpoint_);


			if (matrix.mapped_y(y) < minx_y)
				minx_y = matrix.mapped_y(y);
		}



	if (button == GLUT_RIGHT_BUTTON) {
		if (state == GLUT_DOWN) {

			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];       //存放边的两个顶点 
					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];
					EDGE_PRO[i][0][0] = Point[(i + 1) % point_amount][0];
					EDGE_PRO[i][0][1] = Point[(i + 1) % point_amount][1]; 
				}
			}

			display();
			padding();
			matrix.show();
			point_amount = 0;
		}
	}

	wheel_xy(button,x,y);

	mouse_drag(button, state, x, y);
}


void passivemotion(int x, int y) {			//鼠标移动,没有键按下


	if (time == 0 && check == true) {
		matrix.initscreen();
		matrix.setpoint((x - matrix.getxo()) / matrix.getlength(), (700 - y - matrix.getyo()) / matrix.getlength(), color_2);
		matrix.show();
	}

	if (time == 1) {				//画线算法中,已经获得一个端点
		glClear(GL_COLOR_BUFFER_BIT);
		x2 = float((x - matrix.getxo()) / matrix.getlength());
		y2 = float((700 - y - matrix.getyo()) / matrix.getlength());
		matrix.initscreen();
		DDA();
		matrix.setpoint(int(x1), int(y1_), color_2);
		matrix.show();
		glutSwapBuffers();
	}
	if (keytime == 1) {		//  画圆算法中,已经获得圆心
		glClear(GL_COLOR_BUFFER_BIT);
		r2 = float((x - matrix.getxo()) / matrix.getlength());
		c2 = float((700 - y - matrix.getyo()) / matrix.getlength());
		r = int(sqrt_((r2 - r1)*(r2 - r1) + (c2 - c1)*(c2 - c1)) + 0.5);
		matrix.initscreen();
		middlecircle(int(r1), int(c1), r);
		matrix.show();
		glutSwapBuffers();
	}
}

void activemotion(int x, int y) {		//鼠标移动,有键按下

	if (determine == true) {
		xmove1 = x;
		ymove1 = 700 - y;
		int dx = xmove1 - xmove0;
		int dy = ymove1 - ymove0;
		matrix.newxoyo(xpro + dx, ypro + dy);
		matrix.show();

	}
}

void mykeyboard(unsigned char key, int x, int y) {   //键盘
	if (key == '1') {  //键盘输入1时 画圆算法
		keytime = 0;
		matrix.initscreen();
		matrix.show();
		glutMouseFunc(mymouse1);
		glutMotionFunc(activemotion);
		glutPassiveMotionFunc(passivemotion);
	}

	if (key == '2') {   //键盘输入2时 画线算法
		matrix.initscreen();
		matrix.show();
		glutMouseFunc(mymouse2);
		glutPassiveMotionFunc(passivemotion);
		glutMotionFunc(activemotion);
	}
	if (key == '4') {
		point_amount = 0;
		matrix.initscreen();
		matrix.show();
		glutMouseFunc(mymouse4);
		glutMotionFunc(activemotion);

	}

}int main(int argc, char **argv)
{
	matrix.initscreen();
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowPosition(300, 0);
	glutInitWindowSize(700, 700);
	glutCreateWindow("syp's window");
	init();
	glutDisplayFunc(mydisplay);
	glutReshapeFunc(reshape);
	glutKeyboardFunc(mykeyboard);
	glutMainLoop();
	return 0;
}

猜你喜欢

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