图形学实验四线段裁剪算法

实验四  线段裁剪算法

实验类型:设计型   实验学时: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;
}

结果即为实验要求!

不在展示。

  • 14
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
线段裁剪算法是计算机图形学中非常重要的算法之一,常用于将线段裁剪到指定的窗口范围内。下面是一份使用C++实现的边线段裁剪算法的代码示例: ```c++ #include <iostream> #include <graphics.h> //定义窗口边界 const int LEFT = 100; const int RIGHT = 500; const int TOP = 100; const int BOTTOM = 400; //定义线段端点的结构体 struct Point { int x; int y; }; //计算端点与边界的位置关系 enum Position { INSIDE, LEFT_OF, RIGHT_OF, BELOW, ABOVE }; //计算端点与边界的位置关系 Position getPosition(Point p, int edge) { if (p.x < edge) { return LEFT_OF; } else if (p.x > edge) { return RIGHT_OF; } else if (p.y < edge) { return BELOW; } else if (p.y > edge) { return ABOVE; } else { return INSIDE; } } //裁剪线段 void clipLine(Point p1, Point p2) { int x1 = p1.x; int y1 = p1.y; int x2 = p2.x; int y2 = p2.y; //计算端点与边界的位置关系 Position p1pos = INSIDE; Position p2pos = INSIDE; while (true) { p1pos = getPosition(p1, LEFT); p2pos = getPosition(p2, LEFT); //如果两个端点都在窗口内,则绘制该线段并退出循环 if ((p1pos == INSIDE) && (p2pos == INSIDE)) { line(x1, y1, x2, y2); break; } //如果两个端点都在窗口外,则直接退出循环 if ((p1pos != INSIDE) && (p2pos != INSIDE)) { break; } //计算线段与窗口边界的交点 int intersectX = 0; int intersectY = 0; if (p1pos != INSIDE) { if (p1pos == LEFT_OF) { intersectX = LEFT; intersectY = y1 + (y2 - y1) * (intersectX - x1) / (x2 - x1); } else if (p1pos == RIGHT_OF) { intersectX = RIGHT; intersectY = y1 + (y2 - y1) * (intersectX - x1) / (x2 - x1); } else if (p1pos == BELOW) { intersectY = BOTTOM; intersectX = x1 + (x2 - x1) * (intersectY - y1) / (y2 - y1); } else if (p1pos == ABOVE) { intersectY = TOP; intersectX = x1 + (x2 - x1) * (intersectY - y1) / (y2 - y1); } x1 = intersectX; y1 = intersectY; } else { if (p2pos == LEFT_OF) { intersectX = LEFT; intersectY = y1 + (y2 - y1) * (intersectX - x1) / (x2 - x1); } else if (p2pos == RIGHT_OF) { intersectX = RIGHT; intersectY = y1 + (y2 - y1) * (intersectX - x1) / (x2 - x1); } else if (p2pos == BELOW) { intersectY = BOTTOM; intersectX = x1 + (x2 - x1) * (intersectY - y1) / (y2 - y1); } else if (p2pos == ABOVE) { intersectY = TOP; intersectX = x1 + (x2 - x1) * (intersectY - y1) / (y2 - y1); } x2 = intersectX; y2 = intersectY; } } } int main() { //初始化图形界面 initwindow(600, 500, "Line Clipping"); //绘制窗口边界 rectangle(LEFT, TOP, RIGHT, BOTTOM); //定义测试线段 Point lineStart = {50, 200}; Point lineEnd = {450, 350}; //绘制测试线段 setcolor(YELLOW); line(lineStart.x, lineStart.y, lineEnd.x, lineEnd.y); //裁剪测试线段并绘制裁剪后的线段 setcolor(GREEN); clipLine(lineStart, lineEnd); //等待用户关闭窗口 getchar(); //关闭图形界面 closegraph(); return 0; } ``` 这个程序使用了位置关系算法来计算线段与窗口边界的位置关系,并使用 Cohen-Sutherland 算法裁剪线段裁剪后的线段使用绿色表示,测试线段使用黄色表示,窗口边界使用黑色表示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北溟南风起

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值