1. 程式人生 > >計算機圖形學5——Two-Dimensional Viewing and Clipping(二維線段裁剪演算法)

計算機圖形學5——Two-Dimensional Viewing and Clipping(二維線段裁剪演算法)

採用Cohen-Sutherland演算法裁剪線段

核心程式碼有:

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
{
	GLubyte code1,
code2; GLint done=false,poltLine=false; GLfloat m; while(!done) { code1=encode(p1,cw);//起點 code2=encode(p2,cw);//終點 if(accept(code1,code2)) { done=true; poltLine=true; } else if(reject(code1,code2)) { done=
true; } else { if(inside(code1))//return GLint(!code);起點為0000,則交換起點和終點 { swapPts(&p1,&p2); swapCodes(&code1,&code2); } if(p2.x!=p1.x)//斜率存在,便求斜率 m=(p2.y-p1.y)/(p2.x-p1.x);//這裡之前打錯字了,導致顯示不全
//從右向左檢查R1(起點且為外端點) if(code1&left){ p1.y+=(cw->xmin-p1.x)*m; p1.x=cw->xmin; } else if(code1&right) { p1.y+=(cw->xmax-p1.x)*m; p1.x=cw->xmax; } else if(code1&bottom) { if(p2.x!=p1.x) p1.x+=(cw->ymin-p1.y)/m; p1.y=cw->ymin; } else if(code1&top) { if(p2.x!=p1.x) p1.x+=(cw->ymax-p1.y)/m; p1.y=cw->ymax; } } } *q1=p1; *q2=p2; return poltLine; }

完整程式碼如下:

// ====== 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 <math.h>

// 2D point class
class CPoint2D
{
public:
	float x, y;
};

// 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

// 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());
}

const GLint left=0x1;
const GLint right=0x2;
const GLint bottom=0x4;
const GLint top=0x8;


GLint inside(GLint code)
{
    return GLint(!code);
}
GLint reject(GLint code1,GLint code2)
{
    return GLint(code1&code2);
}
GLint accept(GLint code1,GLint code2)
{
    return GLint(!(code1|code2));
}
GLubyte encode(CPoint2D pt,CRect *cw1)/////////////////
{
    GLubyte code=0x00;
    if(pt.x<cw1->xmin)
        code=code|left;
    if(pt.x>cw1->xmax)
        code=code|right;
    if(pt.y<cw1->ymin)
        code=code|bottom;
    if(pt.y>cw1->ymax)
        code=code|top;
    return(code);
}

void swapPts(CPoint2D *p1,CPoint2D *p2)
{
    CPoint2D temp;
    temp=*p1;*p1=*p2;*p2=temp;
}

void swapCodes(GLubyte *p1,GLubyte*p2)
{
    GLubyte temp;
    temp=*p1;*p1=*p2;*p2=temp;
}
// 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
{
	GLubyte code1,code2;
	GLint done=false,poltLine=false;
	GLfloat m;
	while(!done)
    {
        code1=encode(p1,cw);//起點
        code2=encode(p2,cw);//終點
        if(accept(code1,code2))
        {
            done=true;
            poltLine=true;
        }
        else if(reject(code1,code2))
        {
            done=true;
        }
        else
        {
            if(inside(code1))//return GLint(!code);起點為0000,則交換起點和終點
            {
                swapPts(&p1,&p2);
                swapCodes(&code1,&code2);
            }
            if(p2.x!=p1.x)//斜率存在,便求斜率
                m=(p2.y-p1.y)/(p2.x-p1.x);//這裡之前打錯字了,導致顯示不全

            //從右向左檢查R1(起點且為外端點)
            if(code1&left){
                p1.y+=(cw->xmin-p1.x)*m;
                p1.x=cw->xmin;
            }
            else if(code1&right)
            {
                p1.y+=(cw->xmax-p1.x)*m;
                p1.x=cw->xmax;
            }
            else if(code1&bottom)
            {
                if(p2.x!=p1.x)
                    p1.x+=(cw->ymin-p1.y)/m;
                p1.y=cw->ymin;
            }
            else if(code1&top)
            {
                if(p2.x!=p1.x)
                    p1.x+=(cw->ymax-p1.y)/m;
                p1.y=cw->ymax;
            }
        }
    }
    *q1=p1;
    *q2=p2;
    return poltLine;
}

//Translate the clip rectangle
void Translaterect(int dx,int dy)
{
    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(void)
{
	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(1.0, 1.0, 1.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:
            Translaterect(-5,0);
            glutPostRedisplay();
            break;
      case GLUT_KEY_RIGHT:
            Translaterect(5.0,0.0);
            glutPostRedisplay();
            break;
      case GLUT_KEY_DOWN:
            Translaterect(0.0,-5.0);
            glutPostRedisplay();
            break;
      case GLUT_KEY_UP:
            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 Clippig and Viewing");
	init();
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);
	glutSpecialFunc(special_key);
	glutDisplayFunc(display);
	glutMainLoop();
	return 0;
}

在這裡插入圖片描述

考慮到我修改出這篇文章的程式碼花了不少時間,
應該算是原創的一種了
(っ °Д °;)っ