Cohen-Sutherland线段裁剪算法

来源:互联网 发布:json测试工具 编辑:程序博客网 时间:2024/05/17 15:01

出处:http://blog.csdn.net/liaojinyu282/article/details/6010253


通过一个矩形的裁剪区域将整个屏幕分成9个部分,并为每一个部分赋予相应的区域码,然后根据端点的位置确定这个端点的区域码。

先判断能否完全接受或者完全排除一条线段,若以上2个判断无法直接得出,则逐步裁剪,选取一个位于裁剪区外的端点,把端点的区域码和裁剪边界的区域码进行逻辑与运算,若结果为真,则端点在该裁剪边界外部,这时将端点移向线段和该边界的交点处,如此循环,直到裁剪结束。

代码基本和书上一样,加了点自己的注释


#include <Windows.h>#include <gl/glut.h>////////////////////////////////////////////////////////////////////////////区域码const GLint leftBitCode=0x1;const GLint rightBitCode=0x2;const GLint buttonBitCode=0x4;const GLint topBitCode=0x8;GLint winWidth=640,winHeight=480;class screenPT{public:GLfloat x,y;};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));}//判断能否完全接受一条线段inline void swapPT(screenPT& a,screenPT& b){screenPT t=a;a=b;b=t;}//交换两个点inline void swapCode(GLubyte& a,GLubyte& b){GLubyte t=a;a=b;b=t;}//交换两个区域码//确定一个点所在位置的区域码GLubyte encode(const screenPT& p,const screenPT& winMin,const screenPT& winMax){GLubyte code=0x00;if(p.x<winMin.x)code |= leftBitCode;if(p.x>winMax.x)code |= rightBitCode;if(p.y<winMin.y)code |= buttonBitCode;if(p.y>winMax.y)code |= topBitCode;return code;}//在屏幕上画一条未裁剪的线,由裁剪函数调用void drawOneLine(const screenPT& a,const screenPT& b){glBegin(GL_LINES);glVertex2f(a.x,a.y);glVertex2f(b.x,b.y);glEnd();}//裁剪函数void lineClip(screenPT winMin,screenPT winMax,screenPT lineBegin,screenPT lineEnd){GLubyte code1,code2;//保存两个端点的区域码GLboolean done=false,plotLine=false;//判断裁剪是否结束和是否要绘制直线GLfloat k;//斜率while(!done){code1 = encode(lineBegin,winMin,winMax);code2 = encode(lineEnd,winMin,winMax);if(accept(code1,code2))//当前直线能完全绘制{done=true;plotLine=true;}else{if(reject(code1,code2))//当前直线能完全排除done = true;else{if(inside(code1))//若lineBegin端点在裁剪区内则交换两个端点使它在裁剪区外{swapPT(lineBegin,lineEnd);swapCode(code1,code2);}//计算斜率if(lineBegin.x != lineEnd.x)k = (lineEnd.y-lineBegin.y)/(lineEnd.x-lineBegin.x);//开始裁剪,以下与运算若结果为真,//则lineBegin在边界外,此时将lineBegin移向直线与该边界的交点if(code1 & leftBitCode){lineBegin.y += (winMin.x-lineBegin.x)*k;lineBegin.x = winMin.x;}else if(code1 & rightBitCode){lineBegin.y += (winMax.x-lineBegin.x)*k;lineBegin.x = winMax.x;}else if(code1 & buttonBitCode){if(lineBegin.x != lineEnd.x)lineBegin.x += (winMin.y-lineBegin.y)/k;lineBegin.y = winMin.y;}else if(code1 & topBitCode){if(lineBegin.x != lineEnd.x)lineBegin.x += (winMax.y-lineBegin.y)/k;lineBegin.y = winMax.y;}}}}if(plotLine)drawOneLine(lineBegin,lineEnd);//绘制裁剪好的直线}//////////////////////////////////////////////////////////////////////////void rect(screenPT winMin,screenPT winMax){glBegin(GL_LINE_LOOP);glVertex2f(winMin.x,winMin.y);glVertex2f(winMax.x,winMin.y);glVertex2f(winMax.x,winMax.y);glVertex2f(winMin.x,winMax.y);glEnd();}void init(){glViewport(0,0,winWidth,winHeight);glClearColor(1.0,1.0,1.0,0.0);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluOrtho2D(0,winWidth,0,winHeight);glMatrixMode(GL_MODELVIEW);}void display(){screenPT winMin,winMax,lineBegin,lineEnd;winMin.x=100.0;winMin.y=50.0;winMax.x=400.0;winMax.y=300.0;lineBegin.x=0.0;lineBegin.y=0.0;lineEnd.x=winWidth;lineEnd.y=winHeight;glClear(GL_COLOR_BUFFER_BIT);glColor3f(0.0,0.0,0.0);rect(winMin,winMax);//为裁剪区域绘制一个边框lineClip(winMin,winMax,lineBegin,lineEnd);lineBegin.y=240.0;lineEnd.y=240.0;lineClip(winMin,winMax,lineBegin,lineEnd);lineBegin.x=320.0;lineBegin.y=0.0;lineEnd.x=320.0;lineEnd.y=winHeight;lineClip(winMin,winMax,lineBegin,lineEnd);glFlush();}int main(int argc,char** argv){glutInit(&argc,argv);glutInitWindowPosition(100,100);glutInitWindowSize(winWidth,winHeight);glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);glutCreateWindow("my app");init();glutDisplayFunc(display);glutMainLoop();return 0;}


0 0
原创粉丝点击