OpenGL-2D(Cohen-Sutherland 裁线算法)

使用的是Cohen-Sutherland 裁线算法,先把区域编号,之后裁剪。

注意在移动的时候是用裁剪窗口去判断,而不是windows窗口。

// ====== Computer Graphics Experiment #6 ======
// |   Two-Dimensional Viewing and Clipping    |
// =============================================
//						
// Requirement:			
// (1) Implement Cohen-Sutherland line clipping algorithm.
// (2) Change position and size of window and viewport  
//     and observe the effects.

#include <windows.h>
#include <GL/glut.h>
#include <stdio.h>
#include <math.h> 
// 2D point class
class CPoint2D
{
public:
	float x, y;
};
void swapCP(CPoint2D *p1, CPoint2D *p2)
{
	CPoint2D tmp;
	tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void swapCodes(GLubyte *p1, GLubyte *p2)
{
	GLubyte tmp;
	tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
// Rectangle class
class CRect
{
public:
	float xmin, ymin, xmax, ymax;

	float width(void) { return xmax - xmin; }
	float height(void) { return ymax - ymin; }
	// Make (xmin, ymin) the lower left corner
	void normalize(void);

	// Draw the rectangle
	void draw(GLenum mode);
};

void CRect::normalize(void)
{
	float ftemp;
	if (xmin > xmax)
	{
		ftemp = xmin; xmin = xmax; xmax = ftemp;
	}
	if (ymin > ymax)
	{
		ftemp = ymin; ymin = ymax; ymax = ftemp;
	}
}

void CRect::draw(GLenum mode)
{
	glBegin(mode);
	glVertex2f(xmin, ymin);
	glVertex2f(xmax, ymin);
	glVertex2f(xmax, ymax);
	glVertex2f(xmin, ymax);
	glEnd();
}

#define PI 3.14159265359

int running_state = 0;
// 0 --- Normal state. 
// 1 --- Rubber-band state. 

// Size of the scene
float scene_size = 1000.0;

CRect clip_rect;	// Clipping rectangle
CRect window;	// Window
CRect viewport;		// Viewport
const GLint winLeftBitCode = 0x1;
const GLint winRightBitCode = 0x2;
const GLint winBottomBitCode = 0x4;
const GLint winTopBitCode = 0x8;
// Program window size
int pw_width, pw_height;

// Set window
void set_window(CRect *cw)
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(cw->xmin, cw->xmax, cw->ymin, cw->ymax);
}

// Set viewport
void set_viewport(CRect *vp)
{
	glViewport(vp->xmin, vp->ymin,
		vp->width(), vp->height());
}

inline GLint roundx(const GLfloat a)
{
	return GLint(a + 0.5);
}

inline GLint inside(GLint code)
{
	return GLint(!code);
}
inline GLint reject(GLint code1, GLint code2)
{
	return GLint(code1&code2);
}
inline GLint accept(GLint code1, GLint code2)
{
	return GLint(!(code1 | code2));
}
GLubyte encode(CPoint2D pt)
{	
	GLubyte code = 0x00;	
	if (pt.x < clip_rect.xmin)
		code |= winLeftBitCode;
	if (pt.x > clip_rect.xmax)
		code |= winRightBitCode;
	if (pt.y < clip_rect.ymin)
		code |= winBottomBitCode;
	if (pt.y > clip_rect.ymax)
		code |= winTopBitCode;
	return code;
}
// Cohen-Sutherland line clipping algorithm.
bool line_clipping(CPoint2D p1, CPoint2D p2, CRect *cw,
	CPoint2D *q1, CPoint2D *q2)
	// p1, p2: End points of input line segment
	// cw:	   Clipping rectangle
	// q1, q2: End points of output line segment
	// Return value: true --- accept, false --- reject
{
	// Write your code here
	GLubyte code1, code2;
	int done = false, plotLine = false;
	GLfloat m;/*
	printf("%f~%f~%f~%f===\n", p1.x, p1.y, p2.x, p2.y);
	printf("%f~%f~%f~%f===\n", window.xmax,window.xmin,window.ymax,window.ymin);
	printf("%f~%f~%f~%f===\n", clip_rect.xmax, clip_rect.xmin, clip_rect.ymax, clip_rect.ymin);*/
	while (!done)
	{ 
		code1 = encode(p1);
		code2 = encode(p2);
		if (accept(code1, code2))
		{
			done = true;
			plotLine = true;
		}
		else if (reject(code1, code2))
		{
			done = true;
		}
		else
		{
			if (inside(code1))
			{
				swapCP(&p1, &p2);
				swapCodes(&code1, &code2);
			}
			if (p2.x != p1.x)
				m = (p2.y - p1.y) / (p2.x - p1.x);
			if (code1&winLeftBitCode)
			{
				p1.y += (clip_rect.xmin - p1.x)*m;
				p1.x = clip_rect.xmin;
			}
			else if (code1&winRightBitCode)
			{
				p1.y += (clip_rect.xmax - p1.x)*m;
				p1.x = clip_rect.xmax;
			}
			else if (code1&winBottomBitCode)
			{
				if (p2.x != p1.x)
					p1.x += (clip_rect.ymin - p1.y) / m;
				p1.y = clip_rect.ymin;
			}
			else if (code1&winTopBitCode)
			{
				if (p2.x != p1.x)
					p1.x += (clip_rect.ymax - p1.y) / m;
				p1.y = clip_rect.ymax;
			}
		}	
	}
	if (plotLine)
	{
		q1->x = roundx(p1.x);
		q1->y = roundx(p1.y);
		q2->x = roundx(p2.x);
		q2->y = roundx(p2.y); 
	}
	//printf("%f-%f-%f-%f\n", p1.x, p1.y, p2.x, p2.y);
	return (bool)plotLine;
}

//Translate the clip rectangle
void Translaterect(int dx, int dy)
{
	// Write your code here
	clip_rect.xmin += dx;
	clip_rect.xmax += dx;
	clip_rect.ymin += dy;
	clip_rect.ymax += dy;
}					  

// Initialization function
void init(void)
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glEnable(GL_LINE_STIPPLE);
}

// Display callback function
void display( )
{ 
	int i;
	CPoint2D p1, p2, q1, q2;
	double a, r;

	glClear(GL_COLOR_BUFFER_BIT);

	// Draw blue rectangle to fill the background
	glColor3f(0.0, 0.0, 0.5);
	window.draw(GL_POLYGON);

	// Draw unclipped lines in green color
	p1.x = 0.0; p1.y = 0.0;
	r = 0.5*scene_size;
	glLineStipple(1, 0x0f0f);
	glColor3f(0.0, 1.0, 0.0);
	glBegin(GL_LINES);
	for (i = 0; i<360; i += 15)
	{
		a = (double)i / 180.0*PI;
		p2.x = r*cos(a);
		p2.y = r*sin(a);
		if (i == 0 || i == 180) p2.y = 0;
		if (i == 90 || i == 270) p2.x = 0;
		p2.x += p1.x;
		p2.y += p1.y;
		glVertex2f(p1.x, p1.y);
		glVertex2f(p2.x, p2.y);
	}
	glEnd();
	glLineStipple(1, 0xffff);
 
	// Draw clipped lines in white color
	if (running_state == 0) {
		glColor3f(0.0, 0.0, 0.0);
		glLineWidth(2.0);
		glBegin(GL_LINES);
		for (i = 0; i<360; i += 15)
		{ 
			a = (double)i / 180.0*PI;
			p2.x = r*cos(a);
			p2.y = r*sin(a);
			if (i == 0 || i == 180) p2.y = 0;
			if (i == 90 || i == 270) p2.x = 0;
			p2.x += p1.x;
			p2.y += p1.y;
			if (line_clipping(p1, p2, &clip_rect, &q1, &q2))
			{
				glVertex2f(q1.x, q1.y);
				glVertex2f(q2.x, q2.y);
			} 
		} 
		glEnd();
		glLineWidth(1.0);
	}	
		
	// Draw clipping rectangle
	glLineStipple(1, 0x0f0f);
	glColor3f(1.0, 1.0, 0.0);
	clip_rect.draw(GL_LINE_LOOP);
	glLineStipple(1, 0xffff);
	 
	glutSwapBuffers();
}

// Reshape callback function
void reshape(int w, int h)
{
	// Store program window size
	pw_width = w;
	pw_height = h;

	// set viewport
	viewport.xmin = 0;
	viewport.xmax = w;
	viewport.ymin = 0;
	viewport.ymax = h;
	set_viewport(&viewport);

	// set clipping window
	window.xmin = -0.6*scene_size;
	window.xmax = 0.6*scene_size;
	window.ymin = -0.6*scene_size;
	window.ymax = 0.6*scene_size;
	set_window(&window);		

	// set clipping rectangle		 
	clip_rect.xmin = 0.5*window.xmin;
	clip_rect.xmax = 0.5*window.xmax;
	clip_rect.ymin = 0.5*window.ymin;
	clip_rect.ymax = 0.5*window.ymax;
}

// Keyboard callback function
void keyboard(unsigned char key, int x, int y)
{
	switch (key) {
	case 27:
		exit(0);
	}
}

// Special keyboard callback function
void special_key(int key, int x, int y)
{
	switch (key) {
	case GLUT_KEY_LEFT:
		// Write your code here
		Translaterect(-5.0, 0.0);
		glutPostRedisplay();
		break;
	case GLUT_KEY_RIGHT:
		// Write your code here
		Translaterect(5.0, 0.0);
		glutPostRedisplay();
		break;
	case GLUT_KEY_DOWN:
		// Write your code here
		Translaterect(0.0, -5.0);
		glutPostRedisplay();
		break;
	case GLUT_KEY_UP:
		// Write your code here
		Translaterect(0.0, 5.0);
		glutPostRedisplay();
		break;
	}
}

// Main program entrance
int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
	glutInitWindowSize(500, 500);
	glutCreateWindow("Test 2D Clipping and Viewing");
	init();
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);
	glutSpecialFunc(special_key);
	glutDisplayFunc(display);
	glutMainLoop();
	return 0;
}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值