1. 程式人生 > >圖形學實驗四線段裁剪演算法

圖形學實驗四線段裁剪演算法

實驗四  線段裁剪演算法

實驗型別:設計型   實驗學時:2實驗要求:必修

一、實驗目的

瞭解二維圖形裁剪的原理(點的裁剪、直線的裁剪、多邊形的裁剪),利用VC+OpenGL實現直線的裁剪演算法。

二、實驗內容

1 理解直線裁剪的原理(編碼裁剪演算法、樑友棟演算法)

2 利用VC+OpenGL實現直線的編碼裁剪演算法,在螢幕上用一個封閉矩形裁剪任意一條直線。

3 互動實現直線段的裁剪。

三、實驗原理

編碼裁剪演算法中,為了快速判斷一條直線段與矩形視窗的位置關係,採用瞭如圖3所示的空間劃分和編碼方案。

圖3   直線裁剪分割槽編碼圖

基礎:

升級1

按 c 裁剪,並且按 r 要恢復到原形狀

裁剪一條線段時,先求出兩端點所在的區號code1和code2,若code1 = 0且code2 = 0,則說明線段的兩個端點均在視窗內,那麼整條線段必在視窗內,應取之;若code1和code2經按位與運算的結果不為0,則說明兩個端點同在視窗的上方、下方、左方或右方。這種情況下,對線段的處理是棄之。如果上述兩種條件都不成立,則按第三種情況處理。求出線段與視窗某邊的交點,在交點處把線段一分為二,其中必有一段完全在視窗外,可棄之,對另一段則重複上述處理。

四、實驗示範程式碼(略)

五、實驗步驟

1 在Windows xp/win7操作環境下,啟動VC;

2 建立W32 Console Application 的應用工程;

3 建立源程式編輯環境,進行編輯源程式。

4 除錯執行程式,完成實驗。

六、實驗結果處理

演示結果並儲存相關檔案。

七、實驗注意事項

注意程式設計環境的配置,即在Windows環境下,OpenGL擴充套件庫相關檔案的配置,把標頭檔案“GL.H”、庫檔案“OPENGL32.LIB”和動態連結庫“OPENGL32.DLL”配置到相應的目錄下。

八、預習與思考題

預習:閱讀課本相關內容,仔細閱讀示範程式碼。

思考題:如何實現橫平豎直線段的裁剪。

九、實驗報告要求

1、實驗報告中應包括相關操作步驟和程式程式碼和執行效果截圖。

2.書寫實驗報告時要結構合理,層次分明,在分析描述的時候,需要注意語言的流暢。

 基礎程式碼:


#include<stdio.h>
#include<stdlib.h>
#include<GL/glut.h>


#define LEFT_EDGE 1
#define RIGHT_EDGE 2
#define BOTTOM_EDGE 4
#define TOP_EDGE 8


int x0,y0,x1,y1;

void LineGL(int x0,int y0,int x1,int y1)
{
	glBegin(GL_LINES);
	glColor3f(1.0,0.0,0.0); glVertex2f(x0,y0);
	glColor3f(0.0,1.0,0.0); glVertex2f(x1,y1);	
	glEnd();
}

struct Rectangle
{
	float xmin,xmax,ymin,ymax;
};

Rectangle rect;



int CompCode(int x,int y,Rectangle rect)
{
	int code = 0x00;
	if(y < rect.ymin)
		code = code|4;
	if(y > rect.ymax)
		code = code|8;
	if(x >rect.xmax)
		code = code|2;
	if(x < rect.xmin)
		code = code|1;
	return code;
}

int cohensutherlandlineclip(Rectangle rect,int &x0,int &y0,int &x1,int &y1)//此處&不能刪除,否則導致錯誤
{
	int accept,done;
	float x,y;
	done = 0;

	int code0,code1,codeout;
	code0 = CompCode(x0,y0,rect);
	code1 = CompCode(x1,y1,rect);
	do{
		if(!(code0 | code1))
		{
			accept =1;
			done=1;
		}
		else if(code0 &code1)
			done =1;
		else {
			if(code0!=0)
				codeout = code0;
			else
				codeout = code1;

			if(codeout&LEFT_EDGE){
				y=y0+(y1-y0)*(rect.xmin-x0)/(x1-x0);
				x=(float)rect.xmin;
			}
			else if(codeout&RIGHT_EDGE){
				y=y0+(y1-y0)*(rect.xmax-x0)/(x1-x0);
				x=(float)rect.xmax;
			}

			else if(codeout&BOTTOM_EDGE){
				x=x0+(x1-x0)*(rect.ymin-y0)/(y1-y0);
				y=(float)rect.ymin;}
			else if(codeout&TOP_EDGE){
					x=x0+(x1-x0)*(rect.ymax-y0)/(y1-y0);
					y=(float)rect.ymax;
				}

			if(codeout == code0 )
			{
				x0=x;
				y0=y;
				code0 = CompCode(x0,y0,rect);
			}
			else
			{
				x1 = x;
				y1=y;
				code1 = CompCode(x1,y1,rect);
			}
			}
		}while(!done);

		if(accept)
			LineGL(x0,y0,x1,y1);
		return accept;
	}

	void myDisplay()
	{
		glClear(GL_COLOR_BUFFER_BIT);
		glColor3f(1.0,0.0,0.0);
		glRectf(rect.xmin,rect.ymin,rect.xmax,rect.ymax);

		LineGL(x0,y0,x1,y1);

		glFlush();

	}

	void Init()
	{
		glClearColor(0.0,0.0,0.0,0.0);
		glShadeModel(GL_FLAT);

		rect.xmin=100;
		rect.xmax=300;
		rect.ymin=100;
		rect.ymax=300;

		x0=450,y0=0,x1=0,y1=450;
		printf("Press key 'c' to Clip!\n");
		printf("Press key 'r' to Restore!\n");
	}

	void Reshape(int w,int h)
	{
		glViewport(0,0,(GLsizei)w, (GLsizei)h );
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h );
	}

	void keyboard(unsigned char key,int x,int y)
	{
		switch (key)
		{
		case 'c':
			cohensutherlandlineclip(rect, x0,y0,x1,y1);
			glutPostRedisplay();
			break;
		case 'r':
			Init();
			glutPostRedisplay();
			break;
		case 'x':
			exit(0);
			break;
		default:
			break;
		}
	}


int main(int argc,char *argv[])
{
	glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(100,100);
	glutInitWindowSize(640,480);
	glutCreateWindow("Hello world!");

	Init();
	glutDisplayFunc(myDisplay);
	glutReshapeFunc(Reshape);
	glutKeyboardFunc(keyboard);
	glutMainLoop();
	return 0;
}

#include<stdio.h>
#include<stdlib.h>
#include<GL/glut.h>


#define LEFT_EDGE 1
#define RIGHT_EDGE 2
#define BOTTOM_EDGE 4
#define TOP_EDGE 8


int x0,y0,x1,y1,x2,y2,x3,y3,x4,y4,x5,y5;

void LineGL(int x0,int y0,int x1,int y1)
{
	glBegin(GL_LINES);
	glVertex2f(x0,y0);
	glVertex2f(x1,y1);	
	glEnd();
}

struct Rectangle
{
	float xmin,xmax,ymin,ymax;
};

Rectangle rect;



int CompCode(int x,int y,Rectangle rect)
{
	int code = 0x00;
	if(y < rect.ymin)
		code = code|4;
	if(y > rect.ymax)
		code = code|8;
	if(x >rect.xmax)
		code = code|2;
	if(x < rect.xmin)
		code = code|1;
	return code;
}
int cohensutherlandlineclip(Rectangle rect,int &x0,int &y0,int &x1,int &y1)//此處&不能刪除,否則導致錯誤
{
	int accept,done;
	float x,y;
	done = 0;
	int code0,code1,codeout;
	code0 = CompCode(x0,y0,rect);
	code1 = CompCode(x1,y1,rect);
	do{
		if(!(code0 | code1))
		{
			accept =1;
			done=1;
		}
		else if(code0 &code1)
			done =1;
		else {
			if(code0!=0)
				codeout = code0;
			else
				codeout = code1;
			if(codeout&LEFT_EDGE){
				y=y0+(y1-y0)*(rect.xmin-x0)/(x1-x0);
				x=(float)rect.xmin;
			}
			else if(codeout&RIGHT_EDGE){
				y=y0+(y1-y0)*(rect.xmax-x0)/(x1-x0);
				x=(float)rect.xmax;
			}
			else if(codeout&BOTTOM_EDGE){
				x=x0+(x1-x0)*(rect.ymin-y0)/(y1-y0);
				y=(float)rect.ymin;}
			else if(codeout&TOP_EDGE){
					x=x0+(x1-x0)*(rect.ymax-y0)/(y1-y0);
					y=(float)rect.ymax;
				}
			if(codeout == code0 )
			{
				x0=x;
				y0=y;
				code0 = CompCode(x0,y0,rect);
			}
			else
			{
				x1 = x;
				y1=y;
				code1 = CompCode(x1,y1,rect);
			}
			}
		}while(!done);
		if(accept)
			LineGL(x0,y0,x1,y1);
		return accept;
	}

	void myDisplay()
	{
		glClear(GL_COLOR_BUFFER_BIT);
		glColor3f(1.0,0.0,0.0);
		glBegin(GL_LINE_LOOP);
		glVertex2f(rect.xmin,rect.ymax);
		glVertex2f(rect.xmax,rect.ymax);
		glVertex2f(rect.xmax,rect.ymin);
		glVertex2f(rect.xmin,rect.ymin);
		glEnd();

		glColor3f(0.0,1.0,0.0);LineGL(x0,y0,x1,y1);
		glColor3f(1.0,0.0,1.0);LineGL(x2,y2,x3,y3);
		glColor3f(1.0,1.0,1.0);LineGL(x4,y4,x5,y5);
	
		glFlush();

	}
	void Init()
	{
		glClearColor(0.0,0.0,0.0,0.0);
		glShadeModel(GL_FLAT);

		rect.xmin=100;
		rect.xmax=300;
		rect.ymin=100;
		rect.ymax=300;

		x0=450,y0=0,x1=0,y1=450,x2=0,y2=200,x3=450,y3=200,x4=200,y4=400,x5=200,y5=10;
		printf("Press key 'c' to Clip!\n");
		printf("Press key 'r' to Restore!\n");
	}
	void Reshape(int w,int h)
	{
		glViewport(0,0,(GLsizei)w, (GLsizei)h );
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h );
	}
	void keyboard(unsigned char key,int x,int y)
	{
		
		switch (key)
		{
		case 'c':
			cohensutherlandlineclip(rect, x0,y0,x1,y1);
			cohensutherlandlineclip(rect, x2,y2,x3,y3);
			cohensutherlandlineclip(rect, x4,y4,x5,y5);
			glutPostRedisplay();
			break;
		case 'r':
			Init();
			glutPostRedisplay();
			break;
		case 'x':
			exit(0);
			break;
		default:
			break;
		}
	}
int main(int argc,char *argv[])
{
	glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(100,100);
	glutInitWindowSize(640,480);
	glutCreateWindow("Hello world!");

	Init();
	glutDisplayFunc(myDisplay);
	glutReshapeFunc(Reshape);
	glutKeyboardFunc(keyboard);
	glutMainLoop();
	return 0;
}

結果即為實驗要求!

不在展示。