採用Cohen-Sutherland算法裁剪線段web
核心代碼有:算法
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; }
完整代碼以下: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 <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; }
考慮到我修改出這篇文章的代碼花了很多時間,
應該算是原創的一種了
(っ °Д °;)っide