【Cohen-Sutherland线段裁剪算法】出处:http://blog.csdn.net/liaojinyu282/article/details/6010253
通过一个矩形的裁剪区域将整个屏幕分成9个部分,并为每一个部分赋予相应的区域码,然后根据端点的位置确定这个端点的区域码。
先判断能否完全接受或者完全排除一条线段,若以上2个判断无法直接得出,则逐步裁剪,选取一个位于裁剪区外的端点,把端点的区域码和裁剪边界的区域码进行逻辑与运算,若结果为真,则端点在该裁剪边界外部,这时将端点移向线段和该边界的交点处,如此循环,直到裁剪结束。
代码基本和书上一样,加了点自己的注释
#include
#include
//
//区域码
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.xwinMax.x)
code |= rightBitCode;
if(p.ywinMax.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;
}