1.实验目的:
了解二维图形裁剪的原理(点的裁剪、直线的裁剪、多边形的裁剪),利用VC+OpenGL实现直线的裁剪算法。
2.实验内容:
(1) 理解直线裁剪的原理(Cohen-Surtherland算法、梁友栋算法)
(2) 利用VC+OpenGL实现直线的编码裁剪算法,在屏幕上用一个封闭矩形裁剪任意一条直线。
(3) 调试、编译、修改程序。
(4) 尝试实现梁友栋裁剪算法。
3.实验原理:
编码裁剪算法中,为了快速判断一条直线段与矩形窗口的位置关系,采用了如图A.4所示的空间划分和编码方案。
图A.4 裁剪编码
裁剪一条线段时,先求出两端点所在的区号code1和code2,若code1 = 0且code2 = 0,则说明线段的两个端点均在窗口内,那么整条线段必在窗口内,应取之;若code1和code2经按位与运算的结果不为0,则说明两个端点同在窗口的上方、下方、左方或右方。这种情况下,对线段的处理是弃之。如果上述两种条件都不成立,则按第三种情况处理。求出线段与窗口某边的交点,在交点处把线段一分为二,其中必有一段完全在窗口外,可弃之,对另一段则重复上述处理。
4.实验代码:
#include <GL/glut.h> #include <stdio.h> #include <stdlib.h> #define LEFT_EDGE 1 #define RIGHT_EDGE 2 #define BOTTOM_EDGE 4 #define TOP_EDGE 8 void LineGL(int x0,int y0,int x1,int y1) { glBegin (GL_LINES); glColor3f (1.0f, 0.0f, 0.0f); glVertex2f (x0,y0); glColor3f (0.0f, 1.0f, 0.0f); glVertex2f (x1,y1); glEnd (); } struct Rectangle { float xmin,xmax,ymin,ymax; }; Rectangle rect; int x0,y0,x1,y1; 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; accept=0; 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.0f, 0.0f, 0.0f); 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! Press key 'r' to Restore! "); } 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; }
附上本实验的VC++工程代码(VC++2008)
5.实验提高
请分别给出直线的三种不同位置情况,测试实验代码是否存在问题,有的话请调试改正。可能的话,可以尝试实现梁友栋裁剪算法。