計算機圖形學E9——裁剪——固定矩形窗口裁剪多邊形(凸多邊形/凹多邊形)

其他計算機圖形學實驗見 鏈接

裁剪不包含凹多邊形的代碼

#include<gl/glut.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<time.h>
using namespace std;
const int window_width = 800, window_height = 600;
struct point
{
	float x, y;
	point() {}
	point(float xx, float yy)
		:x(xx), y(yy) {}

	bool operator < (const point& a)const
	{
		return x < a.x;
	}
};
struct EDGE//Edge
{
	float bx, by, ex, ey;
	EDGE() {}
	EDGE(float bxx, float byy, float exx, float eyy)
		:bx(bxx), by(byy), ex(exx), ey(eyy) {}
};
map<point, int> vis;
vector<point> input_vertice;
vector<point> output_vertice;
float intersect_point_color[3] = { 1,0,0 };
float polygon_point_color[3] = { 0,0,1 };
EDGE left(200, 450, 200, 200);
EDGE bottom(200, 200, 600, 200);
EDGE right(600, 200, 600, 450);
EDGE top(600, 450, 200, 450);

void draw_a_point(float x, float y, float color[]);
bool inside(point& pt, EDGE ClipBoundary);//判斷點是否可見
void intersect(point& s, point& p, EDGE ClipBoundary, point& intersect_pt);//直線段SP和邊界求交,返回交點
void SutherlandHodgmanClip(EDGE ClipBoundary, int in_len, int& out_len);
//void output(point pt)
//{
//	//draw_a_point(pt.x, pt.y, intersect_point_color);
//	output_vertice.push_back(pt);
//	//cout << "output_vertice" << output_vertice.size() << ": (" << pt.x << ", " << pt.y << ")" << endl;
//}
void mymouse(int button, int state, int x, int y);
void keyboard(unsigned char key, int x, int y);

int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RED);
	glutInitWindowPosition(50, 50);
	glutInitWindowSize(window_width, window_height);
	glutCreateWindow("固定矩形窗口裁剪交互式多邊形");
	cout << "左鍵畫點\n右鍵連接成窗口\n按空格裁剪\n" << endl;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0, window_width, 0, window_height);

	glClearColor(1, 1, 1, 1);
	glClear(GL_COLOR_BUFFER_BIT);

	//畫出邊界
	glColor3f(0, 1, 0);
	glLineWidth(2.0f);
	glBegin(GL_LINES);
	glVertex2f(::left.bx, ::left.by); glVertex2f(::left.ex, ::left.ey);
	glVertex2f(bottom.bx, bottom.by); glVertex2f(bottom.ex, bottom.ey);
	glVertex2f(::right.bx, ::right.by); glVertex2f(::right.ex, ::right.ey);
	glVertex2f(top.bx, top.by); glVertex2f(top.ex, top.ey);
	glEnd();
	glFlush();

	glutMouseFunc(&mymouse);
	glutKeyboardFunc(&keyboard);

	glutMainLoop();
	return 0;
}

bool inside(point& pt, EDGE ClipBoundary)//判斷點是否可見
{
	if (ClipBoundary.ex > ClipBoundary.bx)
	{
		if (pt.y >= ClipBoundary.by)//裁剪邊爲窗口下邊沿
			return true;
	}
	else if (ClipBoundary.ex < ClipBoundary.bx)
	{
		if (pt.y <= ClipBoundary.by)//裁剪邊爲窗口上邊沿
			return true;
	}
	else if (ClipBoundary.ey > ClipBoundary.by)//裁剪邊爲窗口右邊沿
	{
		if (pt.x <= ClipBoundary.bx)
			return true;
	}
	else if (ClipBoundary.ey < ClipBoundary.by)//裁剪邊爲窗口左邊沿
	{
		if (pt.x >= ClipBoundary.bx)
			return true;
	}
	return false;
}

void intersect(point& s, point& p, EDGE ClipBoundary, point& intersect_pt)//直線段SP和邊界求交,返回交點
{
	if (ClipBoundary.by == ClipBoundary.ey)//水平裁剪邊界
	{
		intersect_pt.y = ClipBoundary.by;
		//x=起點的橫座標+dy/sp斜率
		intersect_pt.x = s.x + (ClipBoundary.by - s.y) * (p.x - s.x) / (p.y - s.y);
	}
	else//垂直裁剪邊界
	{
		intersect_pt.x = ClipBoundary.bx;
		intersect_pt.y = s.y + (ClipBoundary.bx - s.x) * (p.y - s.y) / (p.x - s.x);
	}
}

void SutherlandHodgmanClip(EDGE ClipBoundary)
{
	point s, p, ip;
	output_vertice.clear();
	s = input_vertice[input_vertice.size() - 1];//首尾

	for (int j = 0; j < input_vertice.size(); j++)
	{
		p = input_vertice[j];
		if (inside(p, ClipBoundary))//p在內
		{
			if (inside(s, ClipBoundary))//sp都在窗口內
			{
				//output(p);
				output_vertice.push_back(p);

				//map<point, int>::iterator it = vis.find(p);
				//if (it == vis.end())//沒找到
				//	vis[p] = 1;
				//else
				//	vis[p]++;
			}
			else//p在裏面 s不在
			{
				intersect(s, p, ClipBoundary, ip);
				//output(ip);
				//output(p); 
				output_vertice.push_back(ip);
				output_vertice.push_back(p);

				//map<point, int>::iterator it = vis.find(p);
				//if (it == vis.end())//沒找到
				//	vis[p] = 1;
				//else
				//	vis[p]++;

				//it = vis.find(ip);
				//if (it == vis.end())//沒找到
				//	vis[ip] = 1;
				//else
				//	vis[ip]++;
			}
		}
		else//s在外面
		{
			if (inside(s, ClipBoundary))//s在窗口內p在窗口外
			{
				intersect(s, p, ClipBoundary, ip);

				//output(ip);
				output_vertice.push_back(ip);
				//map<point, int>::iterator it = vis.find(ip);
				//if (it == vis.end())//沒找到
				//	vis[ip] = 1;
				//else
				//	vis[ip]++;
			}
			//sp都在外面則無輸出
		}
		s = p;
	}
	input_vertice = output_vertice;//這次的輸出作爲下一次的輸入,input_vertice和output_vertice是全局變量
}

void draw_a_point(float x, float y, float color[])
{
	glPointSize(5.0f);
	glBegin(GL_POINTS);
	glColor3fv(color);
	glVertex2f(x, y);
	glEnd();
	glFlush();
}

void mymouse(int button, int state, int x, int y)
{
	glClearColor(1, 1, 1, 1);
	//bool flag = 0;

	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		draw_a_point(x, window_height - y, polygon_point_color);
		point p(x, window_height - y);
		input_vertice.push_back(p);
		cout << "多邊形頂點" << input_vertice.size() << ":(" << x << ", " << window_height - y << ")" << endl;
	}

	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
	{
			glLineWidth(2.0f);
			glBegin(GL_LINES);
			glColor3fv(polygon_point_color);
			for (int i = 0; i < input_vertice.size(); i++)
			{
				if (i == input_vertice.size() - 1)
				{
					glVertex2f(input_vertice[0].x, input_vertice[0].y);
					glVertex2f(input_vertice[i].x, input_vertice[i].y);
				}
				else
				{
					glVertex2f(input_vertice[i].x, input_vertice[i].y);
					glVertex2f(input_vertice[i + 1].x, input_vertice[i + 1].y);
				}
			}
			glEnd();
			glFlush();
	}
}

void keyboard(unsigned char key, int x, int y)
{
	if (key == 32)
	{
		SutherlandHodgmanClip(::left);
		SutherlandHodgmanClip(bottom);
		SutherlandHodgmanClip(::right);
		SutherlandHodgmanClip(top);

		glLineWidth(4.0f);
		glBegin(GL_LINE_LOOP);
		glColor3fv(intersect_point_color);
		for (int i = 0; i < output_vertice.size(); i++)
		{//draw_a_point(output_vertice[i].x, output_vertice[i].y, intersect_point_color);
			glVertex2f(output_vertice[i].x, output_vertice[i].y);
		}
		glEnd();
		glFlush();

	}
}

裁剪包含凹多邊形的代碼

#include<gl/glut.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<time.h>
using namespace std;
const int window_width = 800, window_height = 600;
struct point
{
	float x, y;
	point() {}
	point(float xx, float yy)
		:x(xx), y(yy) {}

	bool operator < (const point& a)const
	{
		return x < a.x;
	}
};
struct EDGE//Edge
{
	float bx, by, ex, ey;
	EDGE() {}
	EDGE(float bxx, float byy, float exx, float eyy)
		:bx(bxx), by(byy), ex(exx), ey(eyy) {}
};
map<float, map<float, int> > vis;
vector<point> input_vertice;
vector<point> output_vertice;
float intersect_point_color[3] = { 1,0,0 };
float polygon_point_color[3] = { 0,0,1 };
EDGE left(200, 450, 200, 200);
EDGE bottom(200, 200, 600, 200);
EDGE right(600, 200, 600, 450);
EDGE top(600, 450, 200, 450);

void draw_a_point(float x, float y, float color[]);
bool inside(point& pt, EDGE ClipBoundary);//判斷點是否可見
void intersect(point& s, point& p, EDGE ClipBoundary, point& intersect_pt);//直線段SP和邊界求交,返回交點
void SutherlandHodgmanClip(EDGE ClipBoundary, int in_len, int& out_len);
void mymouse(int button, int state, int x, int y);
void keyboard(unsigned char key, int x, int y);
void draw_line_point(float x, float y);
void bresenham1(GLint x1, GLint y1, GLint x2, GLint y2);

int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RED);
	glutInitWindowPosition(50, 50);
	glutInitWindowSize(window_width, window_height);
	glutCreateWindow("固定矩形窗口裁剪交互式多邊形");
	cout << "左鍵畫點\n右鍵連接成窗口\n按空格裁剪\n" << endl;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0, window_width, 0, window_height);

	glClearColor(1, 1, 1, 1);
	glClear(GL_COLOR_BUFFER_BIT);

	//畫出邊界
	glColor3f(0, 1, 0);
	glLineWidth(2.0f);
	glBegin(GL_LINES);
	glVertex2f(::left.bx, ::left.by); glVertex2f(::left.ex, ::left.ey);
	glVertex2f(bottom.bx, bottom.by); glVertex2f(bottom.ex, bottom.ey);
	glVertex2f(::right.bx, ::right.by); glVertex2f(::right.ex, ::right.ey);
	glVertex2f(top.bx, top.by); glVertex2f(top.ex, top.ey);
	glEnd();
	glFlush();

	glutMouseFunc(&mymouse);
	glutKeyboardFunc(&keyboard);

	glutMainLoop();
	return 0;
}

bool inside(point& pt, EDGE ClipBoundary)//判斷點是否可見
{
	if (ClipBoundary.ex > ClipBoundary.bx)
	{
		if (pt.y >= ClipBoundary.by)//裁剪邊爲窗口下邊沿
			return true;
	}
	else if (ClipBoundary.ex < ClipBoundary.bx)
	{
		if (pt.y <= ClipBoundary.by)//裁剪邊爲窗口上邊沿
			return true;
	}
	else if (ClipBoundary.ey > ClipBoundary.by)//裁剪邊爲窗口右邊沿
	{
		if (pt.x <= ClipBoundary.bx)
			return true;
	}
	else if (ClipBoundary.ey < ClipBoundary.by)//裁剪邊爲窗口左邊沿
	{
		if (pt.x >= ClipBoundary.bx)
			return true;
	}
	return false;
}

void intersect(point& s, point& p, EDGE ClipBoundary, point& intersect_pt)//直線段SP和邊界求交,返回交點
{
	if (ClipBoundary.by == ClipBoundary.ey)//水平裁剪邊界
	{
		intersect_pt.y = ClipBoundary.by;
		//x=起點的橫座標+dy/sp斜率
		intersect_pt.x = s.x + (ClipBoundary.by - s.y) * (p.x - s.x) / (p.y - s.y);
	}
	else//垂直裁剪邊界
	{
		intersect_pt.x = ClipBoundary.bx;
		intersect_pt.y = s.y + (ClipBoundary.bx - s.x) * (p.y - s.y) / (p.x - s.x);
	}
}

void bresenham1(GLint x1, GLint y1, GLint x2, GLint y2)
{
	//glClear(GL_COLOR_BUFFER_BIT);

	draw_line_point(x1, y1);

	int dx = abs(x1 - x2);
	int dy = abs(y1 - y2);
	int flag = 0;//表示當前斜率k的絕對值是否大於1
	if (dx == 0 && dy == 0)
		return;

	if (dy > dx)//斜率絕對值大於1
	{
		flag = 1;
		//橫縱座標軸互換,將x視作y,將y視作x,所有座標都需要互換
		swap(x1, y1);
		swap(x2, y2);
		swap(dx, dy);
	}

	//確定步長tx,ty,斜率爲正或爲負,且只考慮左/右上or左/右下,左/右邊的情況不加步長即可
	int tx = x2 > x1 ? 1 : -1;
	int ty = y2 > y1 ? 1 : -1;

	//確定下一個點的座標x,y
	int x = x1 + 1;
	int y = y1;

	//dt和ds由迭代公式推出。dt是右上的點,ds是右邊的點
	int dt = 2 * (dy - dx);
	int ds = 2 * dy;

	//判別式的值d=2k*dx-dx = 2*dy-dx
	int d = 2 * dy - dx;

	while (x != x2)
	{
		if (d >= 0)//選T點(右上的點
		{
			//d(i+1) = d(i) + 2(dy - dx)
			d += dt;
			y += ty;
		}
		else//選S點,y方向不加步長
		{
			//d(i+1) = d(i) + 2*dy
			d += ds;
		}

		if (flag)//斜率大於1
		{
			draw_line_point(y, x);
		}
		else
		{
			draw_line_point(x, y);
		}
		x += tx;//x增加步長
	}
}

void SutherlandHodgmanClip(EDGE ClipBoundary)
{
	point s, p, ip;
	output_vertice.clear();
	s = input_vertice[input_vertice.size() - 1];//首尾

	for (int j = 0; j < input_vertice.size(); j++)
	{
		p = input_vertice[j];
		if (inside(p, ClipBoundary))//p在內
		{
			if (inside(s, ClipBoundary))//sp都在窗口內
			{
				//output(p);
				output_vertice.push_back(p);
			}
			else//p在裏面 s不在
			{
				intersect(s, p, ClipBoundary, ip);
				//output(ip);
				//output(p); 
				output_vertice.push_back(ip);
				output_vertice.push_back(p);

			}
		}
		else//s在外面
		{
			if (inside(s, ClipBoundary))//s在窗口內p在窗口外
			{
				intersect(s, p, ClipBoundary, ip);

				//output(ip);
				output_vertice.push_back(ip);
			}
			//sp都在外面則無輸出
		}
		s = p;
	}
	input_vertice = output_vertice;//這次的輸出作爲下一次的輸入,input_vertice和output_vertice是全局變量
}

void draw_a_point(float x, float y, float color[])
{
	glPointSize(5.0f);
	glBegin(GL_POINTS);
	glColor3fv(color);
	glVertex2f(x, y);
	glEnd();
	glFlush();
}

void draw_line_point(float x, float y)
{
	vis[x][y]++;
	glPointSize(2.5f);
	glBegin(GL_POINTS);
	if (vis[x][y] % 2 == 0)//訪問偶數次,塗白色
	{
		glColor3f(1, 1, 1);
		glVertex2f(x, y);
	}
	else
	{
		glColor3f(1, 0, 0);//奇數次,塗紅色
		glVertex2f(x, y);
	}

	glEnd();
	glFlush();
}

void mymouse(int button, int state, int x, int y)
{
	glClearColor(1, 1, 1, 1);
	//bool flag = 0;

	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		draw_a_point(x, window_height - y, polygon_point_color);
		point p(x, window_height - y);
		input_vertice.push_back(p);
		cout << "多邊形頂點" << input_vertice.size() << ":(" << x << ", " << window_height - y << ")" << endl;
	}

	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
	{
		glLineWidth(2.0f);
		glBegin(GL_LINES);
		glColor3fv(polygon_point_color);
		for (int i = 0; i < input_vertice.size(); i++)
		{
			if (i == input_vertice.size() - 1)
			{
				glVertex2f(input_vertice[0].x, input_vertice[0].y);
				glVertex2f(input_vertice[i].x, input_vertice[i].y);
			}
			else
			{
				glVertex2f(input_vertice[i].x, input_vertice[i].y);
				glVertex2f(input_vertice[i + 1].x, input_vertice[i + 1].y);
			}
		}
		glEnd();
		glFlush();
	}
}

void keyboard(unsigned char key, int x, int y)
{
	if (key == 32)
	{
		SutherlandHodgmanClip(::left);
		SutherlandHodgmanClip(bottom);
		SutherlandHodgmanClip(::right);
		SutherlandHodgmanClip(top);

		glLineWidth(4.0f);
		glBegin(GL_LINE_LOOP);
		glColor3fv(intersect_point_color);
		for (int i = 0; i < output_vertice.size() - 1; i++)
		{
			bresenham1(output_vertice[i].x, output_vertice[i].y, output_vertice[i + 1].x, output_vertice[i + 1].y);
		}
		bresenham1(output_vertice[0].x, output_vertice[0].y, output_vertice[output_vertice.size() - 1].x, output_vertice[output_vertice.size() - 1].y);

		glEnd();
		glFlush();

	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章