对某线段的两个端点的区号进行位与运算,可知这两个端点是否同在视区的上、下、左、右;
‐如果两端点的编码均为0000,表示直线在窗口内。
‐如果两端点的编码相与不为0000,表示直线在窗口外。
‐如果两端点的编码不全为0000,但相与为0000,则该直线部分可见,需计算直线与窗口的交点,确定哪一部分可见。
‐
算法描述:
BOOLdone,draw;(done表示是否完成,draw表示是否可见)
Unsignedcharcode1,code2;端点1,端点2的编码
While(!
done)
begin
if(判断code1,code2,若为第1种情况)
begin
done=TRUE;
draw=TRUE;
end
elseif(为第2种情况)
begin
done=TRUE;
draw=FALSE;
end
elseif(检查code1,若在窗口内)/*第3种情况*/
begin
交换端点及端点的编码;以左,上,右,下的次序对端点1进行判断及求交;将交点的值赋给端点1;
end
end
算法分析:
本算法的优点在于简单,易于实现。
用编码方法可快速判断线段的完全可见和显然不可见,他可以简单的描述为将直线在窗口左边的部分删去,按左,右,下,上的顺序依次进行,处理之后,剩余部分就是可见的了。
在这个算法中求交点是很重要的,他决定了算法的速度。
本算法对于其他形状的窗口是否同样有效就值得讨论了,这也证明了在图形算法中,没有几个是对大多数情况有效的。
特别适用二种情形:
大窗口场合;窗口特别小场合(光标拾取图形,光标看作小的裁剪窗口)。
Cohen-Sutherland与中点法在区域码测试阶段能以位运算方式高效率地进行,因而当大多数线段能够简单的取舍时,效率较好。
实验环境
五、实验条件:
硬件平台:
PC
软件(推荐):
Windows平台,Visualstdio2013,opengl
实验步骤
六、实验步骤
1.掌握算法原理;
2.依据算法,编写源程序并进行调试;
3.对运行结果进行保存与分析;
4.把源程序以文件的形式提交;
5.按格式书写实验报告。
实验内容
#include"stdafx.h"
#include
#include
#include
#pragmacomment(lib,"opengl32.lib")
#pragmacomment(lib,"glu32.lib")
#pragmacomment(lib,"glut32.lib")
#defineLEFT_EDGE1
#defineRIGHT_EDGE2
#defineBOTTOM_EDGE4
#defineTOP_EDGE8
staticinttimes=1;
//画从(x0,y0)到(x1,y1)的直线
voidLineGL(intx0,inty0,intx1,inty1)
{
glBegin(GL_LINES);
glColor3f(1.0f,0.0f,0.0f);
glVertex2f(x0,y0);
glColor3f(0.0f,1.0f,0.0f);
glVertex2f(x1,y1);
glEnd();
}
//矩形的结构体
typedefstructRectangle
{
floatxmin;
floatxmax;
floatymin;
floatymax;
}Rectan;
Rectanrect;
intx0,y0,x1,y1;
//求出坐标点的Cohen-Sutherland编码
intCompCode(intx,inty,Rectanrect)
{
intcode=0x00;
if(y{
code=code|4;
}
if(y>rect.ymax)
{
code=code|8;
}
if(x>rect.xmax)
{
code=code|2;
}
if(x{
code=code|1;
}
returncode;
}
//裁剪直线
intcohensutherlandlineclip(Rectanrect,int&x0,int&y0,int&x1,int&y1)
{
intaccept=0,done=0;
floatx,y;
intcode0,code1,codeout;
intx00=x0,y00=y0,x11=x1,y11=y1;
code0=CompCode(x0,y0,rect);
code1=CompCode(x1,y1,rect);
//直线全部在矩形框内部,应保留
if(!
(code0|code1))
{
accept=1;
done=1;
}
//直线和矩形不相交,并且划直线的两点在矩形同侧(上、下、右。
左),应去掉。
if(code0&code1)
{
done=1;
}
while(!
done)
{
//直线和矩形有交点,只保留矩形内部的
if(!
(code0|code1))
{
accept=1;
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=y0+(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);
}
//直线和矩形不相交,但是划直线的两点在矩形不同侧,这时应去掉。
if((times<=3)&&(code0&code1))
{
x0=x1;
y0=y1;
done=1;
accept=1;
}
}
}
if(accept)
{
LineGL(x0,y0,x1,y1);
}
returnaccept;
}
voidmyDisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f,1.0f,0.0f);
glRectf(rect.xmin,rect.ymin,rect.xmax,rect.ymax);
LineGL(x0,y0,x1,y1);
glFlush();
}
voidInit()
{
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=0;
y0=360;
x1=650;
y1=0;
}
voidReshape(intw,inth)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h);
}
//按键盘上字母c裁剪,字母r恢复原状,字母x退出。
voidkeyboard(unsignedcharkey,intx,inty)
{
switch(key)
{
case'c':
cohensutherlandlineclip(rect,x0,y0,x1,y1);
glutPostRedisplay();
break;
case'r':
Init();
glutPostRedisplay();
break;
case'x':
exit(0);
break;
default:
break;
}
}
intmain(intargc,char*argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
glutInitWindowPosition(100,100);
glutInitWindowSize(640,480);
glutCreateWindow("裁剪");
Init();
glutDisplayFunc(myDisplay);
glutReshapeFunc(Reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return0;
}
实验结果
实验总结
通过这次实验我对于直线的裁剪有了一定的认识,我实现的直线裁剪方法是Cohen-SutherLand算法(编码算法)算法原理:
对于每条线段P1P2分为三种情况处理:
若P1P2完全在窗口内,则显示该线段P1P2。
若P1P2明显在窗口外,则丢弃该线段。
若线段不满足
(1)或
(2)的条件,则在交点处把线段分为两段。
其中一段完全在窗口外,可弃之。
然后对另一段重复上述处理。
指导教师意见
签名:
年月日